shared code (new strerror stuff)

This commit is contained in:
Jean-Francois Dockes 2020-01-13 10:23:53 +01:00
parent 1ffd54f834
commit a9ae4de43c
2 changed files with 102 additions and 111 deletions

View File

@ -1,35 +1,18 @@
/* Copyright (C) 2014 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
* (at your option) any later version.
/* Copyright (C) 2014-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
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Copyright (C) 2006-2016 J.F.Dockes
*
* This library 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 (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _LOG_H_X_INCLUDED_
#define _LOG_H_X_INCLUDED_
@ -57,7 +40,7 @@
class Logger {
public:
/** Initialize logging to file name. Use "stderr" for stderr
output. Creates the singleton logger object */
output. Creates the singleton logger object */
static Logger *getTheLog(const std::string& fn);
bool reopen(const std::string& fn);
@ -97,7 +80,7 @@ private:
#define LOGGER_PRT (Logger::getTheLog("")->getstream())
#if LOGGER_THREADSAFE
#define LOGGER_LOCK \
#define LOGGER_LOCK \
std::unique_lock<std::recursive_mutex> lock(Logger::getTheLog("")->getmutex())
#else
#define LOGGER_LOCK
@ -107,63 +90,63 @@ private:
#define LOGGER_LOCAL_LOGINC 0
#endif
#define LOGGER_LEVEL (Logger::getTheLog("")->getloglevel() + \
#define LOGGER_LEVEL (Logger::getTheLog("")->getloglevel() + \
LOGGER_LOCAL_LOGINC)
#define LOGGER_DOLOG(L,X) LOGGER_PRT << ":" << L << ":" << \
__FILE__ << ":" << __LINE__ << "::" << X \
#define LOGGER_DOLOG(L,X) LOGGER_PRT << ":" << L << ":" << \
__FILE__ << ":" << __LINE__ << "::" << X \
<< std::flush
#if LOGGER_STATICVERBOSITY >= 7
#define LOGDEB2(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB2) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB2, X); \
} \
#define LOGDEB2(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB2) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB2, X); \
} \
}
#else
#define LOGDEB2(X)
#endif
#if LOGGER_STATICVERBOSITY >= 6
#define LOGDEB1(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB1) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB1, X); \
} \
#define LOGDEB1(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB1) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB1, X); \
} \
}
#else
#define LOGDEB1(X)
#endif
#if LOGGER_STATICVERBOSITY >= 5
#define LOGDEB0(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB0) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB0, X); \
} \
#define LOGDEB0(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB0) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB0, X); \
} \
}
#else
#define LOGDEB0(X)
#endif
#if LOGGER_STATICVERBOSITY >= 4
#define LOGDEB(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB, X); \
} \
#define LOGDEB(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB, X); \
} \
}
#else
#define LOGDEB(X)
#endif
#if LOGGER_STATICVERBOSITY >= 3
#define LOGINF(X) { \
if (LOGGER_LEVEL >= Logger::LLINF) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLINF, X); \
} \
#define LOGINF(X) { \
if (LOGGER_LEVEL >= Logger::LLINF) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLINF, X); \
} \
}
#else
#define LOGINF(X)
@ -171,22 +154,22 @@ private:
#define LOGINFO LOGINF
#if LOGGER_STATICVERBOSITY >= 2
#define LOGERR(X) { \
if (LOGGER_LEVEL >= Logger::LLERR) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLERR, X); \
} \
#define LOGERR(X) { \
if (LOGGER_LEVEL >= Logger::LLERR) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLERR, X); \
} \
}
#else
#define LOGERR(X)
#endif
#if LOGGER_STATICVERBOSITY >= 1
#define LOGFAT(X) { \
if (LOGGER_LEVEL >= Logger::LLFAT) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLFAT, X); \
} \
#define LOGFAT(X) { \
if (LOGGER_LEVEL >= Logger::LLFAT) { \
LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLFAT, X); \
} \
}
#else
#define LOGFAT(X)
@ -198,20 +181,18 @@ private:
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << strerror(errno) << std::endl); \
}
#else // !WINDOWS->
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
#define LOGSYSERR(who, what, arg) { \
char buf[200]; buf[0] = 0; strerror_r(errno, buf, 200); \
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << buf << std::endl); \
}
#else
#else // not WINDOWS or sun
inline char *_log_check_strerror_r(int, char *errbuf) {return errbuf;}
inline char *_log_check_strerror_r(char *cp, char *){return cp;}
#define LOGSYSERR(who, what, arg) { \
char buf[200]; buf[0] = 0; \
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << strerror_r(errno, buf, 200) << std::endl); \
": " << _log_check_strerror_r( \
strerror_r(errno, buf, 200), buf) << std::endl); \
}
#endif
#endif // not windows
#endif /* _LOG_H_X_INCLUDED_ */

View File

@ -115,7 +115,7 @@ string stringtoupper(const string& i)
extern int stringisuffcmp(const string& s1, const string& s2)
{
string::const_reverse_iterator r1 = s1.rbegin(), re1 = s1.rend(),
r2 = s2.rbegin(), re2 = s2.rend();
r2 = s2.rbegin(), re2 = s2.rend();
while (r1 != re1 && r2 != re2) {
char c1 = ::toupper(*r1);
char c2 = ::toupper(*r2);
@ -326,18 +326,18 @@ template <class T> bool stringToStrings(const string& s, T& tokens,
}
template bool stringToStrings<list<string> >(const string&,
list<string>&, const string&);
list<string>&, const string&);
template bool stringToStrings<vector<string> >(const string&,
vector<string>&, const string&);
vector<string>&, const string&);
template bool stringToStrings<set<string> >(const string&,
set<string>&, const string&);
set<string>&, const string&);
template bool stringToStrings<std::unordered_set<string> >
(const string&, std::unordered_set<string>&, const string&);
template <class T> void stringsToString(const T& tokens, string& s)
{
for (typename T::const_iterator it = tokens.begin();
it != tokens.end(); it++) {
it != tokens.end(); it++) {
bool hasblanks = false;
if (it->find_first_of(" \t\n") != string::npos) {
hasblanks = true;
@ -382,10 +382,10 @@ template <class T> void stringsToCSV(const T& tokens, string& s,
{
s.erase();
for (typename T::const_iterator it = tokens.begin();
it != tokens.end(); it++) {
it != tokens.end(); it++) {
bool needquotes = false;
if (it->empty() ||
it->find_first_of(string(1, sep) + "\"\n") != string::npos) {
it->find_first_of(string(1, sep) + "\"\n") != string::npos) {
needquotes = true;
}
if (it != tokens.begin()) {
@ -409,7 +409,7 @@ template <class T> void stringsToCSV(const T& tokens, string& s,
}
template void stringsToCSV<list<string> >(const list<string>&, string&, char);
template void stringsToCSV<vector<string> >(const vector<string>&, string&,
char);
char);
void stringToTokens(const string& str, vector<string>& tokens,
const string& delims, bool skipinit)
@ -418,7 +418,7 @@ void stringToTokens(const string& str, vector<string>& tokens,
// Skip initial delims, return empty if this eats all.
if (skipinit &&
(startPos = str.find_first_not_of(delims, 0)) == string::npos) {
(startPos = str.find_first_not_of(delims, 0)) == string::npos) {
return;
}
while (startPos < str.size()) {
@ -569,13 +569,13 @@ string escapeHtml(const string& in)
{
string out;
for (string::size_type pos = 0; pos < in.length(); pos++) {
switch(in.at(pos)) {
case '<': out += "&lt;"; break;
case '>': out += "&gt;"; break;
case '&': out += "&amp;"; break;
case '"': out += "&quot;"; break;
default: out += in.at(pos); break;
}
switch(in.at(pos)) {
case '<': out += "&lt;"; break;
case '>': out += "&gt;"; break;
case '&': out += "&amp;"; break;
case '"': out += "&quot;"; break;
default: out += in.at(pos); break;
}
}
return out;
}
@ -850,7 +850,7 @@ static bool parsedate(vector<string>::const_iterator& it,
{
dip->y1 = dip->m1 = dip->d1 = dip->y2 = dip->m2 = dip->d2 = 0;
if (it->length() > 4 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) {
it->find_first_not_of("0123456789") != string::npos) {
return false;
}
if (it == end || sscanf(it++->c_str(), "%d", &dip->y1) != 1) {
@ -864,7 +864,7 @@ static bool parsedate(vector<string>::const_iterator& it,
}
if (it->length() > 2 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) {
it->find_first_not_of("0123456789") != string::npos) {
return false;
}
if (it == end || sscanf(it++->c_str(), "%d", &dip->m1) != 1) {
@ -878,7 +878,7 @@ static bool parsedate(vector<string>::const_iterator& it,
}
if (it->length() > 2 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) {
it->find_first_not_of("0123456789") != string::npos) {
return false;
}
if (it == end || sscanf(it++->c_str(), "%d", &dip->d1) != 1) {
@ -1001,7 +1001,7 @@ static bool addperiod(DateInterval *dp, DateInterval *pp)
int monthdays(int mon, int year)
{
switch (mon) {
// We are returning a few too many 29 days februaries, no problem
// We are returning a few too many 29 days februaries, no problem
case 2:
return (year % 4) == 0 ? 29 : 28;
case 1:
@ -1023,7 +1023,7 @@ bool parsedateinterval(const string& s, DateInterval *dip)
DateInterval p1, p2, d1, d2;
p1 = p2 = d1 = d2 = *dip;
bool hasp1 = false, hasp2 = false, hasd1 = false, hasd2 = false,
hasslash = false;
hasslash = false;
if (!stringToStrings(s, vs, "PYMDpymd-/")) {
return false;
@ -1164,6 +1164,16 @@ secondelt:
return true;
}
// We'd like these static, but then, as only one is used, this
// triggers a 'defined but not used' warning.
char *_check_strerror_r(int, char *errbuf)
{
return errbuf;
}
char *_check_strerror_r(char *cp, char *)
{
return cp;
}
void catstrerror(string *reason, const char *what, int _errno)
{
@ -1186,8 +1196,6 @@ void catstrerror(string *reason, const char *what, int _errno)
// Note: sun strerror is noted mt-safe ??
reason->append(strerror(_errno));
#else
#define ERRBUFSZ 200
char errbuf[ERRBUFSZ];
// There are 2 versions of strerror_r.
// - The GNU one returns a pointer to the message (maybe
// static storage or supplied buffer).
@ -1198,13 +1206,15 @@ void catstrerror(string *reason, const char *what, int _errno)
// were returned a pointer...
// Also couldn't find an easy way to disable the gnu version without
// changing the cxxflags globally, so forget it. Recent gnu lib versions
// normally default to the posix version.
// At worse we get no message at all here.
// normally default to the posix version. (not !)
// The feature defines tests are too complicated and seem unreliable.
// In short it's a mess, but thanks to c++ function overloading and smart
// people, we have a solution:
// https://www.zverovich.net/2015/03/13/reliable-detection-of-strerror-variants.html
char errbuf[200];
errbuf[0] = 0;
// We don't use ret, it's there to silence a cc warning
auto ret = strerror_r(_errno, errbuf, ERRBUFSZ);
(void)ret;
reason->append(errbuf);
reason->append(_check_strerror_r(
strerror_r(_errno, errbuf, sizeof(errbuf)), errbuf));
#endif
}
@ -1232,7 +1242,7 @@ static std::unordered_map<string, string> lang_to_code {
{"th", "iso-8859-11"},
{"tr", "iso-8859-9"},
{"uk", "koi8-u"},
};
};
static const string cstr_cp1252("CP1252");
string langtocode(const string& lang)
@ -1252,7 +1262,7 @@ string localelang()
const char *lang = getenv("LANG");
if (lang == 0 || *lang == 0 || !strcmp(lang, "C") ||
!strcmp(lang, "POSIX")) {
!strcmp(lang, "POSIX")) {
return "en";
}
string locale(lang);