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 /* Copyright (C) 2014-2019 J.F.Dockes
* This program is free software; you can redistribute it and/or modify * 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 * 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 * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details. * GNU Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the * along with this program; if not, write to the
* Free Software Foundation, Inc., * Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * 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
*/ */
#ifndef _LOG_H_X_INCLUDED_ #ifndef _LOG_H_X_INCLUDED_
#define _LOG_H_X_INCLUDED_ #define _LOG_H_X_INCLUDED_
@ -57,7 +40,7 @@
class Logger { class Logger {
public: public:
/** Initialize logging to file name. Use "stderr" for stderr /** 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); static Logger *getTheLog(const std::string& fn);
bool reopen(const std::string& fn); bool reopen(const std::string& fn);
@ -97,7 +80,7 @@ private:
#define LOGGER_PRT (Logger::getTheLog("")->getstream()) #define LOGGER_PRT (Logger::getTheLog("")->getstream())
#if LOGGER_THREADSAFE #if LOGGER_THREADSAFE
#define LOGGER_LOCK \ #define LOGGER_LOCK \
std::unique_lock<std::recursive_mutex> lock(Logger::getTheLog("")->getmutex()) std::unique_lock<std::recursive_mutex> lock(Logger::getTheLog("")->getmutex())
#else #else
#define LOGGER_LOCK #define LOGGER_LOCK
@ -107,63 +90,63 @@ private:
#define LOGGER_LOCAL_LOGINC 0 #define LOGGER_LOCAL_LOGINC 0
#endif #endif
#define LOGGER_LEVEL (Logger::getTheLog("")->getloglevel() + \ #define LOGGER_LEVEL (Logger::getTheLog("")->getloglevel() + \
LOGGER_LOCAL_LOGINC) LOGGER_LOCAL_LOGINC)
#define LOGGER_DOLOG(L,X) LOGGER_PRT << ":" << L << ":" << \ #define LOGGER_DOLOG(L,X) LOGGER_PRT << ":" << L << ":" << \
__FILE__ << ":" << __LINE__ << "::" << X \ __FILE__ << ":" << __LINE__ << "::" << X \
<< std::flush << std::flush
#if LOGGER_STATICVERBOSITY >= 7 #if LOGGER_STATICVERBOSITY >= 7
#define LOGDEB2(X) { \ #define LOGDEB2(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB2) { \ if (LOGGER_LEVEL >= Logger::LLDEB2) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB2, X); \ LOGGER_DOLOG(Logger::LLDEB2, X); \
} \ } \
} }
#else #else
#define LOGDEB2(X) #define LOGDEB2(X)
#endif #endif
#if LOGGER_STATICVERBOSITY >= 6 #if LOGGER_STATICVERBOSITY >= 6
#define LOGDEB1(X) { \ #define LOGDEB1(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB1) { \ if (LOGGER_LEVEL >= Logger::LLDEB1) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB1, X); \ LOGGER_DOLOG(Logger::LLDEB1, X); \
} \ } \
} }
#else #else
#define LOGDEB1(X) #define LOGDEB1(X)
#endif #endif
#if LOGGER_STATICVERBOSITY >= 5 #if LOGGER_STATICVERBOSITY >= 5
#define LOGDEB0(X) { \ #define LOGDEB0(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB0) { \ if (LOGGER_LEVEL >= Logger::LLDEB0) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB0, X); \ LOGGER_DOLOG(Logger::LLDEB0, X); \
} \ } \
} }
#else #else
#define LOGDEB0(X) #define LOGDEB0(X)
#endif #endif
#if LOGGER_STATICVERBOSITY >= 4 #if LOGGER_STATICVERBOSITY >= 4
#define LOGDEB(X) { \ #define LOGDEB(X) { \
if (LOGGER_LEVEL >= Logger::LLDEB) { \ if (LOGGER_LEVEL >= Logger::LLDEB) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLDEB, X); \ LOGGER_DOLOG(Logger::LLDEB, X); \
} \ } \
} }
#else #else
#define LOGDEB(X) #define LOGDEB(X)
#endif #endif
#if LOGGER_STATICVERBOSITY >= 3 #if LOGGER_STATICVERBOSITY >= 3
#define LOGINF(X) { \ #define LOGINF(X) { \
if (LOGGER_LEVEL >= Logger::LLINF) { \ if (LOGGER_LEVEL >= Logger::LLINF) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLINF, X); \ LOGGER_DOLOG(Logger::LLINF, X); \
} \ } \
} }
#else #else
#define LOGINF(X) #define LOGINF(X)
@ -171,22 +154,22 @@ private:
#define LOGINFO LOGINF #define LOGINFO LOGINF
#if LOGGER_STATICVERBOSITY >= 2 #if LOGGER_STATICVERBOSITY >= 2
#define LOGERR(X) { \ #define LOGERR(X) { \
if (LOGGER_LEVEL >= Logger::LLERR) { \ if (LOGGER_LEVEL >= Logger::LLERR) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLERR, X); \ LOGGER_DOLOG(Logger::LLERR, X); \
} \ } \
} }
#else #else
#define LOGERR(X) #define LOGERR(X)
#endif #endif
#if LOGGER_STATICVERBOSITY >= 1 #if LOGGER_STATICVERBOSITY >= 1
#define LOGFAT(X) { \ #define LOGFAT(X) { \
if (LOGGER_LEVEL >= Logger::LLFAT) { \ if (LOGGER_LEVEL >= Logger::LLFAT) { \
LOGGER_LOCK; \ LOGGER_LOCK; \
LOGGER_DOLOG(Logger::LLFAT, X); \ LOGGER_DOLOG(Logger::LLFAT, X); \
} \ } \
} }
#else #else
#define LOGFAT(X) #define LOGFAT(X)
@ -198,20 +181,18 @@ private:
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \ LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << strerror(errno) << std::endl); \ ": " << strerror(errno) << std::endl); \
} }
#else // !WINDOWS-> #else // not WINDOWS or sun
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
#define LOGSYSERR(who, what, arg) { \ inline char *_log_check_strerror_r(int, char *errbuf) {return errbuf;}
char buf[200]; buf[0] = 0; strerror_r(errno, buf, 200); \ inline char *_log_check_strerror_r(char *cp, char *){return cp;}
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
": " << buf << std::endl); \
}
#else
#define LOGSYSERR(who, what, arg) { \ #define LOGSYSERR(who, what, arg) { \
char buf[200]; buf[0] = 0; \ char buf[200]; buf[0] = 0; \
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \ 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 // not windows
#endif /* _LOG_H_X_INCLUDED_ */ #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) extern int stringisuffcmp(const string& s1, const string& s2)
{ {
string::const_reverse_iterator r1 = s1.rbegin(), re1 = s1.rend(), 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) { while (r1 != re1 && r2 != re2) {
char c1 = ::toupper(*r1); char c1 = ::toupper(*r1);
char c2 = ::toupper(*r2); 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&, template bool stringToStrings<list<string> >(const string&,
list<string>&, const string&); list<string>&, const string&);
template bool stringToStrings<vector<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&, template bool stringToStrings<set<string> >(const string&,
set<string>&, const string&); set<string>&, const string&);
template bool stringToStrings<std::unordered_set<string> > template bool stringToStrings<std::unordered_set<string> >
(const string&, std::unordered_set<string>&, const string&); (const string&, std::unordered_set<string>&, const string&);
template <class T> void stringsToString(const T& tokens, string& s) template <class T> void stringsToString(const T& tokens, string& s)
{ {
for (typename T::const_iterator it = tokens.begin(); for (typename T::const_iterator it = tokens.begin();
it != tokens.end(); it++) { it != tokens.end(); it++) {
bool hasblanks = false; bool hasblanks = false;
if (it->find_first_of(" \t\n") != string::npos) { if (it->find_first_of(" \t\n") != string::npos) {
hasblanks = true; hasblanks = true;
@ -382,10 +382,10 @@ template <class T> void stringsToCSV(const T& tokens, string& s,
{ {
s.erase(); s.erase();
for (typename T::const_iterator it = tokens.begin(); for (typename T::const_iterator it = tokens.begin();
it != tokens.end(); it++) { it != tokens.end(); it++) {
bool needquotes = false; bool needquotes = false;
if (it->empty() || 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; needquotes = true;
} }
if (it != tokens.begin()) { 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<list<string> >(const list<string>&, string&, char);
template void stringsToCSV<vector<string> >(const vector<string>&, string&, template void stringsToCSV<vector<string> >(const vector<string>&, string&,
char); char);
void stringToTokens(const string& str, vector<string>& tokens, void stringToTokens(const string& str, vector<string>& tokens,
const string& delims, bool skipinit) 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. // Skip initial delims, return empty if this eats all.
if (skipinit && if (skipinit &&
(startPos = str.find_first_not_of(delims, 0)) == string::npos) { (startPos = str.find_first_not_of(delims, 0)) == string::npos) {
return; return;
} }
while (startPos < str.size()) { while (startPos < str.size()) {
@ -569,13 +569,13 @@ string escapeHtml(const string& in)
{ {
string out; string out;
for (string::size_type pos = 0; pos < in.length(); pos++) { for (string::size_type pos = 0; pos < in.length(); pos++) {
switch(in.at(pos)) { switch(in.at(pos)) {
case '<': out += "&lt;"; break; case '<': out += "&lt;"; break;
case '>': out += "&gt;"; break; case '>': out += "&gt;"; break;
case '&': out += "&amp;"; break; case '&': out += "&amp;"; break;
case '"': out += "&quot;"; break; case '"': out += "&quot;"; break;
default: out += in.at(pos); break; default: out += in.at(pos); break;
} }
} }
return out; 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; dip->y1 = dip->m1 = dip->d1 = dip->y2 = dip->m2 = dip->d2 = 0;
if (it->length() > 4 || !it->length() || if (it->length() > 4 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) { it->find_first_not_of("0123456789") != string::npos) {
return false; return false;
} }
if (it == end || sscanf(it++->c_str(), "%d", &dip->y1) != 1) { 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() || if (it->length() > 2 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) { it->find_first_not_of("0123456789") != string::npos) {
return false; return false;
} }
if (it == end || sscanf(it++->c_str(), "%d", &dip->m1) != 1) { 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() || if (it->length() > 2 || !it->length() ||
it->find_first_not_of("0123456789") != string::npos) { it->find_first_not_of("0123456789") != string::npos) {
return false; return false;
} }
if (it == end || sscanf(it++->c_str(), "%d", &dip->d1) != 1) { 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) int monthdays(int mon, int year)
{ {
switch (mon) { 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: case 2:
return (year % 4) == 0 ? 29 : 28; return (year % 4) == 0 ? 29 : 28;
case 1: case 1:
@ -1023,7 +1023,7 @@ bool parsedateinterval(const string& s, DateInterval *dip)
DateInterval p1, p2, d1, d2; DateInterval p1, p2, d1, d2;
p1 = p2 = d1 = d2 = *dip; p1 = p2 = d1 = d2 = *dip;
bool hasp1 = false, hasp2 = false, hasd1 = false, hasd2 = false, bool hasp1 = false, hasp2 = false, hasd1 = false, hasd2 = false,
hasslash = false; hasslash = false;
if (!stringToStrings(s, vs, "PYMDpymd-/")) { if (!stringToStrings(s, vs, "PYMDpymd-/")) {
return false; return false;
@ -1164,6 +1164,16 @@ secondelt:
return true; 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) 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 ?? // Note: sun strerror is noted mt-safe ??
reason->append(strerror(_errno)); reason->append(strerror(_errno));
#else #else
#define ERRBUFSZ 200
char errbuf[ERRBUFSZ];
// There are 2 versions of strerror_r. // There are 2 versions of strerror_r.
// - The GNU one returns a pointer to the message (maybe // - The GNU one returns a pointer to the message (maybe
// static storage or supplied buffer). // static storage or supplied buffer).
@ -1198,13 +1206,15 @@ void catstrerror(string *reason, const char *what, int _errno)
// were returned a pointer... // were returned a pointer...
// Also couldn't find an easy way to disable the gnu version without // Also couldn't find an easy way to disable the gnu version without
// changing the cxxflags globally, so forget it. Recent gnu lib versions // changing the cxxflags globally, so forget it. Recent gnu lib versions
// normally default to the posix version. // normally default to the posix version. (not !)
// At worse we get no message at all here. // 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; errbuf[0] = 0;
// We don't use ret, it's there to silence a cc warning reason->append(_check_strerror_r(
auto ret = strerror_r(_errno, errbuf, ERRBUFSZ); strerror_r(_errno, errbuf, sizeof(errbuf)), errbuf));
(void)ret;
reason->append(errbuf);
#endif #endif
} }
@ -1232,7 +1242,7 @@ static std::unordered_map<string, string> lang_to_code {
{"th", "iso-8859-11"}, {"th", "iso-8859-11"},
{"tr", "iso-8859-9"}, {"tr", "iso-8859-9"},
{"uk", "koi8-u"}, {"uk", "koi8-u"},
}; };
static const string cstr_cp1252("CP1252"); static const string cstr_cp1252("CP1252");
string langtocode(const string& lang) string langtocode(const string& lang)
@ -1252,7 +1262,7 @@ string localelang()
const char *lang = getenv("LANG"); const char *lang = getenv("LANG");
if (lang == 0 || *lang == 0 || !strcmp(lang, "C") || if (lang == 0 || *lang == 0 || !strcmp(lang, "C") ||
!strcmp(lang, "POSIX")) { !strcmp(lang, "POSIX")) {
return "en"; return "en";
} }
string locale(lang); string locale(lang);