From 11d8818d2c3beca22091955a7e2c8fa9519bf820 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 01:26:40 +0100 Subject: [PATCH 01/25] clients/nutclient.h: align method docs with param names --- clients/nutclient.h | 51 ++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/clients/nutclient.h b/clients/nutclient.h index db928575a9..a397f32377 100644 --- a/clients/nutclient.h +++ b/clients/nutclient.h @@ -151,13 +151,13 @@ class Client * \todo Is his method is global to all connection protocol or is it specific to TCP ? * \note Actually, authentication fails only if already set, not if bad values are sent. */ - virtual void authenticate(const std::string& user, const std::string& passwd)=0; + virtual void authenticate(const std::string& user, const std::string& passwd) = 0; /** * Disconnect from the NUTD server. * \todo Is his method is global to all connection protocol or is it specific to TCP ? */ - virtual void logout()=0; + virtual void logout() = 0; /** * Device manipulations. @@ -186,13 +186,13 @@ class Client * Retrieve names of devices supported by NUTD server. * \return The set of names of supported devices. */ - virtual std::set getDeviceNames()=0; + virtual std::set getDeviceNames() = 0; /** * Retrieve the description of a device. * \param name Device name. * \return Device description. */ - virtual std::string getDeviceDescription(const std::string& name)=0; + virtual std::string getDeviceDescription(const std::string& name) = 0; /** \} */ /** @@ -205,13 +205,13 @@ class Client * \param dev Device name * \return Variable names */ - virtual std::set getDeviceVariableNames(const std::string& dev)=0; + virtual std::set getDeviceVariableNames(const std::string& dev) = 0; /** * Retrieve names of read/write variables supported by a device. * \param dev Device name * \return RW variable names */ - virtual std::set getDeviceRWVariableNames(const std::string& dev)=0; + virtual std::set getDeviceRWVariableNames(const std::string& dev) = 0; /** * Test if a variable is supported by a device. * \param dev Device name @@ -225,14 +225,14 @@ class Client * \param name Variable name * \return Variable description if provided. */ - virtual std::string getDeviceVariableDescription(const std::string& dev, const std::string& name)=0; + virtual std::string getDeviceVariableDescription(const std::string& dev, const std::string& name) = 0; /** * Retrieve values of a variable. * \param dev Device name * \param name Variable name * \return Variable values (usually one) if available. */ - virtual std::vector getDeviceVariableValue(const std::string& dev, const std::string& name)=0; + virtual std::vector getDeviceVariableValue(const std::string& dev, const std::string& name) = 0; /** * Retrieve values of all variables of a device. * \param dev Device name @@ -251,14 +251,14 @@ class Client * \param name Variable name * \param value Variable value */ - virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value)=0; + virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::string& value) = 0; /** * Intend to set the value of a variable. * \param dev Device name * \param name Variable name - * \param value Variable value + * \param values Vector of variable values */ - virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::vector& values)=0; + virtual TrackingID setDeviceVariable(const std::string& dev, const std::string& name, const std::vector& values) = 0; /** \} */ /** @@ -271,7 +271,7 @@ class Client * \param dev Device name * \return Command names */ - virtual std::set getDeviceCommandNames(const std::string& dev)=0; + virtual std::set getDeviceCommandNames(const std::string& dev) = 0; /** * Test if a command is supported by a device. * \param dev Device name @@ -285,14 +285,14 @@ class Client * \param name Command name * \return Command description if provided. */ - virtual std::string getDeviceCommandDescription(const std::string& dev, const std::string& name)=0; + virtual std::string getDeviceCommandDescription(const std::string& dev, const std::string& name) = 0; /** * Intend to execute a command. * \param dev Device name * \param name Command name * \param param Additional command parameter */ - virtual TrackingID executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param="")=0; + virtual TrackingID executeDeviceCommand(const std::string& dev, const std::string& name, const std::string& param="") = 0; /** \} */ /** @@ -303,25 +303,25 @@ class Client * Log the current user (if authenticated) for a device. * \param dev Device name. */ - virtual void deviceLogin(const std::string& dev)=0; + virtual void deviceLogin(const std::string& dev) = 0; /** * Retrieve the number of user longged in the specified device. * \param dev Device name. * \return Number of logged-in users. */ - virtual int deviceGetNumLogins(const std::string& dev)=0; - virtual void deviceMaster(const std::string& dev)=0; - virtual void deviceForcedShutdown(const std::string& dev)=0; + virtual int deviceGetNumLogins(const std::string& dev) = 0; + virtual void deviceMaster(const std::string& dev) = 0; + virtual void deviceForcedShutdown(const std::string& dev) = 0; /** * Retrieve the result of a tracking ID. * \param id Tracking ID. */ - virtual TrackingResult getTrackingResult(const TrackingID& id)=0; + virtual TrackingResult getTrackingResult(const TrackingID& id) = 0; virtual bool hasFeature(const Feature& feature); - virtual bool isFeatureEnabled(const Feature& feature)=0; - virtual void setFeature(const Feature& feature, bool status)=0; + virtual bool isFeatureEnabled(const Feature& feature) = 0; + virtual void setFeature(const Feature& feature, bool status) = 0; static const Feature TRACKING; @@ -537,7 +537,7 @@ class Device /** * Intend to set values of a variable of the device. * \param name Variable name. - * \param value New variable values. + * \param values Vector of new variable values. */ void setVariable(const std::string& name, const std::vector& values); @@ -672,7 +672,7 @@ class Variable void setValue(const std::string& value); /** * Intend to set (multiple) values to the variable. - * \param value New variable values. + * \param values Vector of new variable values. */ void setValues(const std::vector& values); @@ -745,9 +745,8 @@ class Command std::string getDescription(); /** - * Intend to retrieve command description. - * \param param Additional command parameter - * \return Command description if provided. + * Intend to execute the instant command on device. + * \param param Optional additional command parameter */ void execute(const std::string& param=""); From a40fc2668fd9c19a52ac70094bd69c35b916884e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 01:10:35 +0100 Subject: [PATCH 02/25] m4/ax_c_pragmas.m4: for (clang) c++ builds with C++11/17/20, avoid warnings about C++98 compatibility that we do not claim anyway - check that we have pragmas for that --- m4/ax_c_pragmas.m4 | 48 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index e58513b727..31ef6eb79d 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -3,16 +3,23 @@ dnl e.g. diagnostics management to keep warnings quiet sometimes AC_DEFUN([AX_C_PRAGMAS], [ CFLAGS_SAVED="${CFLAGS}" + CXXFLAGS_SAVED="${CXXFLAGS}" + + dnl ### To be sure, bolt the language + AC_LANG_PUSH([C]) dnl # This is expected to fail builds with unknown pragma names on GCC or CLANG at least AS_IF([test "${CLANG}" = "yes"], - [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning-option"], + [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning-option" + CXXFLAGS="${CXXFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning-option"], [AS_IF([test "${GCC}" = "yes"], dnl ### Despite the docs, this dies with lack of (apparently) support for dnl ### -Wunknown-warning(-options) on all GCC versions I tried (v5-v10) dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning"], - [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror"], - [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror"]) + [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror" + CXXFLAGS="${CXXFLAGS_SAVED} -Wall -Wextra -Werror"], + [CFLAGS="${CFLAGS_SAVED} -Wall -Wextra -Werror" + CXXFLAGS="${CXXFLAGS_SAVED} -Wall -Wextra -Werror"]) ]) AC_CACHE_CHECK([for pragma GCC diagnostic push and pop], @@ -78,6 +85,37 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code"]) ]) + AC_LANG_POP([C]) + + dnl ### Series of tests for C++ specific pragmas + AC_LANG_PUSH([C++]) + + AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"]], [])], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic=yes], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"]) + ]) + + AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wc++98-compat"], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wc++98-compat"]], [])], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat=yes], + [ax_cv__pragma__gcc__diags_ignored_cxx98_compat=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat"]) + ]) + + AC_LANG_POP([C++]) + dnl # Meta-macros for simpler use-cases where we pick dnl # equivalent-effect macros for different compiler versions AS_IF([test "$ax_cv__pragma__gcc__diags_push_pop" = "yes"],[ @@ -87,6 +125,9 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_unreachable_code_break" = "yes" ],[ AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wunreachable-code(-break)" and for push-pop support]) ]) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat_pedantic" = "yes" || test "$ax_cv__pragma__gcc__diags_ignored_cxx98_compat" = "yes" ],[ + AC_DEFINE([HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT], 1, [define if your compiler has pragmas for GCC diagnostic ignored "-Wc++98-compat(-pedantic)" and for push-pop support]) + ]) ]) dnl ### Sanity check if the CLI options actually work: @@ -115,4 +156,5 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" [AC_MSG_WARN([A bogus test that was expected to fail did not! ax_cv__pragma__bogus_diag=$ax_cv__pragma__bogus_diag (not 'no')])]) CFLAGS="${CFLAGS_SAVED}" + CXXFLAGS="${CXXFLAGS_SAVED}" ]) From 9f42fdfe18eb46c33f4733ea50366b0afbe717a2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 01:20:42 +0100 Subject: [PATCH 03/25] clients/nutclient.cpp: for (clang) c++ builds with C++11/17/20, avoid warnings about C++98 compatibility that we do not claim anyway - quiesce in C++ source --- clients/nutclient.cpp | 73 ++++++++++++++++++++++++++++--------------- clients/nutclient.h | 2 +- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index d0170c3919..a4b994ecdf 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -60,6 +60,23 @@ static inline void *xrealloc(void *ptr, size_t size){return realloc(ptr, size);} static inline char *xstrdup(const char *string){return strdup(string);} #endif /* HAVE_NUTCOMMON */ +/* To stay in line with modern C++, we use nullptr (not numeric NULL + * or shim __null on some systems) which was defined after C++98. + * The NUT C++ interface is intended for C++11 and newer, so we + * quiesce these warnigns if possible. + * An idea might be to detect if we do build with old C++ standard versions + * and define a nullptr like https://stackoverflow.com/a/44517878/4715872 + * but again - currently we do not intend to support that officially. + */ +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT +#pragma GCC diagnostic push +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT_PEDANTIC +#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT +#pragma GCC diagnostic ignored "-Wc++98-compat" +#endif namespace nut { @@ -175,7 +192,7 @@ void Socket::connect(const std::string& host, int port) } } - for (ai = res; ai != NULL; ai = ai->ai_next) { + for (ai = res; ai != nullptr; ai = ai->ai_next) { sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); @@ -202,11 +219,11 @@ void Socket::connect(const std::string& host, int port) if(errno == EINPROGRESS) { FD_ZERO(&wfds); FD_SET(sock_fd, &wfds); - select(sock_fd+1,NULL,&wfds,NULL, hasTimeout()?&_tv:NULL); + select(sock_fd+1, nullptr, &wfds, nullptr, hasTimeout() ? &_tv : nullptr); if (FD_ISSET(sock_fd, &wfds)) { error_size = sizeof(error); - getsockopt(sock_fd,SOL_SOCKET,SO_ERROR, - &error,&error_size); + getsockopt(sock_fd, SOL_SOCKET, SO_ERROR, + &error, &error_size); if( error == 0) { /* connect successful */ v = 0; @@ -262,10 +279,10 @@ void Socket::connect(const std::string& host, int port) #ifdef OLD - struct hostent *hostinfo = NULL; + struct hostent *hostinfo = nullptr; SOCKADDR_IN sin = { 0 }; hostinfo = ::gethostbyname(host.c_str()); - if(hostinfo == NULL) /* Host doesnt exist */ + if(hostinfo == nullptr) /* Host doesnt exist */ { throw nut::UnknownHostException(); } @@ -316,7 +333,7 @@ size_t Socket::read(void* buf, size_t sz) fd_set fds; FD_ZERO(&fds); FD_SET(_sock, &fds); - int ret = select(_sock+1, &fds, NULL, NULL, &_tv); + int ret = select(_sock+1, &fds, nullptr, nullptr, &_tv); if (ret < 1) { throw nut::TimeoutException(); } @@ -343,7 +360,7 @@ size_t Socket::write(const void* buf, size_t sz) fd_set fds; FD_ZERO(&fds); FD_SET(_sock, &fds); - int ret = select(_sock+1, NULL, &fds, NULL, &_tv); + int ret = select(_sock+1, nullptr, &fds, nullptr, &_tv); if (ret < 1) { throw nut::TimeoutException(); } @@ -427,7 +444,7 @@ Device Client::getDevice(const std::string& name) if(hasDevice(name)) return Device(this, name); else - return Device(NULL, ""); + return Device(nullptr, ""); } std::set Client::getDevices() @@ -587,7 +604,7 @@ Device TcpClient::getDevice(const std::string& name) catch(NutException& ex) { if(ex.str()=="UNKNOWN-UPS") - return Device(NULL, ""); + return Device(nullptr, ""); else throw; } @@ -1116,7 +1133,7 @@ Client* Device::getClient() bool Device::isOk()const { - return _client!=NULL && !_name.empty(); + return _client!=nullptr && !_name.empty(); } Device::operator bool()const @@ -1189,7 +1206,7 @@ Variable Device::getVariable(const std::string& name) if(getClient()->hasDeviceVariable(getName(), name)) return Variable(this, name); else - return Variable(NULL, ""); + return Variable(nullptr, ""); } std::set Device::getVariables() @@ -1245,7 +1262,7 @@ Command Device::getCommand(const std::string& name) if(getClient()->hasDeviceCommand(getName(), name)) return Command(this, name); else - return Command(NULL, ""); + return Command(nullptr, ""); } TrackingID Device::executeCommand(const std::string& name, const std::string& param) @@ -1326,7 +1343,7 @@ Device* Variable::getDevice() bool Variable::isOk()const { - return _device!=NULL && !_name.empty(); + return _device!=nullptr && !_name.empty(); } @@ -1421,7 +1438,7 @@ Device* Command::getDevice() bool Command::isOk()const { - return _device!=NULL && !_name.empty(); + return _device!=nullptr && !_name.empty(); } Command::operator bool()const @@ -1466,14 +1483,14 @@ extern "C" { strarr strarr_alloc(unsigned short count) { strarr arr = (strarr)xcalloc(count+1, sizeof(char*)); - arr[count] = NULL; + arr[count] = nullptr; return arr; } void strarr_free(strarr arr) { char** pstr = arr; - while(*pstr!=NULL) + while(*pstr!=nullptr) { free(*pstr); ++pstr; @@ -1517,7 +1534,7 @@ NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short por { // TODO really catch it delete client; - return NULL; + return nullptr; } } @@ -1709,7 +1726,7 @@ strarr nutclient_get_devices(NUTCLIENT_t client) catch(...){} } } - return NULL; + return nullptr; } int nutclient_has_device(NUTCLIENT_t client, const char* dev) @@ -1743,7 +1760,7 @@ char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev) catch(...){} } } - return NULL; + return nullptr; } strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev) @@ -1760,7 +1777,7 @@ strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev) catch(...){} } } - return NULL; + return nullptr; } strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev) @@ -1777,7 +1794,7 @@ strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev) catch(...){} } } - return NULL; + return nullptr; } int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const char* var) @@ -1811,7 +1828,7 @@ char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* catch(...){} } } - return NULL; + return nullptr; } strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, const char* var) @@ -1828,7 +1845,7 @@ strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, catch(...){} } } - return NULL; + return nullptr; } void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, const char* var, const char* value) @@ -1885,7 +1902,7 @@ strarr nutclient_get_device_commands(NUTCLIENT_t client, const char* dev) catch(...){} } } - return NULL; + return nullptr; } int nutclient_has_device_command(NUTCLIENT_t client, const char* dev, const char* cmd) @@ -1919,7 +1936,7 @@ char* nutclient_get_device_command_description(NUTCLIENT_t client, const char* d catch(...){} } } - return NULL; + return nullptr; } void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const char* cmd, const char* param) @@ -1938,4 +1955,8 @@ void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const } } +#ifdef HAVE_PRAGMAS_FOR_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT +#pragma GCC diagnostic pop +#endif + } /* extern "C" */ diff --git a/clients/nutclient.h b/clients/nutclient.h index a397f32377..f2cadcb11f 100644 --- a/clients/nutclient.h +++ b/clients/nutclient.h @@ -985,7 +985,7 @@ typedef NUTCLIENT_t NUTCLIENT_TCP_t; * Create a client to NUTD using a TCP connection. * \param host Host name to connect to. * \param port Host port. - * \return New client or NULL if failed. + * \return New client or nullptr if failed. */ NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short port); /** From ba9d2b43db55e7f83c10b351e3445334004e6c1b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 01:41:53 +0100 Subject: [PATCH 04/25] clients/nutclient.cpp: fix old-style C casts into static_cast<>s --- clients/nutclient.cpp | 64 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index a4b994ecdf..3535d8d107 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -169,7 +169,7 @@ void Socket::connect(const std::string& host, int port) throw nut::UnknownHostException(); } - snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port); + snprintf(sport, sizeof(sport), "%hu", static_cast(port)); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; @@ -345,7 +345,7 @@ size_t Socket::read(void* buf, size_t sz) disconnect(); throw nut::IOException("Error while reading on socket"); } - return (size_t) res; + return static_cast(res); } size_t Socket::write(const void* buf, size_t sz) @@ -372,7 +372,7 @@ size_t Socket::write(const void* buf, size_t sz) disconnect(); throw nut::IOException("Error while writing on socket"); } - return (size_t) res; + return static_cast(res); } std::string Socket::read() @@ -1482,7 +1482,7 @@ extern "C" { strarr strarr_alloc(unsigned short count) { - strarr arr = (strarr)xcalloc(count+1, sizeof(char*)); + strarr arr = static_cast(xcalloc(count+1, sizeof(char*))); arr[count] = nullptr; return arr; } @@ -1528,7 +1528,7 @@ NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short por try { client->connect(host, port); - return (NUTCLIENT_TCP_t)client; + return static_cast(client); } catch(nut::NutException& ex) { @@ -1543,7 +1543,7 @@ void nutclient_destroy(NUTCLIENT_t client) { if(client) { - delete (nut::Client*)client; + delete static_cast(client); } } @@ -1551,7 +1551,7 @@ int nutclient_tcp_is_connected(NUTCLIENT_TCP_t client) { if(client) { - nut::TcpClient* cl = dynamic_cast((nut::Client*)client); + nut::TcpClient* cl = dynamic_cast(static_cast(client)); if(cl) { return cl->isConnected() ? 1 : 0; @@ -1564,7 +1564,7 @@ void nutclient_tcp_disconnect(NUTCLIENT_TCP_t client) { if(client) { - nut::TcpClient* cl = dynamic_cast((nut::Client*)client); + nut::TcpClient* cl = dynamic_cast(static_cast(client)); if(cl) { cl->disconnect(); @@ -1576,7 +1576,7 @@ int nutclient_tcp_reconnect(NUTCLIENT_TCP_t client) { if(client) { - nut::TcpClient* cl = dynamic_cast((nut::Client*)client); + nut::TcpClient* cl = dynamic_cast(static_cast(client)); if(cl) { try @@ -1594,7 +1594,7 @@ void nutclient_tcp_set_timeout(NUTCLIENT_TCP_t client, long timeout) { if(client) { - nut::TcpClient* cl = dynamic_cast((nut::Client*)client); + nut::TcpClient* cl = dynamic_cast(static_cast(client)); if(cl) { cl->setTimeout(timeout); @@ -1606,7 +1606,7 @@ long nutclient_tcp_get_timeout(NUTCLIENT_TCP_t client) { if(client) { - nut::TcpClient* cl = dynamic_cast((nut::Client*)client); + nut::TcpClient* cl = dynamic_cast(static_cast(client)); if(cl) { return cl->getTimeout(); @@ -1619,7 +1619,7 @@ void nutclient_authenticate(NUTCLIENT_t client, const char* login, const char* p { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1635,7 +1635,7 @@ void nutclient_logout(NUTCLIENT_t client) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1651,7 +1651,7 @@ void nutclient_device_login(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1667,7 +1667,7 @@ int nutclient_get_device_num_logins(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1684,7 +1684,7 @@ void nutclient_device_master(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1700,7 +1700,7 @@ void nutclient_device_forced_shutdown(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1716,7 +1716,7 @@ strarr nutclient_get_devices(NUTCLIENT_t client) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1733,7 +1733,7 @@ int nutclient_has_device(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1750,7 +1750,7 @@ char* nutclient_get_device_description(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1767,7 +1767,7 @@ strarr nutclient_get_device_variables(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1784,7 +1784,7 @@ strarr nutclient_get_device_rw_variables(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1801,7 +1801,7 @@ int nutclient_has_device_variable(NUTCLIENT_t client, const char* dev, const cha { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1818,7 +1818,7 @@ char* nutclient_get_device_variable_description(NUTCLIENT_t client, const char* { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1835,7 +1835,7 @@ strarr nutclient_get_device_variable_values(NUTCLIENT_t client, const char* dev, { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1852,7 +1852,7 @@ void nutclient_set_device_variable_value(NUTCLIENT_t client, const char* dev, co { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1868,13 +1868,13 @@ void nutclient_set_device_variable_values(NUTCLIENT_t client, const char* dev, c { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try { std::vector vals; - strarr pstr = (strarr)values; + strarr pstr = static_cast(values); while(*pstr) { vals.push_back(std::string(*pstr)); @@ -1892,7 +1892,7 @@ strarr nutclient_get_device_commands(NUTCLIENT_t client, const char* dev) { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1909,7 +1909,7 @@ int nutclient_has_device_command(NUTCLIENT_t client, const char* dev, const char { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1926,7 +1926,7 @@ char* nutclient_get_device_command_description(NUTCLIENT_t client, const char* d { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try @@ -1943,7 +1943,7 @@ void nutclient_execute_device_command(NUTCLIENT_t client, const char* dev, const { if(client) { - nut::Client* cl = (nut::Client*)client; + nut::Client* cl = static_cast(client); if(cl) { try From 48206849a58cb7a536823d477b5901da2c9760a1 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 01:49:21 +0100 Subject: [PATCH 05/25] clients/nutclient.{h,cpp}: align strarr_alloc() type with xcalloc() it uses => size_t --- clients/nutclient.cpp | 2 +- clients/nutclient.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index 3535d8d107..84d9ad790d 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -1480,7 +1480,7 @@ void Command::execute(const std::string& param) extern "C" { -strarr strarr_alloc(unsigned short count) +strarr strarr_alloc(size_t count) { strarr arr = static_cast(xcalloc(count+1, sizeof(char*))); arr[count] = nullptr; diff --git a/clients/nutclient.h b/clients/nutclient.h index f2cadcb11f..8cc2440c7f 100644 --- a/clients/nutclient.h +++ b/clients/nutclient.h @@ -781,7 +781,7 @@ typedef char** strarr; /** * Alloc an array of string. */ -strarr strarr_alloc(unsigned short count); +strarr strarr_alloc(size_t count); /** * Free an array of string. From 4aad2968d6efaf866d115c0194c7619dadb601da Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:05:24 +0100 Subject: [PATCH 06/25] m4/ax_c_pragmas.m4: define pragmas for -Wexit-time-destructors and -Wglobal-constructors handling --- m4/ax_c_pragmas.m4 | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index 31ef6eb79d..34f7b943c7 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -114,6 +114,30 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_CXX98_COMPAT], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wc++98-compat"]) ]) + AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wglobal-constructors"], + [ax_cv__pragma__gcc__diags_ignored_global_constructors], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wglobal-constructors"]], [])], + [ax_cv__pragma__gcc__diags_ignored_global_constructors=yes], + [ax_cv__pragma__gcc__diags_ignored_global_constructors=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_global_constructors" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wglobal-constructors"]) + ]) + + AC_CACHE_CHECK([for C++ pragma GCC diagnostic ignored "-Wexit-time-destructors"], + [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wexit-time-destructors"]], [])], + [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors=yes], + [ax_cv__pragma__gcc__diags_ignored_exit_time_destructors=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_exit_time_destructors" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wexit-time-destructors"]) + ]) + AC_LANG_POP([C++]) dnl # Meta-macros for simpler use-cases where we pick From b5353cc52d6ab4ebc5888f693df28ebf51e45c73 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:05:55 +0100 Subject: [PATCH 07/25] clients/nutclient.cpp: use pragmas for -Wexit-time-destructors and -Wglobal-constructors handling for an std:string static variable --- clients/nutclient.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index 84d9ad790d..f44b181eed 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -423,7 +423,23 @@ void Socket::write(const std::string& str) * */ +/* Pedantic builds complain about the static variable below... + * It is assumed safe to ignore since it is a std::string with + * no complex teardown at program exit. + */ +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic push +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS +# pragma GCC diagnostic ignored "-Wglobal-constructors" +# endif +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS +# pragma GCC diagnostic ignored "-Wexit-time-destructors" +# endif +#endif const Feature Client::TRACKING = "TRACKING"; +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic pop +#endif Client::Client() { From b56a607572fd4d05062fad2b6e314920d7a9bf7c Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:23:05 +0100 Subject: [PATCH 08/25] clients/Makefile.am: define HAVE_NUTCOMMON for NUT C++ builds --- clients/Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clients/Makefile.am b/clients/Makefile.am index aba351a3f7..aaa25cbaa3 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -1,6 +1,11 @@ # Network UPS Tools: clients EXTRA_DIST = +# nutclient.cpp for some legacy reason (maybe initial detached development?) +# optionally includes "common.h" with the NUT build setup - and this option +# was never triggered in fact, not until pushed through command line like this: +AM_CXXFLAGS = -DHAVE_NUTCOMMON=1 + # by default, link programs in this directory with libcommon.a LDADD = ../common/libcommon.la libupsclient.la $(NETLIBS) if WITH_SSL From c643daf88cd756f65fe0287079853f94c63065b2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:24:47 +0100 Subject: [PATCH 09/25] clients/nutclient.cpp: quiesce warning and make visible the unused variable --- clients/nutclient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index f44b181eed..e40010a59c 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -1549,6 +1549,7 @@ NUTCLIENT_TCP_t nutclient_tcp_create_client(const char* host, unsigned short por catch(nut::NutException& ex) { // TODO really catch it + NUT_UNUSED_VARIABLE(ex); delete client; return nullptr; } From 1ebb2c68f7376c4f508152be34c0909983fe94eb Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:26:34 +0100 Subject: [PATCH 10/25] clients/nutclient.cpp: (presumed) typo fix - line ended with comma not semicolon --- clients/nutclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index e40010a59c..de1fe5f670 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -730,7 +730,7 @@ std::map > > TcpClient { std::vector& vals = *it2; std::string var = vals[0]; - vals.erase(vals.begin()), + vals.erase(vals.begin()); map2[var] = vals; } map[*it] = map2; From 2cfdea9bf31b41b8ee11715fc3c44ab4fa0dc368 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 02:51:29 +0100 Subject: [PATCH 11/25] clients/nutclient.{h,cpp}: move virtual destructors of exception classes into CPP file to bolt a linker unit (avoid Weak Vtables warnings and related build overheads) --- clients/nutclient.cpp | 8 ++++++++ clients/nutclient.h | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/clients/nutclient.cpp b/clients/nutclient.cpp index de1fe5f670..cc5cbd801b 100644 --- a/clients/nutclient.cpp +++ b/clients/nutclient.cpp @@ -98,6 +98,14 @@ std::string SystemException::err() } } +/* Implemented out-of-line to avoid "Weak vtables" warnings and related overheads */ +NutException::~NutException() {} +SystemException::~SystemException() {} +IOException::~IOException() {} +UnknownHostException::~UnknownHostException() {} +NotConnectedException::~NotConnectedException() {} +TimeoutException::~TimeoutException() {} + namespace internal { diff --git a/clients/nutclient.h b/clients/nutclient.h index 8cc2440c7f..db9d0f6877 100644 --- a/clients/nutclient.h +++ b/clients/nutclient.h @@ -51,7 +51,7 @@ class NutException : public std::exception { public: NutException(const std::string& msg):_msg(msg){} - virtual ~NutException() {} + virtual ~NutException(); virtual const char * what() const noexcept {return this->_msg.c_str();} virtual std::string str() const noexcept {return this->_msg;} private: @@ -65,7 +65,7 @@ class SystemException : public NutException { public: SystemException(); - virtual ~SystemException() {} + virtual ~SystemException(); private: static std::string err(); }; @@ -78,7 +78,7 @@ class IOException : public NutException { public: IOException(const std::string& msg):NutException(msg){} - virtual ~IOException() {} + virtual ~IOException(); }; /** @@ -88,7 +88,7 @@ class UnknownHostException : public IOException { public: UnknownHostException():IOException("Unknown host"){} - virtual ~UnknownHostException() {} + virtual ~UnknownHostException(); }; /** @@ -98,7 +98,7 @@ class NotConnectedException : public IOException { public: NotConnectedException():IOException("Not connected"){} - virtual ~NotConnectedException() {} + virtual ~NotConnectedException(); }; /** @@ -108,7 +108,7 @@ class TimeoutException : public IOException { public: TimeoutException():IOException("Timeout"){} - virtual ~TimeoutException() {} + virtual ~TimeoutException(); }; /** From c1fcda134e0682a88ee60bc9f6351f175a9e1a53 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:02:10 +0100 Subject: [PATCH 12/25] clients/Makefile.am: be sure to use NUT libcommon for CXX client builds --- clients/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clients/Makefile.am b/clients/Makefile.am index aaa25cbaa3..68a1b13f0a 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -72,6 +72,9 @@ if HAVE_CXX11 # libnutclient version information and build libnutclient_la_SOURCES = nutclient.h nutclient.cpp libnutclient_la_LDFLAGS = -version-info 1:0:0 +# Needed in not-standalone builds with -DHAVE_NUTCOMMON=1 +# which is defined for in-tree CXX builds above: +libnutclient_la_LIBADD = $(top_builddir)/common/libcommonclient.la else EXTRA_DIST += nutclient.h nutclient.cpp endif From b6348007604bf817a8a724c259d780ef27be1025 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:05:28 +0100 Subject: [PATCH 13/25] tests/cpputest.cpp: print final result code more comprehensibly (especially since process exit code is inverted) --- tests/cpputest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cpputest.cpp b/tests/cpputest.cpp index a30250975e..c804e1f10a 100644 --- a/tests/cpputest.cpp +++ b/tests/cpputest.cpp @@ -58,7 +58,7 @@ int main(int argc, char* argv[]) /* Return error code 1 if the one of test failed. */ std::cerr << "D: Got to the end of test suite with code " << - "'" << wasSucessful << "'" << std::endl; + "'" << ( wasSucessful ? "true" : "false" ) << "'" << std::endl; return wasSucessful ? 0 : 1; } From 6ddc24d55a955c777a8ff1d50c7a86e3b4e28c8b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:08:48 +0100 Subject: [PATCH 14/25] m4/ax_c_pragmas.m4: introduce HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW detection First shot at issue NUT #904 --- m4/ax_c_pragmas.m4 | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index 34f7b943c7..5f65f07c0b 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -85,6 +85,18 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_UNREACHABLE_CODE], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wunreachable-code"]) ]) + AC_CACHE_CHECK([for pragma GCC diagnostic ignored "-Wformat-overflow"], + [ax_cv__pragma__gcc__diags_ignored_format_overflow], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[#pragma GCC diagnostic ignored "-Wformat-overflow"]], [])], + [ax_cv__pragma__gcc__diags_ignored_format_overflow=yes], + [ax_cv__pragma__gcc__diags_ignored_format_overflow=no] + )] + ) + AS_IF([test "$ax_cv__pragma__gcc__diags_ignored_format_overflow" = "yes"],[ + AC_DEFINE([HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW], 1, [define if your compiler has #pragma GCC diagnostic ignored "-Wformat-overflow"]) + ]) + AC_LANG_POP([C]) dnl ### Series of tests for C++ specific pragmas From b3d777fd175f24860c334d17a138337cd7b2b470 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:12:23 +0100 Subject: [PATCH 15/25] tests/nutlogtest.c: use HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW detection to quiesce warnings about "%s" resolving from NULL pointer First shot at issue NUT #904 --- tests/nutlogtest.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index 0a4c49728a..1cb2881544 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -7,6 +7,15 @@ int main(void) { const char *s1 = "!NULL"; const char *s2 = NULL; + +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-overflow" +#endif upsdebugx(0, "D: '%s' vs '%s'", s1, s2); +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) +# pragma GCC diagnostic pop +#endif + return 0; } From 60edbb7b312577d03f16b4ef8ff99679e8e70fe2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:35:35 +0100 Subject: [PATCH 16/25] m4/ax_c_pragmas.m4, str.h => common.h: introduce HAVE_PRINTF_STRING_NULL and NUT_STRARG(x) macro (for issue #904) --- configure.ac | 1 + include/str.h | 9 +++++++++ m4/ax_c_pragmas.m4 | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/configure.ac b/configure.ac index bb2d03737d..e7918d16ac 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,7 @@ dnl Note: the compiler/pragma/attr methods below are custom for NUT codebase: NUT_COMPILER_FAMILY AX_C_PRAGMAS AX_C___ATTRIBUTE__ +AX_C_PRINTF_STRING_NULL AC_CHECK_FUNCS(flock lockf fcvt fcvtl pow10 round abs_val abs) AC_CHECK_FUNCS(fabs, [], [], [#include ]) AC_CHECK_FUNCS(cfsetispeed tcsendbreak) diff --git a/include/str.h b/include/str.h index 028d504a00..92edbda257 100644 --- a/include/str.h +++ b/include/str.h @@ -29,6 +29,15 @@ extern "C" { /* *INDENT-ON* */ #endif +/* Some compilers and/or C libraries do not handle printf("%s", NULL) correctly */ +#ifndef NUT_STRARG +# ifdef HAVE_PRINTF_STRING_NULL +# define NUT_STRARG(x) x +# else +# define NUT_STRARG(x) (x?x:"(null)") +# endif +#endif + /* Remove all * - leading and trailing (str_trim[_m]()) * - leading (str_ltrim[_m]()) diff --git a/m4/ax_c_pragmas.m4 b/m4/ax_c_pragmas.m4 index 5f65f07c0b..db9546882e 100644 --- a/m4/ax_c_pragmas.m4 +++ b/m4/ax_c_pragmas.m4 @@ -194,3 +194,45 @@ dnl ### [CFLAGS="${CFLAGS_SAVED} -Werror=pragmas -Werror=unknown-warning" CFLAGS="${CFLAGS_SAVED}" CXXFLAGS="${CXXFLAGS_SAVED}" ]) + +AC_DEFUN([AX_C_PRINTF_STRING_NULL], [ + dnl ### To be sure, bolt the language + AC_LANG_PUSH([C]) + + AC_CACHE_CHECK([for practical support to pritnf("%s", NULL)], + [ax_cv__printf_string_null], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([dnl +#include +#include +], [dnl +char buf[128]; +char *s = NULL; +int res = snprintf(buf, sizeof(buf), "%s", s); +buf[sizeof(buf)-1] = '\0'; +if (res < 0) { + printf(stderr, "FAILED to snprintf() a NULL string argument"); + exit 1; +} +if (buf[0] == '\0') + printf(stderr, "RETURNED empty string from snprintf() with a NULL string argument"); + exit 0; +} +if (strcasestr(buf, 'null') == NULL) + printf(stderr, "RETURNED some string from snprintf() with a NULL string argument: '%s'", buf); + exit 0; +} +printf(stderr, "SUCCESS: RETURNED a string that contains something like 'null' from snprintf() with a NULL string argument: '%s'", buf); +exit 0; + ])], + [ax_cv__printf_string_null=yes], + [ax_cv__printf_string_null=no] + )] + ) + + AS_IF([test "$ax_cv__printf_string_null" = "yes"],[ + AC_DEFINE([HAVE_PRINTF_STRING_NULL], 1, [define if your libc can printf("%s", NULL) sanely]) + ]) + + AC_LANG_POP([C]) +]) From 34ddafb2fc7dc2b2ca8ed13f83135241f3a742f5 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 13:54:51 +0100 Subject: [PATCH 17/25] tests/nutlogtest.c: add more tests to investigate NUT_STRARG() behaviors --- tests/nutlogtest.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index 1cb2881544..c7a719fee6 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -12,10 +12,28 @@ int main(void) { # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wformat-overflow" #endif - upsdebugx(0, "D: '%s' vs '%s'", s1, s2); + upsdebugx(0, "D: checking with libc handling of NULL: '%s' vs '%s'", s1, s2); #if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_FORMAT_OVERFLOW) # pragma GCC diagnostic pop #endif +/* This explicitly does not work with -Wformat, due to verbatim NULL without a var: + * nutlogtest.c:20:5: error: reading through null pointer (argument 4) [-Werror=format=] + * and also due to (void*) vs (char*) in naive case: + * upsdebugx(0, "D: '%s' vs '%s'", NUT_STRARG(NULL), NULL); + * but with casting the explicit NULL remains: + * upsdebugx(0, "D: '%s' vs '%s'", NUT_STRARG((char *)NULL), (char *)NULL); + */ + + upsdebugx(0, "D: checking with NUT_STRARG macro: '%s' vs '%s'", NUT_STRARG(s2), s2); + +#ifdef NUT_STRARG +#undef NUT_STRARG +#endif + +#define NUT_STRARG(x) (x?x:"") + + upsdebugx(0, "D: checking that macro wrap trick works: '%s' vs '%s'", NUT_STRARG(s2), s2); + return 0; } From cfe2979ac0f23b8c86f5e6ac2d7943eb55d54698 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 17:46:00 +0100 Subject: [PATCH 18/25] tests/Makefile.am: fix delivery and tracking of CPPUNITTEST(ER)SRC --- tests/Makefile.am | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/Makefile.am b/tests/Makefile.am index 8b936e07d3..7c7d8aedc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -15,6 +15,11 @@ nutlogtest_SOURCES = nutlogtest.c nutlogtest_LDADD = $(top_builddir)/common/libcommon.la ### Optional tests which can not be built everywhere +# List of src files for CppUnit tests +CPPUNITTESTSRC = example.cpp nutclienttest.cpp +# The test driver which orchestrates running those tests above +CPPUNITTESTERSRC = cpputest.cpp + if HAVE_CXX11 if HAVE_CPPUNIT # Note: per configure script this "SHOULD" also assume @@ -30,16 +35,12 @@ endif cppunittest_CXXFLAGS = $(AM_CXXFLAGS) $(CPPUNIT_CFLAGS) $(CPPUNIT_CXXFLAGS) $(CPPUNIT_NUT_CXXFLAGS) $(CXXFLAGS) cppunittest_LDFLAGS = $(CPPUNIT_LIBS) cppunittest_LDADD = $(top_builddir)/clients/libnutclient.la - -# List of src files for CppUnit tests -CPPUNITTESTSRC = example.cpp nutclienttest.cpp - -cppunittest_SOURCES = $(CPPUNITTESTSRC) cpputest.cpp +cppunittest_SOURCES = $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) else !HAVE_CPPUNIT # Just redistribute test source into tarball -EXTRA_DIST += example.cpp cpputest.cpp +EXTRA_DIST += $(CPPUNITTESTSRC) $(CPPUNITTESTERSRC) endif !HAVE_CPPUNIT From 1f49916338c6c095df49fb99535e73ce23604f3e Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 17:47:29 +0100 Subject: [PATCH 19/25] tests/nutclienttest.cpp: fix casting --- tests/nutclienttest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/nutclienttest.cpp b/tests/nutclienttest.cpp index d8cb942f5f..a27da93452 100644 --- a/tests/nutclienttest.cpp +++ b/tests/nutclienttest.cpp @@ -98,7 +98,7 @@ void NutClientTest::test_stringset_to_strarr() ptr++; } - CPPUNIT_ASSERT_EQUAL_MESSAGE("stringset_to_strarr(...) result has not 3 items", (size_t)3, res.size()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("stringset_to_strarr(...) result has not 3 items", static_cast(3), res.size()); CPPUNIT_ASSERT_MESSAGE("stringset_to_strarr(...) result has not item \"test\"", res.find("test")!=res.end()); CPPUNIT_ASSERT_MESSAGE("stringset_to_strarr(...) result has not item \"hello\"", res.find("hello")!=res.end()); CPPUNIT_ASSERT_MESSAGE("stringset_to_strarr(...) result has not item \"world\"", res.find("world")!=res.end()); From b85d8bf0bf89a4b465024ea9a1f1f89359c8f586 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 17:59:46 +0100 Subject: [PATCH 20/25] tests/nutclienttest.cpp: fix NULL => nullptr --- tests/nutclienttest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/nutclienttest.cpp b/tests/nutclienttest.cpp index a27da93452..8cfaff9ce1 100644 --- a/tests/nutclienttest.cpp +++ b/tests/nutclienttest.cpp @@ -87,12 +87,12 @@ void NutClientTest::test_stringset_to_strarr() strset.insert("world"); strarr arr = stringset_to_strarr(strset); - CPPUNIT_ASSERT_MESSAGE("stringset_to_strarr(...) result is null", arr!=NULL); + CPPUNIT_ASSERT_MESSAGE("stringset_to_strarr(...) result is null", arr != nullptr); std::set res; char** ptr = arr; - while(*ptr!=NULL) + while(*ptr != nullptr) { res.insert(std::string(*ptr)); ptr++; @@ -114,7 +114,7 @@ void NutClientTest::test_stringvector_to_strarr() strset.push_back("world"); strarr arr = stringvector_to_strarr(strset); - CPPUNIT_ASSERT_MESSAGE("stringvector_to_strarr(...) result is null", arr!=NULL); + CPPUNIT_ASSERT_MESSAGE("stringvector_to_strarr(...) result is null", arr != nullptr); char** ptr = arr; CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not item 0==\"test\"", std::string("test"), std::string(*ptr)); @@ -123,7 +123,7 @@ void NutClientTest::test_stringvector_to_strarr() ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not item 2==\"world\"", std::string("world"), std::string(*ptr)); ++ptr; - CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not only 3 items", (char*)NULL, *ptr); + CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not only 3 items", nullptr, *ptr); strarr_free(arr); } From fefcb285aff38aefe6d07a7a3a890bce1f0ed42a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 18:15:43 +0100 Subject: [PATCH 21/25] tests/nutclienttest.cpp: fix CPPUNIT assert after nullptr --- tests/nutclienttest.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/nutclienttest.cpp b/tests/nutclienttest.cpp index 8cfaff9ce1..f553f9d871 100644 --- a/tests/nutclienttest.cpp +++ b/tests/nutclienttest.cpp @@ -123,7 +123,12 @@ void NutClientTest::test_stringvector_to_strarr() ++ptr; CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not item 2==\"world\"", std::string("world"), std::string(*ptr)); ++ptr; - CPPUNIT_ASSERT_EQUAL_MESSAGE("stringvector_to_strarr(...) result has not only 3 items", nullptr, *ptr); + + /* https://stackoverflow.com/a/12565009/4715872 + * Can not compare nullptr_t and another data type (char*) + * with CPPUNIT template assertEquals() + */ + CPPUNIT_ASSERT_MESSAGE("stringvector_to_strarr(...) result has not only 3 items", nullptr == *ptr); strarr_free(arr); } From 2d022ba756a9e5a8f1172144cd15ef7311a232f3 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 18:01:29 +0100 Subject: [PATCH 22/25] tests/example.cpp: fix casting --- tests/example.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/example.cpp b/tests/example.cpp index 28ea52e318..6f6e9b4093 100644 --- a/tests/example.cpp +++ b/tests/example.cpp @@ -53,7 +53,7 @@ void ExampleTest::testOne() float f = 1.0; // Process - int cast = (int)f; + int cast = static_cast(f); // Check CPPUNIT_ASSERT_EQUAL( i, cast ); From 05c50671c74aa0e90d6ebd932308eae4e023070d Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 17:59:29 +0100 Subject: [PATCH 23/25] tests/*.{c,cpp}: update legaleze headings --- tests/cpputest.cpp | 2 +- tests/example.cpp | 3 +-- tests/nutclienttest.cpp | 1 + tests/nutlogtest.c | 17 +++++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/tests/cpputest.cpp b/tests/cpputest.cpp index c804e1f10a..1168f2562d 100644 --- a/tests/cpputest.cpp +++ b/tests/cpputest.cpp @@ -2,6 +2,7 @@ Copyright (C) 2012 Emilien Kia + 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -61,4 +62,3 @@ int main(int argc, char* argv[]) "'" << ( wasSucessful ? "true" : "false" ) << "'" << std::endl; return wasSucessful ? 0 : 1; } - diff --git a/tests/example.cpp b/tests/example.cpp index 6f6e9b4093..053531d045 100644 --- a/tests/example.cpp +++ b/tests/example.cpp @@ -2,6 +2,7 @@ Copyright (C) 2012 Emilien Kia + 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -58,5 +59,3 @@ void ExampleTest::testOne() // Check CPPUNIT_ASSERT_EQUAL( i, cast ); } - - diff --git a/tests/nutclienttest.cpp b/tests/nutclienttest.cpp index f553f9d871..8a049d49d6 100644 --- a/tests/nutclienttest.cpp +++ b/tests/nutclienttest.cpp @@ -1,6 +1,7 @@ /* nutclienttest - CppUnit nutclient unit test Copyright (C) 2016 Emilien Kia + Copyright (C) 2020 Jim Klimov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/tests/nutlogtest.c b/tests/nutlogtest.c index c7a719fee6..68c6940b32 100644 --- a/tests/nutlogtest.c +++ b/tests/nutlogtest.c @@ -1,6 +1,23 @@ /* nutlogtest - some trivial usage for upslog*() and upsdebug*() related * routines to sanity-check their code (compiler does not warn, test runs * do not crash). + * + * Copyright (C) + * 2020 Jim Klimov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "common.h" From 232644d11c21f6bcc922c287ccda8e2e9bca876f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Wed, 25 Nov 2020 18:07:39 +0100 Subject: [PATCH 24/25] tests/nutclienttest.cpp example.cpp: wrap into HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS et al to avoid warnings for CPPUnit macro implementation (boils down to static vars) --- tests/example.cpp | 18 ++++++++++++++++++ tests/nutclienttest.cpp | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/tests/example.cpp b/tests/example.cpp index 053531d045..e06bf7c9b9 100644 --- a/tests/example.cpp +++ b/tests/example.cpp @@ -18,6 +18,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" + +/* Current CPPUnit offends the honor of C++98 */ +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic push +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS +# pragma GCC diagnostic ignored "-Wglobal-constructors" +# endif +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS +# pragma GCC diagnostic ignored "-Wexit-time-destructors" +# endif +#endif + #include class ExampleTest : public CppUnit::TestFixture @@ -59,3 +73,7 @@ void ExampleTest::testOne() // Check CPPUNIT_ASSERT_EQUAL( i, cast ); } + +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic pop +#endif diff --git a/tests/nutclienttest.cpp b/tests/nutclienttest.cpp index 8a049d49d6..7b0b11b712 100644 --- a/tests/nutclienttest.cpp +++ b/tests/nutclienttest.cpp @@ -17,6 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "common.h" + +/* Current CPPUnit offends the honor of C++98 */ +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic push +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS +# pragma GCC diagnostic ignored "-Wglobal-constructors" +# endif +# ifdef HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS +# pragma GCC diagnostic ignored "-Wexit-time-destructors" +# endif +#endif + #include namespace nut { @@ -203,3 +217,7 @@ void NutClientTest::test_copy_assignment_var() { } } // namespace nut {} + +#if (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_PUSH_POP) && (defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_EXIT_TIME_DESTRUCTORS || defined HAVE_PRAGMA_GCC_DIAGNOSTIC_IGNORED_GLOBAL_CONSTRUCTORS) +#pragma GCC diagnostic pop +#endif From 10677aa5c95f22a4204a8ccb4c6add04b6403042 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 27 Nov 2020 00:20:49 +0100 Subject: [PATCH 25/25] clients/Makefile.am: AM_CXXFLAGS+=-I$(top_srcdir)/include --- clients/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clients/Makefile.am b/clients/Makefile.am index 68a1b13f0a..35e78a8cbb 100644 --- a/clients/Makefile.am +++ b/clients/Makefile.am @@ -4,7 +4,7 @@ EXTRA_DIST = # nutclient.cpp for some legacy reason (maybe initial detached development?) # optionally includes "common.h" with the NUT build setup - and this option # was never triggered in fact, not until pushed through command line like this: -AM_CXXFLAGS = -DHAVE_NUTCOMMON=1 +AM_CXXFLAGS = -DHAVE_NUTCOMMON=1 -I$(top_srcdir)/include # by default, link programs in this directory with libcommon.a LDADD = ../common/libcommon.la libupsclient.la $(NETLIBS)