utils: Make sure the compiler can emit format warnings for stringtf
Unfortunately the compilers can't emit Wformat warnings for variadic templates
and those can't be annotated with the format attribute.
Use a variadic function which can be annotated and thus warns on format string-args mismatches.
Ref 0796a2262e
This commit is contained in:
parent
80b08a2075
commit
eaf2e51b0c
|
@ -518,7 +518,7 @@ void Event::AddFrame(Image *image,
|
|||
|
||||
if (image) {
|
||||
if (save_jpegs & 1) {
|
||||
std::string event_file = stringtf(staticConfig.capture_file_format, path.c_str(), frames);
|
||||
std::string event_file = stringtf(staticConfig.capture_file_format.c_str(), path.c_str(), frames);
|
||||
Debug(1, "Writing capture frame %d to %s", frames, event_file.c_str());
|
||||
if (!WriteFrameImage(image, timestamp, event_file.c_str())) {
|
||||
Error("Failed to write frame image");
|
||||
|
@ -548,7 +548,7 @@ void Event::AddFrame(Image *image,
|
|||
}
|
||||
|
||||
if (alarm_image and (save_jpegs & 2)) {
|
||||
std::string event_file = stringtf(staticConfig.analyse_file_format, path.c_str(), frames);
|
||||
std::string event_file = stringtf(staticConfig.analyse_file_format.c_str(), path.c_str(), frames);
|
||||
Debug(1, "Writing analysis frame %d", frames);
|
||||
if (!WriteFrameImage(alarm_image, timestamp, event_file.c_str(), true)) {
|
||||
Error("Failed to write analysis frame image");
|
||||
|
|
|
@ -44,7 +44,7 @@ constexpr Milliseconds EventStream::STREAM_PAUSE_WAIT;
|
|||
bool EventStream::loadInitialEventData(int monitor_id, SystemTimePoint event_time) {
|
||||
std::string sql = stringtf("SELECT `Id` FROM `Events` WHERE "
|
||||
"`MonitorId` = %d AND unix_timestamp(`EndDateTime`) > %ld "
|
||||
"ORDER BY `Id` ASC LIMIT 1", monitor_id, event_time);
|
||||
"ORDER BY `Id` ASC LIMIT 1", monitor_id, std::chrono::system_clock::to_time_t(event_time));
|
||||
|
||||
MYSQL_RES *result = zmDbFetch(sql.c_str());
|
||||
if (!result)
|
||||
|
@ -687,7 +687,7 @@ bool EventStream::checkEventLoaded() {
|
|||
} // void EventStream::checkEventLoaded()
|
||||
|
||||
Image * EventStream::getImage( ) {
|
||||
std::string path = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id);
|
||||
std::string path = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
|
||||
Debug(2, "EventStream::getImage path(%s) from %s frame(%ld) ", path.c_str(), event_data->path.c_str(), curr_frame_id);
|
||||
Image *image = new Image(path.c_str());
|
||||
return image;
|
||||
|
@ -702,12 +702,12 @@ bool EventStream::sendFrame(Microseconds delta_us) {
|
|||
// This needs to be abstracted. If we are saving jpgs, then load the capture file.
|
||||
// If we are only saving analysis frames, then send that.
|
||||
if (event_data->SaveJPEGs & 1) {
|
||||
filepath = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id);
|
||||
filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
|
||||
} else if (event_data->SaveJPEGs & 2) {
|
||||
filepath = stringtf(staticConfig.analyse_file_format, event_data->path.c_str(), curr_frame_id);
|
||||
filepath = stringtf(staticConfig.analyse_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
|
||||
if (stat(filepath.c_str(), &filestat) < 0) {
|
||||
Debug(1, "analyze file %s not found will try to stream from other", filepath.c_str());
|
||||
filepath = stringtf(staticConfig.capture_file_format, event_data->path.c_str(), curr_frame_id);
|
||||
filepath = stringtf(staticConfig.capture_file_format.c_str(), event_data->path.c_str(), curr_frame_id);
|
||||
if (stat(filepath.c_str(), &filestat) < 0) {
|
||||
Debug(1, "capture file %s not found either", filepath.c_str());
|
||||
filepath = "";
|
||||
|
|
|
@ -528,8 +528,8 @@ void Logger::logPrint(bool hex, const char *filepath, int line, int level, const
|
|||
"INSERT INTO `Logs` "
|
||||
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
|
||||
" VALUES "
|
||||
"( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
||||
now_sec, now_frac.count(), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString,
|
||||
"( %ld.%06" PRIi64 ", '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
||||
now_sec, static_cast<int64>(now_frac.count()), mId.c_str(), staticConfig.SERVER_ID, tid, level, classString,
|
||||
escapedString.c_str(), file, line);
|
||||
dbQueue.push(std::move(sql_string));
|
||||
} else {
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "zm_config.h"
|
||||
#include "zm_logger.h"
|
||||
#include <array>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <fcntl.h> /* Definition of AT_* constants */
|
||||
#include <sstream>
|
||||
|
@ -116,6 +117,26 @@ std::string Join(const StringVector &values, const std::string &delim) {
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
std::string stringtf(const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
va_list args2;
|
||||
va_copy(args2, args);
|
||||
|
||||
int size = vsnprintf(nullptr, 0, format, args) + 1; // Extra space for '\0'
|
||||
va_end(args);
|
||||
|
||||
if (size <= 0) {
|
||||
throw std::runtime_error("Error during formatting.");
|
||||
}
|
||||
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
vsnprintf(buf.get(), size, format, args2);
|
||||
va_end(args2);
|
||||
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
|
||||
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes) {
|
||||
static constexpr char lowercase_table[] = "0123456789abcdef";
|
||||
std::string buf;
|
||||
|
|
|
@ -61,16 +61,8 @@ inline bool StartsWith(const std::string &haystack, const std::string &needle) {
|
|||
return (haystack.substr(0, needle.length()) == needle);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
std::string stringtf(const std::string &format, Args... args) {
|
||||
int size = snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
|
||||
if (size <= 0) {
|
||||
throw std::runtime_error("Error during formatting.");
|
||||
}
|
||||
std::unique_ptr<char[]> buf(new char[size]);
|
||||
snprintf(buf.get(), size, format.c_str(), args...);
|
||||
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
|
||||
}
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
std::string stringtf(const char* format, ...);
|
||||
|
||||
std::string ByteArrayToHexString(nonstd::span<const uint8> bytes);
|
||||
|
||||
|
|
Loading…
Reference in New Issue