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

util/StringFormat: new utility library

parent 41cdc4e1
......@@ -444,6 +444,7 @@ libutil_a_SOURCES = \
src/util/NumberParser.hxx \
src/util/MimeType.cxx src/util/MimeType.hxx \
src/util/StringBuffer.hxx \
src/util/StringFormat.hxx \
src/util/StringPointer.hxx \
src/util/StringView.cxx src/util/StringView.hxx \
src/util/AllocatedString.cxx src/util/AllocatedString.hxx \
......
......@@ -19,9 +19,9 @@
#include "AudioFormat.hxx"
#include "util/StringBuffer.hxx"
#include "util/StringFormat.hxx"
#include <assert.h>
#include <stdio.h>
void
AudioFormat::ApplyMask(AudioFormat mask) noexcept
......@@ -44,21 +44,16 @@ AudioFormat::ApplyMask(AudioFormat mask) noexcept
StringBuffer<24>
ToString(const AudioFormat af) noexcept
{
StringBuffer<24> buffer;
if (af.format == SampleFormat::DSD && af.sample_rate > 0 &&
af.sample_rate % 44100 == 0) {
/* use shortcuts such as "dsd64" which implies the
sample rate */
snprintf(buffer.data(), buffer.capacity(), "dsd%u:%u",
return StringFormat<24>("dsd%u:%u",
af.sample_rate * 8 / 44100,
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.channels);
return buffer;
}
......@@ -27,6 +27,7 @@
#include "util/UriUtil.hxx"
#include "util/RuntimeError.hxx"
#include "util/ScopeExit.hxx"
#include "util/StringFormat.hxx"
#include <stdio.h>
......@@ -47,10 +48,6 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
unsigned &didreadp,
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
IXML_Document *request =
MakeActionHelper("Browse", m_serviceType.c_str(),
......@@ -58,8 +55,10 @@ ContentDirectoryService::readDirSlice(UpnpClient_Handle hdl,
"BrowseFlag", "BrowseDirectChildren",
"Filter", "*",
"SortCriteria", "",
"StartingIndex", ofbuf,
"RequestedCount", cntbuf);
"StartingIndex",
StringFormat<32>("%u", offset).c_str(),
"RequestedCount",
StringFormat<32>("%u", count).c_str());
if (request == nullptr)
throw std::runtime_error("UpnpMakeAction() failed");
......@@ -112,15 +111,13 @@ ContentDirectoryService::search(UpnpClient_Handle hdl,
unsigned offset = 0, total = -1, count;
do {
char ofbuf[100];
sprintf(ofbuf, "%d", offset);
UniqueIxmlDocument request(MakeActionHelper("Search", m_serviceType.c_str(),
"ContainerID", objectId,
"SearchCriteria", ss,
"Filter", "*",
"SortCriteria", "",
"StartingIndex", ofbuf,
"StartingIndex",
StringFormat<32>("%u", offset).c_str(),
"RequestedCount", "0")); // Setting a value here gets twonky into fits
if (!request)
throw std::runtime_error("UpnpMakeAction() failed");
......
......@@ -28,7 +28,7 @@
#include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx"
#include "util/ScopeExit.hxx"
#include "util/FormatString.hxx"
#include "util/StringFormat.hxx"
#include "util/UriUtil.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
......@@ -38,7 +38,6 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define SUBTUNE_PREFIX "tune_"
......@@ -191,18 +190,15 @@ ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
tag_handler_invoke_duration(handler, handler_ctx,
SongTime::FromMS(info.play_length));
if (track_count > 1) {
char track[16];
sprintf(track, "%u", song_num + 1);
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
}
if (track_count > 1)
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
StringFormat<16>("%u", song_num + 1));
if (info.song != nullptr) {
if (track_count > 1) {
/* start numbering subtunes from 1 */
char tag_title[1024];
snprintf(tag_title, sizeof(tag_title),
"%s (%u/%d)",
const auto tag_title =
StringFormat<1024>("%s (%u/%d)",
info.song, song_num + 1,
track_count);
tag_handler_invoke_tag(handler, handler_ctx,
......@@ -297,9 +293,9 @@ gme_container_scan(Path path_fs)
ScanMusicEmu(emu, i,
add_tag_handler, &tag_builder);
char track_name[64];
snprintf(track_name, sizeof(track_name),
SUBTUNE_PREFIX "%03u.%s", i+1, subtune_suffix);
const auto track_name =
StringFormat<64>(SUBTUNE_PREFIX "%03u.%s", i+1,
subtune_suffix);
tail = list.emplace_after(tail, track_name,
tag_builder.Commit());
}
......
......@@ -26,7 +26,7 @@
#include "fs/Path.hxx"
#include "fs/AllocatedPath.hxx"
#include "util/Macros.hxx"
#include "util/FormatString.hxx"
#include "util/StringFormat.hxx"
#include "util/Domain.hxx"
#include "system/ByteOrder.hxx"
#include "Log.hxx"
......@@ -413,9 +413,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
title = "";
if (n_tracks > 1) {
char tag_title[1024];
snprintf(tag_title, sizeof(tag_title),
"%s (%u/%u)",
const auto tag_title =
StringFormat<1024>("%s (%u/%u)",
title, track, n_tracks);
tag_handler_invoke_tag(handler, handler_ctx,
TAG_TITLE, tag_title);
......@@ -435,9 +434,8 @@ ScanSidTuneInfo(const SidTuneInfo &info, unsigned track, unsigned n_tracks,
date);
/* track */
char track_buffer[16];
sprintf(track_buffer, "%d", track);
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track_buffer);
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK,
StringFormat<16>("%u", track));
}
static bool
......
......@@ -20,6 +20,7 @@
#include "config.h"
#include "FileOutputStream.hxx"
#include "system/Error.hxx"
#include "util/StringFormat.hxx"
FileOutputStream::FileOutputStream(Path _path, Mode _mode)
:path(_path), mode(_mode)
......@@ -212,10 +213,9 @@ FileOutputStream::Commit()
unlink(GetPath().c_str());
/* hard-link the temporary file to the final path */
char fd_path[64];
snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d",
fd.Get());
if (linkat(AT_FDCWD, fd_path, AT_FDCWD, path.c_str(),
if (linkat(AT_FDCWD,
StringFormat<64>("/proc/self/fd/%d", fd.Get()),
AT_FDCWD, path.c_str(),
AT_SYMLINK_FOLLOW) < 0)
throw FormatErrno("Failed to commit %s",
path.c_str());
......
......@@ -34,6 +34,7 @@
#include "IOThread.hxx"
#include "util/ASCII.hxx"
#include "util/StringUtil.hxx"
#include "util/StringFormat.hxx"
#include "util/NumberParser.hxx"
#include "util/RuntimeError.hxx"
#include "util/Domain.hxx"
......@@ -373,13 +374,10 @@ CurlInputStream::InitEasy()
if (proxy_port > 0)
request->SetOption(CURLOPT_PROXYPORT, (long)proxy_port);
if (proxy_user != nullptr && proxy_password != nullptr) {
char proxy_auth_str[1024];
snprintf(proxy_auth_str, sizeof(proxy_auth_str),
"%s:%s",
proxy_user, proxy_password);
request->SetOption(CURLOPT_PROXYUSERPWD, proxy_auth_str);
}
if (proxy_user != nullptr && proxy_password != nullptr)
request->SetOption(CURLOPT_PROXYUSERPWD,
StringFormat<1024>("%s:%s", proxy_user,
proxy_password).c_str());
request->SetOption(CURLOPT_SSL_VERIFYPEER, verify_peer ? 1l : 0l);
request->SetOption(CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l);
......@@ -416,11 +414,10 @@ CurlInputStream::SeekInternal(offset_type new_offset)
/* send the "Range" header */
if (offset > 0) {
char range[32];
sprintf(range, "%" PRIoffset "-", offset);
request->SetOption(CURLOPT_RANGE, range);
}
if (offset > 0)
request->SetOption(CURLOPT_RANGE,
StringFormat<40>("%" PRIoffset "-",
offset).c_str());
StartRequest();
}
......
......@@ -25,6 +25,7 @@
#include "Domain.hxx"
#include "LogV.hxx"
#include "util/Domain.hxx"
#include "util/StringFormat.hxx"
extern "C" {
#include <libavutil/log.h>
......@@ -57,9 +58,10 @@ FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl)
cls = *(const AVClass *const*)ptr;
if (cls != nullptr) {
char domain[64];
snprintf(domain, sizeof(domain), "%s/%s",
ffmpeg_domain.GetName(), cls->item_name(ptr));
const auto domain =
StringFormat<64>("%s/%s",
ffmpeg_domain.GetName(),
cls->item_name(ptr));
const Domain d(domain);
LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl);
}
......
......@@ -37,6 +37,7 @@
#include "config/ConfigGlobal.hxx"
#include "config/Block.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringFormat.hxx"
#include "Log.hxx"
#include <stdexcept>
......
......@@ -20,9 +20,9 @@
#ifndef MPD_ACK_H
#define MPD_ACK_H
#include <stdexcept>
#include "util/StringFormat.hxx"
#include <stdio.h>
#include <stdexcept>
class Domain;
......@@ -60,9 +60,9 @@ template<typename... Args>
static inline ProtocolError
FormatProtocolError(enum ack code, const char *fmt, Args&&... args) noexcept
{
char buffer[256];
snprintf(buffer, sizeof(buffer), fmt, std::forward<Args>(args)...);
return ProtocolError(code, buffer);
return ProtocolError(code,
StringFormat<256>(fmt,
std::forward<Args>(args)...));
}
#endif
......@@ -35,6 +35,7 @@
#include "thread/Cond.hxx"
#include "util/RuntimeError.hxx"
#include "util/StringCompare.hxx"
#include "util/StringFormat.hxx"
#include "util/TimeParser.hxx"
#include "util/UriUtil.hxx"
......@@ -296,9 +297,7 @@ public:
{
request.SetOption(CURLOPT_CUSTOMREQUEST, "PROPFIND");
char buffer[40];
sprintf(buffer, "depth: %u", depth);
request_headers.Append(buffer);
request_headers.Append(StringFormat<40>("depth: %u", depth));
request.SetOption(CURLOPT_HTTPHEADER, request_headers.Get());
......
......@@ -21,8 +21,8 @@
#include "TagHandler.hxx"
#include "TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/StringFormat.hxx"
#include <stdio.h>
#include <stdlib.h>
static void
......@@ -42,11 +42,8 @@ add_tag_tag(TagType type, const char *value, void *ctx)
/* filter out this extra data and leading zeroes */
char *end;
unsigned n = strtoul(value, &end, 10);
if (value != end) {
char s[21];
if (snprintf(s, 21, "%u", n) > 0)
tag.AddItem(type, s);
}
if (value != end)
tag.AddItem(type, StringFormat<21>("%u", n));
} else
tag.AddItem(type, value);
}
......
......@@ -31,7 +31,7 @@
#endif
#ifdef HAVE_THREAD_NAME
# include <stdio.h>
#include "util/StringFormat.hxx"
#endif
static inline void
......@@ -59,9 +59,7 @@ static inline void
FormatThreadName(const char *fmt, gcc_unused Args&&... args)
{
#ifdef HAVE_THREAD_NAME
char buffer[16];
snprintf(buffer, sizeof(buffer), fmt, args...);
SetThreadName(buffer);
SetThreadName(StringFormat<16>(fmt, args...));
#else
(void)fmt;
#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