Commit 60d5bf02 authored by Max Kellermann's avatar Max Kellermann

util/StringFormat: new utility library

parent 41cdc4e1
...@@ -444,6 +444,7 @@ libutil_a_SOURCES = \ ...@@ -444,6 +444,7 @@ libutil_a_SOURCES = \
src/util/NumberParser.hxx \ src/util/NumberParser.hxx \
src/util/MimeType.cxx src/util/MimeType.hxx \ src/util/MimeType.cxx src/util/MimeType.hxx \
src/util/StringBuffer.hxx \ src/util/StringBuffer.hxx \
src/util/StringFormat.hxx \
src/util/StringPointer.hxx \ src/util/StringPointer.hxx \
src/util/StringView.cxx src/util/StringView.hxx \ src/util/StringView.cxx src/util/StringView.hxx \
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \ src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#include "AudioFormat.hxx" #include "AudioFormat.hxx"
#include "util/StringBuffer.hxx" #include "util/StringBuffer.hxx"
#include "util/StringFormat.hxx"
#include <assert.h> #include <assert.h>
#include <stdio.h>
void void
AudioFormat::ApplyMask(AudioFormat mask) noexcept AudioFormat::ApplyMask(AudioFormat mask) noexcept
...@@ -44,21 +44,16 @@ AudioFormat::ApplyMask(AudioFormat mask) noexcept ...@@ -44,21 +44,16 @@ AudioFormat::ApplyMask(AudioFormat mask) noexcept
StringBuffer<24> StringBuffer<24>
ToString(const AudioFormat af) noexcept ToString(const AudioFormat af) noexcept
{ {
StringBuffer<24> buffer;
if (af.format == SampleFormat::DSD && af.sample_rate > 0 && if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
af.sample_rate % 44100 == 0) { af.sample_rate % 44100 == 0) {
/* use shortcuts such as "dsd64" which implies the /* use shortcuts such as "dsd64" which implies the
sample rate */ sample rate */
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u", return StringFormat<24>("dsd%u:%u",
af.sample_rate * 8 / 44100, af.sample_rate * 8 / 44100,
af.channels); af.channels);
return buffer;
} }
snprintf(buffer.data(), buffer.capacity(), "%u:%s:%u", return StringFormat<24>("%u:%s:%u",
af.sample_rate, sample_format_to_string(af.format), af.sample_rate, sample_format_to_string(af.format),
af.channels); af.channels);
return buffer;
} }
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/StringFormat.hxx"
#include <stdio.h> #include <stdio.h>
...@@ -47,10 +48,6 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl, ...@@ -47,10 +48,6 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
unsigned &didreadp, unsigned &didreadp,
unsigned &totalp) const unsigned &totalp) const
{ {
// Create request
char ofbuf[100], cntbuf[100];
sprintf(ofbuf, "%u", offset);
sprintf(cntbuf, "%u", count);
// Some devices require an empty SortCriteria, else bad params // Some devices require an empty SortCriteria, else bad params
IXML_Document *request = IXML_Document *request =
MakeActionHelper("Browse", m_serviceType.c_str(), MakeActionHelper("Browse", m_serviceType.c_str(),
...@@ -58,8 +55,10 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl, ...@@ -58,8 +55,10 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
"BrowseFlag", "BrowseDirectChildren", "BrowseFlag", "BrowseDirectChildren",
"Filter", "*", "Filter", "*",
"SortCriteria", "", "SortCriteria", "",
"StartingIndex", ofbuf, "StartingIndex",
"RequestedCount", cntbuf); StringFormat<32>("%u", offset).c_str(),
"RequestedCount",
StringFormat<32>("%u", count).c_str());
if (request == nullptr) if (request == nullptr)
throw std::runtime_error("UpnpMakeAction() failed"); throw std::runtime_error("UpnpMakeAction() failed");
...@@ -112,15 +111,13 @@ ContentDirectoryService::search(UpnpClient_Handle hdl, ...@@ -112,15 +111,13 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
unsigned offset = 0, total = -1, count; unsigned offset = 0, total = -1, count;
do { do {
char ofbuf[100];
sprintf(ofbuf, "%d", offset);
UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(), UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
"ContainerID", objectId, "ContainerID", objectId,
"SearchCriteria", ss, "SearchCriteria", ss,
"Filter", "*", "Filter", "*",
"SortCriteria", "", "SortCriteria", "",
"StartingIndex", ofbuf, "StartingIndex",
StringFormat<32>("%u", offset).c_str(),
"RequestedCount", "0")); // Setting a value here gets twonky into fits "RequestedCount", "0")); // Setting a value here gets twonky into fits
if (!request) if (!request)
throw std::runtime_error("UpnpMakeAction() failed"); throw std::runtime_error("UpnpMakeAction() failed");
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/ScopeExit.hxx" #include "util/ScopeExit.hxx"
#include "util/FormatString.hxx" #include "util/StringFormat.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#define SUBTUNE_PREFIX "tune_" #define SUBTUNE_PREFIX "tune_"
...@@ -191,18 +190,15 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count, ...@@ -191,18 +190,15 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
tag_handler_invoke_duration(handler, handler_ctx, tag_handler_invoke_duration(handler, handler_ctx,
SongTime::FromMS(info.play_length)); SongTime::FromMS(info.play_length));
if (track_count > 1) { if (track_count > 1)
char track[16]; tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
sprintf(track, "%u", song_num + 1); StringFormat<16>("%u", song_num + 1));
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
}
if (info.song != nullptr) { if (info.song != nullptr) {
if (track_count > 1) { if (track_count > 1) {
/* start numbering subtunes from 1 */ /* start numbering subtunes from 1 */
char tag_title[1024]; const auto tag_title =
snprintf(tag_title, sizeof(tag_title), StringFormat<1024>("%s (%u/%d)",
"%s (%u/%d)",
info.song, song_num + 1, info.song, song_num + 1,
track_count); track_count);
tag_handler_invoke_tag(handler, handler_ctx, tag_handler_invoke_tag(handler, handler_ctx,
...@@ -297,9 +293,9 @@ gme_container_scan(Path path_fs) ...@@ -297,9 +293,9 @@ gme_container_scan(Path path_fs)
ScanMusicEmu(emu, i, ScanMusicEmu(emu, i,
add_tag_handler, &tag_builder); add_tag_handler, &tag_builder);
char track_name[64]; const auto track_name =
snprintf(track_name, sizeof(track_name), StringFormat<64>(SUBTUNE_PREFIX "%03u.%s", i+1,
SUBTUNE_PREFIX "%03u.%s", i+1, subtune_suffix); subtune_suffix);
tail = list.emplace_after(tail, track_name, tail = list.emplace_after(tail, track_name,
tag_builder.Commit()); tag_builder.Commit());
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include "fs/Path.hxx" #include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx" #include "fs/AllocatedPath.hxx"
#include "util/Macros.hxx" #include "util/Macros.hxx"
#include "util/FormatString.hxx" #include "util/StringFormat.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "system/ByteOrder.hxx" #include "system/ByteOrder.hxx"
#include "Log.hxx" #include "Log.hxx"
...@@ -413,9 +413,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks, ...@@ -413,9 +413,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
title = ""; title = "";
if (n_tracks > 1) { if (n_tracks > 1) {
char tag_title[1024]; const auto tag_title =
snprintf(tag_title, sizeof(tag_title), StringFormat<1024>("%s (%u/%u)",
"%s (%u/%u)",
title, track, n_tracks); title, track, n_tracks);
tag_handler_invoke_tag(handler, handler_ctx, tag_handler_invoke_tag(handler, handler_ctx,
TAG_TITLE, tag_title); TAG_TITLE, tag_title);
...@@ -435,9 +434,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks, ...@@ -435,9 +434,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
date); date);
/* track */ /* track */
char track_buffer[16]; tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
sprintf(track_buffer, "%d", track); StringFormat<16>("%u", track));
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track_buffer);
} }
static bool static bool
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "config.h" #include "config.h"
#include "FileOutputStream.hxx" #include "FileOutputStream.hxx"
#include "system/Error.hxx" #include "system/Error.hxx"
#include "util/StringFormat.hxx"
FileOutputStream::FileOutputStream(Path _path, Mode _mode) FileOutputStream::FileOutputStream(Path _path, Mode _mode)
:path(_path), mode(_mode) :path(_path), mode(_mode)
...@@ -212,10 +213,9 @@ FileOutputStream::Commit() ...@@ -212,10 +213,9 @@ FileOutputStream::Commit()
unlink(GetPath().c_str()); unlink(GetPath().c_str());
/* hard-link the temporary file to the final path */ /* hard-link the temporary file to the final path */
char fd_path[64]; if (linkat(AT_FDCWD,
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d", StringFormat<64>("/proc/self/fd/%d", fd.Get()),
fd.Get()); AT_FDCWD, path.c_str(),
if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(),
AT_SYMLINK_FOLLOW) < 0) AT_SYMLINK_FOLLOW) < 0)
throw FormatErrno("Failed to commit %s", throw FormatErrno("Failed to commit %s",
path.c_str()); path.c_str());
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "IOThread.hxx" #include "IOThread.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/StringUtil.hxx" #include "util/StringUtil.hxx"
#include "util/StringFormat.hxx"
#include "util/NumberParser.hxx" #include "util/NumberParser.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
...@@ -373,13 +374,10 @@ CurlInputStream::InitEasy() ...@@ -373,13 +374,10 @@ CurlInputStream::InitEasy()
if (proxy_port > 0) if (proxy_port > 0)
request->SetOption(CURLOPT_PROXYPORT, (long)proxy_port); request->SetOption(CURLOPT_PROXYPORT, (long)proxy_port);
if (proxy_user != nullptr && proxy_password != nullptr) { if (proxy_user != nullptr && proxy_password != nullptr)
char proxy_auth_str[1024]; request->SetOption(CURLOPT_PROXYUSERPWD,
snprintf(proxy_auth_str, sizeof(proxy_auth_str), StringFormat<1024>("%s:%s", proxy_user,
"%s:%s", proxy_password).c_str());
proxy_user, proxy_password);
request->SetOption(CURLOPT_PROXYUSERPWD, proxy_auth_str);
}
request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l); request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l);
request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l); request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l);
...@@ -416,11 +414,10 @@ CurlInputStream::SeekInternal(offset_type new_offset) ...@@ -416,11 +414,10 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */ /* send the "Range" header */
if (offset > 0) { if (offset > 0)
char range[32]; request->SetOption(CURLOPT_RANGE,
sprintf(range, "%" PRIoffset "-", offset); StringFormat<40>("%" PRIoffset "-",
request->SetOption(CURLOPT_RANGE, range); offset).c_str());
}
StartRequest(); StartRequest();
} }
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "Domain.hxx" #include "Domain.hxx"
#include "LogV.hxx" #include "LogV.hxx"
#include "util/Domain.hxx" #include "util/Domain.hxx"
#include "util/StringFormat.hxx"
extern "C" { extern "C" {
#include <libavutil/log.h> #include <libavutil/log.h>
...@@ -57,9 +58,10 @@ FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl) ...@@ -57,9 +58,10 @@ FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl)
cls = *(const AVClass *const*)ptr; cls = *(const AVClass *const*)ptr;
if (cls != nullptr) { if (cls != nullptr) {
char domain[64]; const auto domain =
snprintf(domain, sizeof(domain), "%s/%s", StringFormat<64>("%s/%s",
ffmpeg_domain.GetName(), cls->item_name(ptr)); ffmpeg_domain.GetName(),
cls->item_name(ptr));
const Domain d(domain); const Domain d(domain);
LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl); LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl);
} }
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "config/ConfigGlobal.hxx" #include "config/ConfigGlobal.hxx"
#include "config/Block.hxx" #include "config/Block.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "util/StringFormat.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept> #include <stdexcept>
......
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
#ifndef MPD_ACK_H #ifndef MPD_ACK_H
#define MPD_ACK_H #define MPD_ACK_H
#include <stdexcept> #include "util/StringFormat.hxx"
#include <stdio.h> #include <stdexcept>
class Domain; class Domain;
...@@ -60,9 +60,9 @@ template<typename... Args> ...@@ -60,9 +60,9 @@ template<typename... Args>
static inline ProtocolError static inline ProtocolError
FormatProtocolError(enum ack code, const char *fmt, Args&&... args) noexcept FormatProtocolError(enum ack code, const char *fmt, Args&&... args) noexcept
{ {
char buffer[256]; return ProtocolError(code,
snprintf(buffer, sizeof(buffer), fmt, std::forward<Args>(args)...); StringFormat<256>(fmt,
return ProtocolError(code, buffer); std::forward<Args>(args)...));
} }
#endif #endif
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "thread/Cond.hxx" #include "thread/Cond.hxx"
#include "util/RuntimeError.hxx" #include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx" #include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
#include "util/TimeParser.hxx" #include "util/TimeParser.hxx"
#include "util/UriUtil.hxx" #include "util/UriUtil.hxx"
...@@ -296,9 +297,7 @@ public: ...@@ -296,9 +297,7 @@ public:
{ {
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND"); request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
char buffer[40]; request_headers.Append(StringFormat<40>("depth: %u", depth));
sprintf(buffer, "depth: %u", depth);
request_headers.Append(buffer);
request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get()); request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include "TagHandler.hxx" #include "TagHandler.hxx"
#include "TagBuilder.hxx" #include "TagBuilder.hxx"
#include "util/ASCII.hxx" #include "util/ASCII.hxx"
#include "util/StringFormat.hxx"
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
static void static void
...@@ -42,11 +42,8 @@ add_tag_tag(TagType type, const char *value, void *ctx) ...@@ -42,11 +42,8 @@ add_tag_tag(TagType type, const char *value, void *ctx)
/* filter out this extra data and leading zeroes */ /* filter out this extra data and leading zeroes */
char *end; char *end;
unsigned n = strtoul(value, &end, 10); unsigned n = strtoul(value, &end, 10);
if (value != end) { if (value != end)
char s[21]; tag.AddItem(type, StringFormat<21>("%u", n));
if (snprintf(s, 21, "%u", n) > 0)
tag.AddItem(type, s);
}
} else } else
tag.AddItem(type, value); tag.AddItem(type, value);
} }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#endif #endif
#ifdef HAVE_THREAD_NAME #ifdef HAVE_THREAD_NAME
# include <stdio.h> #include "util/StringFormat.hxx"
#endif #endif
static inline void static inline void
...@@ -59,9 +59,7 @@ static inline void ...@@ -59,9 +59,7 @@ static inline void
FormatThreadName(const char *fmt, gcc_unused Args&&... args) FormatThreadName(const char *fmt, gcc_unused Args&&... args)
{ {
#ifdef HAVE_THREAD_NAME #ifdef HAVE_THREAD_NAME
char buffer[16]; SetThreadName(StringFormat<16>(fmt, args...));
snprintf(buffer, sizeof(buffer), fmt, args...);
SetThreadName(buffer);
#else #else
(void)fmt; (void)fmt;
#endif #endif
......
/*
* Copyright (C) 2010-2015 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef STRING_FORMAT_HXX
#define STRING_FORMAT_HXX
#include "StringBuffer.hxx"
#include <stdio.h>
template<typename... Args>
static inline void
StringFormat(char *buffer, size_t size,
const char *fmt, Args&&... args) noexcept
{
snprintf(buffer, size, fmt, args...);
}
template<size_t CAPACITY, typename... Args>
static inline void
StringFormat(StringBuffer<CAPACITY> &buffer,
const char *fmt, Args&&... args) noexcept
{
StringFormat(buffer.data(), buffer.capacity(), fmt, args...);
}
template<size_t CAPACITY, typename... Args>
static inline StringBuffer<CAPACITY>
StringFormat(const char *fmt, Args&&... args) noexcept
{
StringBuffer<CAPACITY> result;
StringFormat(result, fmt, args...);
return result;
}
template<typename... Args>
static inline void
StringFormatUnsafe(char *buffer, const char *fmt, Args&&... args) noexcept
{
sprintf(buffer, fmt, args...);
}
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment