Compare commits

...

58 Commits

Author SHA1 Message Date
Max Kellermann
df4b6b92f2 release v0.23.5 2021-12-01 20:00:00 +01:00
Max Kellermann
1c69913eca decoder/flac: submit MixRamp only if there is actual data 2021-12-01 17:58:51 +01:00
Max Kellermann
cb5c6259fd decoder/mad: submit MixRamp only if there is actual data
Fixes MixRamp failures when a MP3 file has two ID3 tags, one of them
without MixRamp.
2021-12-01 17:19:53 +01:00
Max Kellermann
bf287fefb5 decoder/mad: move parse_id3_mixramp() to tag/Id3MixRamp.cxx 2021-12-01 17:11:36 +01:00
Max Kellermann
20bf1d68e6 MixRampInfo: move to tag/ 2021-12-01 17:09:02 +01:00
Max Kellermann
9bc4c168fd tag/MixRamp: rename to MixRampParser.cxx 2021-12-01 17:07:53 +01:00
Max Kellermann
3415049d1c test/tag/TestMixRampParser: include the header, not the .cxx file 2021-12-01 17:07:39 +01:00
Max Kellermann
a45949b597 tag/MixRamp: [[gnu::...]] attributes 2021-12-01 15:48:33 +01:00
Max Kellermann
6009d4abab tag/MixRamp: use std::string_view 2021-12-01 15:47:54 +01:00
Max Kellermann
16fb843c9b tag/MixRamp: fix typo which broken MixRamp
Fixes regression by commit 8e0d810968 which is 2 years old, and nobody
noticed.  D'oh, how embarassing!
2021-12-01 15:46:31 +01:00
Max Kellermann
36b333459b test/tag/TestMixRampParser: new unit test 2021-12-01 15:46:01 +01:00
Max Kellermann
4d3320233e test/test_mixramp: move to test/tag/ 2021-12-01 15:33:17 +01:00
Max Kellermann
933a1a41e6 lib/upnp/Discovery: use InjectEvent instead of DeferEvent
Fixes regression by commit 774b4313f2
2021-11-30 18:03:27 +01:00
August2111
1ff8626716 MSVC util/StringAPI.hxx add usage of MSVC compiler 2021-11-26 17:30:17 +01:00
Max Kellermann
c30466b84a net/IPv4Address: add method GetPortBE() 2021-11-26 16:25:43 +01:00
Max Kellermann
868f1a4431 net/UniqueSocketDescriptor, ...: include <utility> instead of <algorithm>
Since C++11, std::swap() lives in <utility>.
2021-11-26 16:25:29 +01:00
Max Kellermann
05f529fffd util/StringStrip: use [[gnu::...]] attributes 2021-11-26 16:24:55 +01:00
Max Kellermann
f01388559f .github/workflows/build.yml: fix the ccache.key 2021-11-26 13:32:48 +01:00
Max Kellermann
27edd4a610 .github/workflows: merge build-{linux,macos}.yml into one 2021-11-26 13:32:08 +01:00
Max Kellermann
cc421b04cd test/meson.build: add "protocol:gtest" where appropriate 2021-11-26 08:47:06 +01:00
Max Kellermann
3f2bc325a1 test/meson.build: fix test() indent 2021-11-26 08:40:40 +01:00
Max Kellermann
54686dfd79 test/meson.build: add dependencies on run_input
Fixes spurious unit test failures because run_input has not yet been
built.
2021-11-26 08:35:49 +01:00
Rosen Penev
f22cf02ed8 fix wrong namespace name
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-26 08:08:45 +01:00
Rosen Penev
5b51d0f733 use some auto
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-26 08:08:45 +01:00
Rosen Penev
e03f82636a const reference conversion
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 12:33:03 -08:00
Rosen Penev
d53d85bd79 remove unused includes
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 12:33:03 -08:00
Max Kellermann
4682ae0898 command/database: support relative offsets for "searchadd"
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1337
2021-11-23 12:17:32 +01:00
Max Kellermann
fd5b195879 .github/workflows/build-macos.yml: use actions/setup-python@v1
Without it, BSFishy/meson-build defaults to /usr/local/bin/python,
which is Python 2.
2021-11-23 12:17:32 +01:00
Max Kellermann
bb5df9839d .github/workflows/build-macos.yml: install Meson, ninja and Boost 2021-11-23 12:17:32 +01:00
Max Kellermann
be34d55291 .github/workflows: add macOS build 2021-11-23 11:41:40 +01:00
Max Kellermann
c13911b171 .github/workflows: auto-build with GitHub Actions 2021-11-23 10:45:14 +01:00
Max Kellermann
6f83bdd6f3 Merge branch '1' of git://github.com/neheb/MPD 2021-11-23 10:39:07 +01:00
Rosen Penev
9bcd425a85 array conversions
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-23 01:38:10 -08:00
Max Kellermann
ec917f70d2 Merge remote-tracking branches 'neheb/2' and 'neheb/3' 2021-11-23 09:23:43 +01:00
Rosen Penev
40ce4eeb43 use cinttypes header
stdint.h is deprecated.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:30:36 -08:00
Rosen Penev
29ae84e199 manual braced init
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:30:04 -08:00
Rosen Penev
250011f016 return by braced init list
shorter

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-22 23:28:08 -08:00
Max Kellermann
e08c85ae2d doc/mpd.conf.5.rst: move ReplayGain documentation to user.rst 2021-11-22 22:25:04 +01:00
Max Kellermann
dcb5ca203c db/DatabasePlaylist: increment only one variable
Fixes "searchaddpl" bug emitting bogus error "Bad position".

Closes https://github.com/MusicPlayerDaemon/MPD/issues/1338
2021-11-22 20:47:34 +01:00
Max Kellermann
77df5a8f24 lib/pcre: migrate to PCRE2
Closes https://github.com/MusicPlayerDaemon/MPD/issues/1352
2021-11-22 19:32:45 +01:00
kaliko
d6bebd2507 doc/conf.py: Set sidebar width to 300px to limit wrapping
This enhances readability in sidebar, especially for "User’s Manual" and
"Protocol" pages
2021-11-20 10:49:15 +01:00
Max Kellermann
f74996c02f Merge remote-tracking branches 'neheb/1', 'neheb/2', 'neheb/3', 'neheb/4' and 'neheb/5' 2021-11-20 07:55:24 +01:00
Max Kellermann
eea2d35d3a util/AllocatedString, ...: add missing include for std::exchange()
Fixes building with GCC 12.
2021-11-19 16:06:20 +01:00
Max Kellermann
d94e8bd82d queue/IdTable: include cleanup 2021-11-19 16:03:09 +01:00
Max Kellermann
b0c92e1a34 queue/IdTable: lazy-initialize the "data" array
With large "max_playlist_length" settings, the "data" array can be
very large, and initializing it during MPD startup causes page faults,
resulting in allocation of physical RAM.  This commit postpones the
initialization until the queue is really large, to avoid wasting
memory.
2021-11-19 16:00:39 +01:00
Max Kellermann
ead5bcf048 queue/IdTable: make size const 2021-11-19 15:51:10 +01:00
kaliko
bdd268a524 doc/user.rst: update build dependencies on Debian Bullseye 2021-11-19 11:04:47 +01:00
Shen-Ta Hsieh
e783c2bd2c util/LazyRandomEngine: use std::optional to avoid allocation
Signed-off-by: Shen-Ta Hsieh <ibmibmibm.tw@gmail.com>
2021-11-14 03:53:42 +08:00
Rosen Penev
837fc98638 use const references
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:18:33 -08:00
Rosen Penev
5deca66fdc add various nodiscard
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:17:26 -08:00
Rosen Penev
cfe2dd4147 use nullptr
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:16:19 -08:00
Rosen Penev
00f8d65a17 remove std::move
clang-tidy reports this is trivially copyable and thus std::move has no
effect.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:15:21 -08:00
Rosen Penev
4e0e4c00bf treewide: replace lock_guard with scoped_lock
SonarLint reports the latter to be better:

std::scoped_lock basically provides the same feature as std::lock_guard,
but is more generic: It can lock several mutexes at the same time, with a
deadlock prevention mechanism (see {rule:cpp:S5524}). The equivalent code
to perform simultaneous locking with std::lock_guard is significantly more
complex. Therefore, it is simpler to use std::scoped_lock all the time,
even when locking only one mutex (there will be no performance impact).

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 17:13:03 -08:00
Max Kellermann
a8c77a6fba Merge branch '1' of git://github.com/neheb/MPD 2021-11-11 10:33:17 +01:00
Rosen Penev
31aa6d0c4f use auto with make_unique
C arrays can be used with make_unique in C++17.

Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 01:33:03 -08:00
Max Kellermann
d051c4931d Merge branch '2' of git://github.com/neheb/MPD 2021-11-11 10:32:45 +01:00
Rosen Penev
94b0baceb0 convert address_family_ranking to std::array
Signed-off-by: Rosen Penev <rosenp@gmail.com>
2021-11-11 01:27:31 -08:00
Max Kellermann
16feb261e2 increment version number to 0.23.5 2021-11-11 10:18:19 +01:00
161 changed files with 1213 additions and 586 deletions
.github/workflows
NEWS
android
doc
meson.build
src
LogBackend.cxxMapper.cxxMusicBuffer.cxxMusicBuffer.hxxMusicPipe.cxxMusicPipe.hxxRemoteTagCache.cxx
archive
client
command
db
decoder
event
filter
fs
input
lib
mixer
neighbor
net
output
pcm
player
playlist
protocol
queue
song
sticker
storage
tag
thread
util
test

132
.github/workflows/build.yml vendored Normal file

@@ -0,0 +1,132 @@
---
on:
workflow_dispatch:
push:
paths-ignore:
- 'android/**'
- 'build/**'
- 'doc/**'
- 'python/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
- actions
pull_request:
paths-ignore:
- 'android/**'
- 'build/**'
- 'doc/**'
- 'python/**'
- 'subprojects/**'
- 'systemd/**'
- 'win32/**'
branches:
- master
jobs:
build-linux:
runs-on: ubuntu-latest
env:
CC: 'ccache gcc-10'
CXX: 'ccache g++-10'
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: linux
- name: Install dependencies
run: |
sudo apt install -y --no-install-recommends \
g++-10 libfmt-dev libboost-dev \
libgtest-dev \
libpcre2-dev \
libsystemd-dev libdbus-1-dev \
libicu-dev \
libcurl4-gnutls-dev \
libpcre2-dev \
libavahi-client-dev \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev libogg-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
libfluidsynth-dev libgme-dev libmikmod-dev libmodplug-dev \
libmpcdec-dev libwavpack-dev libwildmidi-dev \
libsidplay2-dev libsidutils-dev libresid-builder-dev \
libavcodec-dev libavformat-dev \
libmp3lame-dev libtwolame-dev libshine-dev \
libsamplerate0-dev libsoxr-dev \
libbz2-dev libcdio-paranoia-dev libiso9660-dev libmms-dev \
libzzip-dev \
libyajl-dev libexpat-dev \
libasound2-dev libao-dev libjack-jackd2-dev libopenal-dev \
libpulse-dev libshout3-dev \
libsndio-dev \
libmpdclient-dev \
libnfs-dev \
libupnp-dev \
libsqlite3-dev \
libchromaprint-dev \
libgcrypt20-dev
- name: Full Build
uses: BSFishy/meson-build@v1.0.3
with:
action: test
directory: output/full
setup-options: -Ddocumentation=disabled -Dtest=true -Dsystemd=enabled -Dpcre=enabled
meson-version: 0.56.0
- name: Mini Build
uses: BSFishy/meson-build@v1.0.3
with:
action: test
directory: output/mini
setup-options: -Dbuildtype=minsize -Dauto_features=disabled -Dtest=true -Ddaemon=false -Dinotify=false -Depoll=false -Deventfd=false -Dsignalfd=false -Dtcp=false -Ddsd=false -Ddatabase=false -Dneighbor=false -Dcue=false -Dfifo=false -Dhttpd=false -Dpipe=false -Drecorder=false -Dsnapcast=false
meson-version: 0.56.0
build-macos:
runs-on: macos-latest
steps:
- id: checkout
uses: actions/checkout@v2
- id: cache-ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: macos
- uses: actions/setup-python@v1
- name: Install dependencies
run: |
brew install \
meson ninja \
fmt \
boost \
googletest \
icu4c \
ffmpeg \
libnfs \
yajl \
libupnp \
libid3tag \
chromaprint \
libsamplerate \
libsoxr \
flac \
opus \
libvorbis \
faad2 \
wavpack \
libmpdclient
- name: Meson Build
uses: BSFishy/meson-build@v1.0.3
with:
action: test
directory: output
setup-options: -Ddocumentation=disabled -Dtest=true
meson-version: 0.56.0

11
NEWS

@@ -1,3 +1,14 @@
ver 0.23.5 (2021/12/01)
* protocol
- support relative offsets for "searchadd"
- fix "searchaddpl" bug (bogus error "Bad position")
* database
- upnp: fix crash bug
* tags
- fix MixRamp support
* migrate to PCRE2
* GCC 12 build fixes
ver 0.23.4 (2021/11/11)
* protocol
- add optional position parameter to "searchaddpl"

@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.musicpd"
android:installLocation="auto"
android:versionCode="64"
android:versionName="0.23.4">
android:versionCode="65"
android:versionName="0.23.5">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>

@@ -38,7 +38,7 @@ author = 'Max Kellermann'
# built documents.
#
# The short X.Y version.
version = '0.23.4'
version = '0.23.5'
# The full version, including alpha/beta/rc tags.
#release = version + '~git'
@@ -107,6 +107,7 @@ html_theme = 'classic'
# documentation.
#
# html_theme_options = {}
html_theme_options = {"sidebarwidth": "300px"}
# Add any paths that contain custom themes here, relative to this directory.
# html_theme_path = []

@@ -128,23 +128,6 @@ audio_output
no audio_output section is specified, then MPD will scan for a usable audio
output.
replaygain <off or album or track or auto>
If specified, mpd will adjust the volume of songs played using ReplayGain
tags (see https://wiki.hydrogenaud.io/index.php?title=Replaygain).
Setting this to "album" will
adjust volume using the album's ReplayGain tags, while setting it to "track"
will adjust it using the track ReplayGain tags. "auto" uses the track
ReplayGain tags if random play is activated otherwise the album ReplayGain
tags. Currently only FLAC, Ogg Vorbis, Musepack, and MP3 (through ID3v2
ReplayGain tags, not APEv2) are supported.
replaygain_preamp <-15 to 15>
This is the gain (in dB) applied to songs with ReplayGain tags.
volume_normalization <yes or no>
If yes, mpd will normalize the volume of songs as they play. The default is
no.
filesystem_charset <charset>
This specifies the character set used for the filesystem. A list of supported
character sets can be obtained by running "iconv -l". The default is

@@ -1222,6 +1222,8 @@ The music database
The ``position`` parameter specifies where the songs will be
inserted. [#since_0_23]_
It can be relative to the current song as in :ref:`addid
<command_addid>`. [#since_0_23_5]_
.. _command_searchaddpl:
@@ -1659,3 +1661,4 @@ client-to-client messages are local to the current partition.
.. [#since_0_23_1] Since :program:`MPD` 0.23.1
.. [#since_0_23_3] Since :program:`MPD` 0.23.3
.. [#since_0_23_4] Since :program:`MPD` 0.23.4
.. [#since_0_23_5] Since :program:`MPD` 0.23.5

@@ -64,13 +64,13 @@ In any case, you need:
Each plugin usually needs a codec library, which you also need to
install. Check the :doc:`plugins` for details about required libraries
For example, the following installs a fairly complete list of build dependencies on Debian Buster:
For example, the following installs a fairly complete list of build dependencies on Debian Bullseye:
.. code-block:: none
apt install meson g++ \
libfmt-dev \
libpcre3-dev \
libpcre2-dev \
libmad0-dev libmpg123-dev libid3tag0-dev \
libflac-dev libvorbis-dev libopus-dev libogg-dev \
libadplug-dev libaudiofile-dev libsndfile1-dev libfaad-dev \
@@ -465,6 +465,11 @@ The following table lists the audio_output options valid for all plugins:
implement an external mixer, see :ref:`external_mixer`) or no mixer
(:samp:`none`). By default, the hardware mixer is used for
devices which support it, and none for the others.
* - **replay_gain_handler software|mixer|none**
- Specifies how :ref:`replay_gain` is applied. The default is
``software``, which uses an internal software volume control.
``mixer`` uses the configured (hardware) mixer control.
``none`` disables replay gain on this audio output.
* - **filters "name,...**"
- The specified configured filters are instantiated in the given
order. Each filter name refers to a ``filter`` block, see
@@ -583,6 +588,40 @@ Sometimes, music needs to be resampled before it can be played; for example, CDs
Check the :ref:`resampler_plugins` reference for a list of resamplers
and how to configure them.
Volume Normalization Settings
-----------------------------
.. _replay_gain:
Replay Gain
^^^^^^^^^^^
The setting ``replaygain`` specifies whether MPD shall adjust the
volume of songs played using `ReplayGain
<https://wiki.hydrogenaud.io/index.php?title=Replaygain>`__ tags.
Setting this to ``album`` will adjust volume using the album's
ReplayGain tags, while setting it to ``track`` will adjust it using
the "track" ReplayGain tags. ``auto`` uses the track ReplayGain tags
if random play is activated otherwise the album ReplayGain
tags.
If ReplayGain is enabled, then the setting ``replaygain_preamp`` is
set to a value (in dB) between ``-15`` and ``15``. This is the gain
applied to songs with ReplayGain tags.
ReplayGain is usually implemented with a software volume filter (which
prevents `Bit-perfect playback`_). To use a hardware mixer, set
``replay_gain_handler`` to ``mixer`` in the ``audio_output`` section
(see :ref:`config_audio_output` for details).
Simple Volume Normalization
^^^^^^^^^^^^^^^^^^^^^^^^^^^
MPD implements a very simple volume normalization method which can be
enabled by setting ``volume_normalization`` to ``yes``. It supports
16 bit PCM only.
Client Connections
------------------
@@ -1076,6 +1115,7 @@ Check list for bit-perfect playback:
* Disable sound processing inside ALSA by configuring a "hardware"
device (:samp:`hw:0,0` or similar).
* Don't use software volume (setting :code:`mixer_type`).
* Don't use :ref:`replay_gain`.
* Don't force :program:`MPD` to use a specific audio format (settings
:code:`format`, :ref:`audio_output_format <audio_output_format>`).
* Verify that you are really doing bit-perfect playback using :program:`MPD`'s verbose log and :file:`/proc/asound/card*/pcm*p/sub*/hw_params`. Some DACs can also indicate the audio format.

@@ -1,7 +1,7 @@
project(
'mpd',
['c', 'cpp'],
version: '0.23.4',
version: '0.23.5',
meson_version: '>= 0.56.0',
default_options: [
'c_std=c11',
@@ -44,7 +44,7 @@ version_conf = configuration_data()
version_conf.set_quoted('PACKAGE', meson.project_name())
version_conf.set_quoted('PACKAGE_NAME', meson.project_name())
version_conf.set_quoted('VERSION', meson.project_version())
version_conf.set_quoted('PROTOCOL_VERSION', '0.23.4')
version_conf.set_quoted('PROTOCOL_VERSION', '0.23.5')
configure_file(output: 'Version.h', configuration: version_conf)
conf = configuration_data()

@@ -19,6 +19,7 @@
#include "LogBackend.hxx"
#include "Log.hxx"
#include "util/Compiler.h"
#include "util/Domain.hxx"
#include "util/StringStrip.hxx"
#include "Version.h"
@@ -110,7 +111,7 @@ chomp_length(std::string_view p) noexcept
#ifdef HAVE_SYSLOG
gcc_const
[[gnu::const]]
static int
ToSysLogLevel(LogLevel log_level) noexcept
{

@@ -85,15 +85,15 @@ map_fs_to_utf8(Path path_fs) noexcept
{
if (path_fs.IsAbsolute()) {
if (global_instance->storage == nullptr)
return std::string();
return {};
const auto music_dir_fs = global_instance->storage->MapFS("");
if (music_dir_fs.IsNull())
return std::string();
return {};
auto relative = music_dir_fs.Relative(path_fs);
if (relative == nullptr || StringIsEmpty(relative))
return std::string();
return {};
path_fs = Path::FromFS(relative);
}

@@ -29,8 +29,8 @@ MusicBuffer::MusicBuffer(unsigned num_chunks)
MusicChunkPtr
MusicBuffer::Allocate() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
return MusicChunkPtr(buffer.Allocate(), MusicChunkDeleter(*this));
const std::scoped_lock<Mutex> protect(mutex);
return {buffer.Allocate(), MusicChunkDeleter(*this)};
}
void
@@ -44,7 +44,7 @@ MusicBuffer::Return(MusicChunk *chunk) noexcept
chunk->next.reset();
chunk->other.reset();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(!chunk->other || !chunk->other->other);

@@ -54,7 +54,7 @@ public:
#endif
bool IsFull() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return buffer.IsFull();
}

@@ -27,7 +27,7 @@
bool
MusicPipe::Contains(const MusicChunk *chunk) const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
for (const MusicChunk *i = head.get(); i != nullptr; i = i->next.get())
if (i == chunk)
@@ -41,7 +41,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const noexcept
MusicChunkPtr
MusicPipe::Shift() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
auto chunk = std::move(head);
if (chunk != nullptr) {
@@ -81,7 +81,7 @@ MusicPipe::Push(MusicChunkPtr chunk) noexcept
assert(!chunk->IsEmpty());
assert(chunk->length == 0 || chunk->audio_format.IsValid());
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(size > 0 || !audio_format.IsDefined());
assert(!audio_format.IsDefined() ||

@@ -77,7 +77,7 @@ public:
*/
[[gnu::pure]]
const MusicChunk *Peek() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return head.get();
}
@@ -101,7 +101,7 @@ public:
*/
[[gnu::pure]]
unsigned GetSize() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return size;
}

@@ -98,7 +98,7 @@ RemoteTagCache::ItemResolved(Item &item) noexcept
void
RemoteTagCache::InvokeHandlers() noexcept
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
while (!invoke_list.empty()) {
auto &item = invoke_list.front();
@@ -125,7 +125,7 @@ RemoteTagCache::Item::OnRemoteTag(Tag &&_tag) noexcept
scanner.reset();
const std::lock_guard<Mutex> lock(parent.mutex);
const std::scoped_lock<Mutex> lock(parent.mutex);
parent.ItemResolved(*this);
}
@@ -137,6 +137,6 @@ RemoteTagCache::Item::OnRemoteTagError(std::exception_ptr e) noexcept
scanner.reset();
const std::lock_guard<Mutex> lock(parent.mutex);
const std::scoped_lock<Mutex> lock(parent.mutex);
parent.ItemResolved(*this);
}

@@ -26,7 +26,6 @@
#include "plugins/ZzipArchivePlugin.hxx"
#include <cassert>
#include <iterator>
#include <string.h>

@@ -162,7 +162,7 @@ class Iso9660InputStream final : public InputStream {
std::array<uint8_t, ISO_BLOCKSIZE> data;
public:
ConstBuffer<uint8_t> Read() const noexcept {
[[nodiscard]] ConstBuffer<uint8_t> Read() const noexcept {
assert(fill <= data.size());
assert(position <= fill);

@@ -35,7 +35,7 @@
#include <utility>
#include <inttypes.h> /* for PRIoffset (PRIu64) */
#include <cinttypes> /* for PRIoffset (PRIu64) */
struct ZzipDir {
ZZIP_DIR *const dir;

@@ -80,7 +80,7 @@ Response::VFmtError(enum ack code,
Fmt(FMT_STRING("ACK [{}@{}] {{{}}} "),
(int)code, list_index, command);
VFmt(format_str, std::move(args));
VFmt(format_str, args);
Write("\n");
}

@@ -18,6 +18,7 @@
*/
#include "DatabaseCommands.hxx"
#include "PositionArg.hxx"
#include "Request.hxx"
#include "Partition.hxx"
#include "db/DatabaseQueue.hxx"
@@ -86,6 +87,20 @@ ParseQueuePosition(Request &args, unsigned queue_length)
return queue_length;
}
static unsigned
ParseInsertPosition(Request &args, const playlist &playlist)
{
if (args.size >= 2 && StringIsEqual(args[args.size - 2], "position")) {
unsigned position = ParseInsertPosition(args.back(), playlist);
args.pop_back();
args.pop_back();
return position;
}
/* append to the end of the queue by default */
return playlist.queue.GetLength();
}
/**
* Convert all remaining arguments to a #DatabaseSelection.
*
@@ -160,7 +175,8 @@ handle_match_add(Client &client, Request args, bool fold_case)
{
auto &partition = client.GetPartition();
const auto queue_length = partition.playlist.queue.GetLength();
const unsigned position = ParseQueuePosition(args, queue_length);
const unsigned position =
ParseInsertPosition(args, partition.playlist);
SongFilter filter;
const auto selection = ParseDatabaseSelection(args, fold_case, filter);

@@ -213,7 +213,7 @@ read_stream_art(Response &r, const std::string_view art_directory,
std::min<offset_type>(art_file_size - offset,
r.GetClient().binary_limit);
std::unique_ptr<std::byte[]> buffer(new std::byte[buffer_size]);
auto buffer = std::make_unique<std::byte[]>(buffer_size);
std::size_t read_size = 0;
if (buffer_size > 0) {

@@ -67,7 +67,7 @@ protected:
}
void CancelThread() noexcept override {
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
cancel = true;
cond.notify_one();
}
@@ -204,7 +204,7 @@ GetChromaprintCommand::DecodeFile(std::string_view suffix, InputStream &is,
return false;
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (cancel)
throw StopDecoder();
}

@@ -53,10 +53,9 @@ SearchInsertIntoPlaylist(const Database &db, const Storage *storage,
unsigned n = 0;
db.Visit(selection, [&playlist, &position, &n, storage](const auto &song){
db.Visit(selection, [&playlist, position, &n, storage](const auto &song){
playlist.Insert(position + n,
DatabaseDetachSong(storage, song));
++position;
++n;
});

@@ -35,6 +35,7 @@ db_plugins = static_library(
include_directories: inc,
dependencies: [
upnp_dep,
pcre_dep,
libmpdclient_dep,
log_dep,
],

@@ -278,5 +278,5 @@ Directory::Walk(bool recursive, const SongFilter *filter,
LightDirectory
Directory::Export() const noexcept
{
return LightDirectory(GetPath(), mtime);
return {GetPath(), mtime};
}

@@ -316,7 +316,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
if (r.rest.find('/') == std::string_view::npos) {
if (visit_song) {
Song *song = r.directory->FindSong(r.rest);
const Song *song = r.directory->FindSong(r.rest);
if (song != nullptr) {
const auto song2 = song->Export();
if (selection.Match(song2))

@@ -250,11 +250,11 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
{
const SongFilter *filter = selection.filter;
if (selection.filter == nullptr)
return UPnPDirContent();
return {};
const auto searchcaps = server.getSearchCapabilities(handle);
if (searchcaps.empty())
return UPnPDirContent();
return {};
std::string cond;
for (const auto &item : filter->GetItems()) {

@@ -33,7 +33,6 @@
#include "util/StringCompare.hxx"
#include "Log.hxx"
#include <string>
#include <exception>
#include <string.h>

@@ -34,7 +34,7 @@ UpdateQueueItem
UpdateQueue::Pop() noexcept
{
if (update_queue.empty())
return UpdateQueueItem();
return {};
auto i = std::move(update_queue.front());
update_queue.pop_front();

@@ -36,7 +36,7 @@ UpdateRemoveService::RunDeferred() noexcept
std::forward_list<std::string> copy;
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
std::swap(uris, copy);
}
@@ -55,7 +55,7 @@ UpdateRemoveService::Remove(std::string &&uri)
bool was_empty;
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
was_empty = uris.empty();
uris.emplace_front(std::move(uri));
}

@@ -84,7 +84,7 @@ try {
}
bool
directory_child_access(Storage &storage, const Directory &directory,
directory_child_access(const Storage &storage, const Directory &directory,
std::string_view name, int mode) noexcept
{
#ifdef _WIN32

@@ -55,7 +55,7 @@ directory_child_is_regular(Storage &storage, const Directory &directory,
*/
[[gnu::pure]]
bool
directory_child_access(Storage &storage, const Directory &directory,
directory_child_access(const Storage &storage, const Directory &directory,
std::string_view name, int mode) noexcept;
#endif

@@ -152,7 +152,7 @@ DecoderBridge::FlushChunk() noexcept
if (!chunk->IsEmpty())
dc.pipe->Push(std::move(chunk));
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
dc.client_cond.notify_one();
}
@@ -214,7 +214,7 @@ DecoderBridge::GetVirtualCommand() noexcept
DecoderCommand
DecoderBridge::LockGetVirtualCommand() noexcept
{
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
return GetVirtualCommand();
}
@@ -274,7 +274,7 @@ DecoderBridge::Ready(const AudioFormat audio_format,
seekable);
{
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
dc.SetReady(audio_format, seekable, duration);
}
@@ -300,7 +300,7 @@ DecoderBridge::GetCommand() noexcept
void
DecoderBridge::CommandFinished() noexcept
{
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
assert(dc.command != DecoderCommand::NONE || initial_seek_running);
assert(dc.command != DecoderCommand::SEEK ||

@@ -22,7 +22,7 @@
#include "Command.hxx"
#include "pcm/AudioFormat.hxx"
#include "MixRampInfo.hxx"
#include "tag/MixRampInfo.hxx"
#include "input/Handler.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
@@ -231,7 +231,7 @@ public:
[[gnu::pure]]
bool LockIsIdle() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return IsIdle();
}
@@ -241,7 +241,7 @@ public:
[[gnu::pure]]
bool LockIsStarting() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return IsStarting();
}
@@ -253,7 +253,7 @@ public:
[[gnu::pure]]
bool LockHasFailed() const noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return HasFailed();
}
@@ -284,7 +284,7 @@ public:
* Like CheckRethrowError(), but locks and unlocks the object.
*/
void LockCheckRethrowError() const {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
CheckRethrowError();
}
@@ -360,7 +360,7 @@ private:
}
void LockAsynchronousCommand(DecoderCommand cmd) noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
command = cmd;
Signal();
}

@@ -35,8 +35,8 @@
#include "DecoderPlugin.hxx"
#include "ReplayGainInfo.hxx"
#include "tag/Tag.hxx"
#include "tag/MixRampInfo.hxx"
#include "pcm/AudioFormat.hxx"
#include "MixRampInfo.hxx"
#include "config/Block.hxx"
#include "Chrono.hxx"

@@ -262,7 +262,7 @@ static void
MaybeLoadReplayGain(DecoderBridge &bridge, InputStream &is)
{
{
const std::lock_guard<Mutex> protect(bridge.dc.mutex);
const std::scoped_lock<Mutex> protect(bridge.dc.mutex);
if (bridge.dc.replay_gain_mode == ReplayGainMode::OFF)
/* ReplayGain is disabled */
return;
@@ -337,7 +337,7 @@ TryDecoderFile(DecoderBridge &bridge, Path path_fs, std::string_view suffix,
DecoderControl &dc = bridge.dc;
if (plugin.file_decode != nullptr) {
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
return decoder_file_decode(plugin, bridge, path_fs);
} else if (plugin.stream_decode != nullptr) {
std::unique_lock<Mutex> lock(dc.mutex);
@@ -365,7 +365,7 @@ TryContainerDecoder(DecoderBridge &bridge, Path path_fs,
bridge.Reset();
DecoderControl &dc = bridge.dc;
const std::lock_guard<Mutex> protect(dc.mutex);
const std::scoped_lock<Mutex> protect(dc.mutex);
return decoder_file_decode(plugin, bridge, path_fs);
}

@@ -83,8 +83,8 @@ audiofile_file_read(AFvirtualfile *vfile, void *data, size_t length) noexcept
static AFfileoffset
audiofile_file_length(AFvirtualfile *vfile) noexcept
{
AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
InputStream &is = afis.is;
const AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
const InputStream &is = afis.is;
return is.GetSize();
}
@@ -92,8 +92,8 @@ audiofile_file_length(AFvirtualfile *vfile) noexcept
static AFfileoffset
audiofile_file_tell(AFvirtualfile *vfile) noexcept
{
AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
InputStream &is = afis.is;
const AudioFileInputStream &afis = *(AudioFileInputStream *)vfile->closure;
const InputStream &is = afis.is;
return is.GetOffset();
}

@@ -38,7 +38,7 @@
#include "tag/Builder.hxx"
#include "tag/Handler.hxx"
#include "tag/ReplayGain.hxx"
#include "tag/MixRamp.hxx"
#include "tag/MixRampParser.hxx"
#include "input/InputStream.hxx"
#include "pcm/CheckAudioFormat.hxx"
#include "util/ScopeExit.hxx"

@@ -78,7 +78,9 @@ FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
if (flac_parse_replay_gain(rgi, vc))
GetClient()->SubmitReplayGain(&rgi);
GetClient()->SubmitMixRamp(flac_parse_mixramp(vc));
if (auto mix_ramp = flac_parse_mixramp(vc);
mix_ramp.IsDefined())
GetClient()->SubmitMixRamp(std::move(mix_ramp));
tag = flac_vorbis_comments_to_tag(&vc);
}

@@ -23,9 +23,10 @@
#include "input/InputStream.hxx"
#include "tag/Id3Scan.hxx"
#include "tag/Id3ReplayGain.hxx"
#include "tag/Id3MixRamp.hxx"
#include "tag/Handler.hxx"
#include "tag/ReplayGain.hxx"
#include "tag/MixRamp.hxx"
#include "tag/MixRampParser.hxx"
#include "pcm/CheckAudioFormat.hxx"
#include "util/Clamp.hxx"
#include "util/StringCompare.hxx"
@@ -268,35 +269,6 @@ MadDecoder::FillBuffer() noexcept
return true;
}
#ifdef ENABLE_ID3TAG
gcc_pure
static MixRampInfo
parse_id3_mixramp(struct id3_tag *tag) noexcept
{
MixRampInfo result;
struct id3_frame *frame;
for (unsigned i = 0; (frame = id3_tag_findframe(tag, "TXXX", i)); i++) {
if (frame->nfields < 3)
continue;
char *const key = (char *)
id3_ucs4_latin1duplicate(id3_field_getstring
(&frame->fields[1]));
char *const value = (char *)
id3_ucs4_latin1duplicate(id3_field_getstring
(&frame->fields[2]));
ParseMixRampTag(result, key, value);
free(key);
free(value);
}
return result;
}
#endif
inline void
MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
{
@@ -310,7 +282,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
id3_data = stream.this_frame;
mad_stream_skip(&(stream), tagsize);
} else {
allocated.reset(new id3_byte_t[tagsize]);
allocated = std::make_unique<id3_byte_t[]>(tagsize);
memcpy(allocated.get(), stream.this_frame, count);
mad_stream_skip(&(stream), count);
@@ -338,7 +310,9 @@ MadDecoder::ParseId3(size_t tagsize, Tag *mpd_tag) noexcept
found_replay_gain = true;
}
client->SubmitMixRamp(parse_id3_mixramp(id3_tag.get()));
if (auto mix_ramp = Id3ToMixRampInfo(id3_tag.get());
mix_ramp.IsDefined())
client->SubmitMixRamp(std::move(mix_ramp));
}
#else /* !ENABLE_ID3TAG */

@@ -23,7 +23,7 @@
#include "tag/Handler.hxx"
#include "tag/Builder.hxx"
#include "tag/ReplayGain.hxx"
#include "tag/MixRamp.hxx"
#include "tag/MixRampParser.hxx"
#include "fs/Path.hxx"
#include "util/Domain.hxx"
#include "util/ScopeExit.hxx"

@@ -137,7 +137,7 @@ SidplayGlobal::SidplayGlobal(const ConfigBlock &block)
const auto kernal_path = block.GetPath("kernal");
if (!kernal_path.IsNull())
{
kernal.reset(new uint8_t[rom_size]);
kernal = std::make_unique<uint8_t[]>(rom_size);
loadRom(kernal_path, kernal.get());
}
@@ -145,7 +145,7 @@ SidplayGlobal::SidplayGlobal(const ConfigBlock &block)
const auto basic_path = block.GetPath("basic");
if (!basic_path.IsNull())
{
basic.reset(new uint8_t[rom_size]);
basic = std::make_unique<uint8_t[]>(rom_size);
loadRom(basic_path, basic.get());
}
#endif

@@ -68,7 +68,7 @@ private:
exception = std::current_exception();
}
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
done = true;
cond.notify_one();
}

@@ -323,7 +323,7 @@ EventLoop::Run() noexcept
/* try to handle DeferEvents without WakeFD
overhead */
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
HandleInject();
#endif
@@ -346,7 +346,7 @@ EventLoop::Run() noexcept
#ifdef HAVE_THREADED_EVENT_LOOP
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
busy = true;
}
#endif
@@ -378,7 +378,7 @@ EventLoop::AddInject(InjectEvent &d) noexcept
bool must_wake;
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
if (d.IsPending())
return;
@@ -397,7 +397,7 @@ EventLoop::AddInject(InjectEvent &d) noexcept
void
EventLoop::RemoveInject(InjectEvent &d) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (d.IsPending())
inject.erase(inject.iterator_to(d));
@@ -424,7 +424,7 @@ EventLoop::OnSocketReady([[maybe_unused]] unsigned flags) noexcept
wake_fd.Read();
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
HandleInject();
}

@@ -91,7 +91,7 @@ public:
}
#endif
bool IsDefined() const noexcept {
[[nodiscard]] bool IsDefined() const noexcept {
return event.IsDefined();
}

@@ -37,6 +37,7 @@
#endif
#include <algorithm>
#include <array>
#include <cassert>
#include <csignal>
@@ -62,7 +63,7 @@ public:
#endif
}
auto &GetEventLoop() const noexcept {
[[nodiscard]] auto &GetEventLoop() const noexcept {
return event.GetEventLoop();
}
@@ -90,12 +91,12 @@ private:
/* this should be enough - is it? */
static constexpr unsigned MAX_SIGNAL = 64;
static SignalHandler signal_handlers[MAX_SIGNAL];
static std::array<SignalHandler, MAX_SIGNAL> signal_handlers;
#ifdef USE_SIGNALFD
static sigset_t signal_mask;
#else
static std::atomic_bool signal_pending[MAX_SIGNAL];
static std::array<std::atomic_bool, MAX_SIGNAL> signal_pending;
#endif
static Manual<SignalMonitor> monitor;
@@ -153,7 +154,7 @@ void
SignalMonitorFinish() noexcept
{
#ifdef USE_SIGNALFD
std::fill_n(signal_handlers, MAX_SIGNAL, nullptr);
signal_handlers = {};
#else
struct sigaction sa;
sa.sa_flags = 0;
@@ -167,7 +168,7 @@ SignalMonitorFinish() noexcept
}
}
std::fill_n(signal_pending, MAX_SIGNAL, false);
std::fill(signal_pending.begin(), signal_pending.end(), false);
#endif
monitor.Destruct();

@@ -23,7 +23,6 @@
#include "filter/Filter.hxx"
#include "filter/Prepared.hxx"
#include "pcm/AudioFormat.hxx"
#include "util/ConstBuffer.hxx"
#include <cassert>
#include <memory>

@@ -31,7 +31,7 @@ AllocatedPath::FromUTF8(std::string_view path_utf8) noexcept
return FromFS(path_utf8);
#else
try {
return AllocatedPath(::PathFromUTF8(path_utf8));
return {::PathFromUTF8(path_utf8)};
} catch (...) {
return nullptr;
}
@@ -44,7 +44,7 @@ AllocatedPath::FromUTF8Throw(std::string_view path_utf8)
#ifdef FS_CHARSET_ALWAYS_UTF8
return FromFS(path_utf8);
#else
return AllocatedPath(::PathFromUTF8(path_utf8));
return {::PathFromUTF8(path_utf8)};
#endif
}

@@ -26,7 +26,7 @@ Path::ToUTF8() const noexcept
try {
return ToUTF8Throw();
} catch (...) {
return std::string();
return {};
}
}

@@ -244,7 +244,7 @@ AsyncInputStream::AppendToBuffer(const void *data, size_t append_size) noexcept
void
AsyncInputStream::DeferredResume() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
try {
Resume();
@@ -257,7 +257,7 @@ AsyncInputStream::DeferredResume() noexcept
void
AsyncInputStream::DeferredSeek() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (seek_state != SeekState::SCHEDULED)
return;

@@ -37,7 +37,7 @@ BufferingInputStream::BufferingInputStream(InputStreamPtr _input)
BufferingInputStream::~BufferingInputStream() noexcept
{
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
stop = true;
wake_cond.notify_one();
}

@@ -97,7 +97,7 @@ InputStream::ReadTag() noexcept
std::unique_ptr<Tag>
InputStream::LockReadTag() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return ReadTag();
}
@@ -152,7 +152,7 @@ InputStream::LockReadFull(void *ptr, size_t _size)
bool
InputStream::LockIsEOF() const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return IsEOF();
}

@@ -27,6 +27,7 @@
#include <cassert>
#include <memory>
#include <string>
#include <utility>
struct Tag;
class InputStreamHandler;

@@ -45,7 +45,7 @@ ThreadInputStream::Stop() noexcept
return;
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
close = true;
wake_cond.notify_one();
}

@@ -37,14 +37,14 @@ InputCacheItem::~InputCacheItem() noexcept
void
InputCacheItem::AddLease(InputCacheLease &lease) noexcept
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
leases.push_back(lease);
}
void
InputCacheItem::RemoveLease(InputCacheLease &lease) noexcept
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
auto i = leases.iterator_to(lease);
if (i == next_lease)
++next_lease;

@@ -63,7 +63,7 @@ public:
using BufferingInputStream::size;
bool IsInUse() const noexcept {
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
return !leases.empty();
}

@@ -24,7 +24,7 @@ CacheInputStream::CacheInputStream(InputCacheLease _lease,
:InputStream(_lease->GetUri(), _mutex),
InputCacheLease(std::move(_lease))
{
auto &i = GetCacheItem();
const auto &i = GetCacheItem();
size = i.size();
seekable = true;
SetReady();
@@ -36,7 +36,7 @@ CacheInputStream::Check()
const ScopeUnlock unlock(mutex);
auto &i = GetCacheItem();
const std::lock_guard<Mutex> protect(i.mutex);
const std::scoped_lock<Mutex> protect(i.mutex);
i.Check();
}
@@ -60,7 +60,7 @@ CacheInputStream::IsAvailable() const noexcept
const ScopeUnlock unlock(mutex);
auto &i = GetCacheItem();
const std::lock_guard<Mutex> protect(i.mutex);
const std::scoped_lock<Mutex> protect(i.mutex);
return i.IsAvailable(_offset);
}
@@ -76,7 +76,7 @@ CacheInputStream::Read(std::unique_lock<Mutex> &lock,
{
const ScopeUnlock unlock(mutex);
const std::lock_guard<Mutex> protect(i.mutex);
const std::scoped_lock<Mutex> protect(i.mutex);
nbytes = i.Read(lock, _offset, ptr, read_size);
}
@@ -91,6 +91,6 @@ CacheInputStream::OnInputCacheAvailable() noexcept
auto &i = GetCacheItem();
const ScopeUnlock unlock(i.mutex);
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
InvokeOnAvailable();
}

@@ -28,12 +28,10 @@
#include "lib/alsa/NonBlock.hxx"
#include "lib/alsa/Error.hxx"
#include "lib/alsa/Format.hxx"
#include "../InputPlugin.hxx"
#include "../AsyncInputStream.hxx"
#include "event/Call.hxx"
#include "config/Block.hxx"
#include "util/Domain.hxx"
#include "util/RuntimeError.hxx"
#include "util/ASCII.hxx"
#include "util/DivideString.hxx"
#include "pcm/AudioParser.hxx"
@@ -239,7 +237,7 @@ AlsaInputStream::DispatchSockets() noexcept
{
non_block.DispatchSockets(*this, capture_handle);
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
auto w = PrepareWriteBuffer();
const snd_pcm_uframes_t w_frames = w.size / frame_size;

@@ -238,7 +238,7 @@ CurlInputStream::OnHeaders(unsigned status,
StringFormat<40>("got HTTP status %u",
status).c_str());
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (IsSeekPending()) {
/* don't update metadata while seeking */
@@ -301,7 +301,7 @@ CurlInputStream::OnData(ConstBuffer<void> data)
{
assert(data.size > 0);
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (IsSeekPending())
SeekDone();
@@ -317,7 +317,7 @@ CurlInputStream::OnData(ConstBuffer<void> data)
void
CurlInputStream::OnEnd()
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
InvokeOnAvailable();
AsyncInputStream::SetClosed();
@@ -326,7 +326,7 @@ CurlInputStream::OnEnd()
void
CurlInputStream::OnError(std::exception_ptr e) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
postponed_exception = std::move(e);
if (IsSeekPending())

@@ -141,7 +141,7 @@ NfsInputStream::DoSeek(offset_type new_offset)
void
NfsInputStream::OnNfsFileOpen(uint64_t _size) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (reconnecting) {
/* reconnect has succeeded */
@@ -161,7 +161,7 @@ NfsInputStream::OnNfsFileOpen(uint64_t _size) noexcept
void
NfsInputStream::OnNfsFileRead(const void *data, size_t data_size) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(!IsBufferFull());
assert(IsBufferFull() == (GetBufferSpace() == 0));
AppendToBuffer(data, data_size);
@@ -174,7 +174,7 @@ NfsInputStream::OnNfsFileRead(const void *data, size_t data_size) noexcept
void
NfsInputStream::OnNfsFileError(std::exception_ptr &&e) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (IsPaused()) {
/* while we're paused, don't report this error to the

@@ -87,7 +87,7 @@ QobuzClient::StartLogin()
void
QobuzClient::AddLoginHandler(QobuzSessionHandler &h) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(!h.is_linked());
const bool was_empty = handlers.empty();
@@ -114,7 +114,7 @@ QobuzClient::AddLoginHandler(QobuzSessionHandler &h) noexcept
QobuzSession
QobuzClient::GetSession() const
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (error)
std::rethrow_exception(error);
@@ -129,7 +129,7 @@ void
QobuzClient::OnQobuzLoginSuccess(QobuzSession &&_session) noexcept
{
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
session = std::move(_session);
login_request.reset();
}
@@ -141,7 +141,7 @@ void
QobuzClient::OnQobuzLoginError(std::exception_ptr _error) noexcept
{
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
error = std::move(_error);
login_request.reset();
}
@@ -152,7 +152,7 @@ QobuzClient::OnQobuzLoginError(std::exception_ptr _error) noexcept
void
QobuzClient::InvokeHandlers() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
while (!handlers.empty()) {
auto &h = handlers.front();
handlers.pop_front();

@@ -83,7 +83,7 @@ public:
void AddLoginHandler(QobuzSessionHandler &h) noexcept;
void RemoveLoginHandler(QobuzSessionHandler &h) noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (h.is_linked())
h.unlink();
}

@@ -84,7 +84,7 @@ private:
void
QobuzInputStream::OnQobuzSession() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
try {
const auto session = qobuz_client->GetSession();
@@ -103,7 +103,7 @@ QobuzInputStream::OnQobuzSession() noexcept
void
QobuzInputStream::OnQobuzTrackSuccess(std::string url) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
track_request.reset();
try {
@@ -117,7 +117,7 @@ QobuzInputStream::OnQobuzTrackSuccess(std::string url) noexcept
void
QobuzInputStream::OnQobuzTrackError(std::exception_ptr e) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
track_request.reset();
Failed(e);

@@ -149,7 +149,7 @@ UringInputStream::OnRead(std::unique_ptr<std::byte[]> data,
{
read_operation.reset();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (nbytes == 0) {
postponed_exception = std::make_exception_ptr(std::runtime_error("Premature end of file"));
@@ -170,7 +170,7 @@ UringInputStream::OnReadError(int error) noexcept
{
read_operation.reset();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
postponed_exception = std::make_exception_ptr(MakeErrno(error, "Read failed"));
InvokeOnAvailable();

@@ -41,4 +41,4 @@ ErrorCategory::message(int condition) const
return snd_strerror(condition);
}
} // namespace Avahi
} // namespace Alsa

@@ -61,7 +61,7 @@ public:
CurlSocket(const CurlSocket &) = delete;
CurlSocket &operator=(const CurlSocket &) = delete;
auto &GetEventLoop() const noexcept {
[[nodiscard]] auto &GetEventLoop() const noexcept {
return socket_event.GetEventLoop();
}
@@ -73,7 +73,7 @@ public:
void *userp, void *socketp) noexcept;
private:
SocketDescriptor GetSocket() const noexcept {
[[nodiscard]] SocketDescriptor GetSocket() const noexcept {
return socket_event.GetSocket();
}

@@ -40,7 +40,7 @@ CurlGlobal *CurlInit::instance;
CurlInit::CurlInit(EventLoop &event_loop)
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (++ref > 1) {
assert(&event_loop == &instance->GetEventLoop());
return;
@@ -56,7 +56,7 @@ CurlInit::CurlInit(EventLoop &event_loop)
CurlInit::~CurlInit() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (--ref > 0)
return;

@@ -32,8 +32,8 @@
#include <curl/curl.h>
#include <algorithm>
#include <stdexcept>
#include <utility>
/**
* OO wrapper for "struct curl_slist *".

@@ -35,8 +35,8 @@
#include <dbus/dbus.h>
#include <algorithm>
#include <stdexcept>
#include <utility>
namespace ODBus {

@@ -44,7 +44,7 @@ try {
#ifdef HAVE_ICU
const auto u = UCharFromUTF8(src);
if (u.IsNull())
return AllocatedString(src);
return {src};
AllocatedArray<UChar> folded(u.size() * 2U);
@@ -54,7 +54,7 @@ try {
U_FOLD_CASE_DEFAULT,
&error_code);
if (folded_length == 0 || error_code != U_ZERO_ERROR)
return AllocatedString(src);
return {src};
folded.SetSize(folded_length);
return UCharToUTF8({folded.begin(), folded.size()});
@@ -63,7 +63,7 @@ try {
#error not implemented
#endif
} catch (...) {
return AllocatedString(src);
return {src};
}
#endif /* HAVE_ICU_CASE_FOLD */

@@ -105,7 +105,7 @@ AllocatedString
IcuConverter::ToUTF8(std::string_view s) const
{
#ifdef HAVE_ICU
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
ucnv_resetToUnicode(converter);
@@ -133,7 +133,7 @@ AllocatedString
IcuConverter::FromUTF8(std::string_view s) const
{
#ifdef HAVE_ICU
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
const auto u = UCharFromUTF8(s);
@@ -152,7 +152,7 @@ IcuConverter::FromUTF8(std::string_view s) const
throw std::runtime_error(fmt::format(FMT_STRING("Failed to convert from Unicode: {}"),
u_errorName(code)));
return AllocatedString({buffer, size_t(target - buffer)});
return {{buffer, size_t(target - buffer)}};
#elif defined(HAVE_ICONV)
return DoConvert(from_utf8, s);

@@ -54,7 +54,7 @@ UCharToUTF8(std::basic_string_view<UChar> src)
/* worst-case estimate */
size_t dest_capacity = 4 * src.size();
std::unique_ptr<char[]> dest(new char[dest_capacity + 1]);
auto dest = std::make_unique<char[]>(dest_capacity + 1);
UErrorCode error_code = U_ZERO_ERROR;
int32_t dest_length;

@@ -68,7 +68,7 @@ private:
* thread.
*/
void LockSetFinished() noexcept {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
finished = true;
cond.notify_one();
}

49
src/lib/pcre/Error.cxx Normal file

@@ -0,0 +1,49 @@
/*
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.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.
*/
#include "Error.hxx"
#include <pcre2.h>
namespace Pcre {
ErrorCategory error_category;
std::string
ErrorCategory::message(int condition) const
{
PCRE2_UCHAR8 buffer[256];
pcre2_get_error_message_8(condition, buffer, std::size(buffer));
return std::string{(const char *)buffer};
}
} // namespace Pcre

56
src/lib/pcre/Error.hxx Normal file

@@ -0,0 +1,56 @@
/*
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.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.
*/
#pragma once
#include <system_error>
namespace Pcre {
class ErrorCategory final : public std::error_category {
public:
const char *name() const noexcept override {
return "pcre2";
}
std::string message(int condition) const override;
};
extern ErrorCategory error_category;
inline std::system_error
MakeError(int error, const char *msg) noexcept
{
return std::system_error(error, error_category, msg);
}
} // namespace Pcre

127
src/lib/pcre/MatchData.hxx Normal file

@@ -0,0 +1,127 @@
/*
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.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.
*/
#pragma once
#include <pcre2.h>
#include <cassert>
#include <cstddef>
#include <string_view>
#include <utility>
class MatchData {
friend class RegexPointer;
pcre2_match_data_8 *match_data = nullptr;
const char *s;
PCRE2_SIZE *ovector;
std::size_t n;
explicit MatchData(pcre2_match_data_8 *_md, const char *_s) noexcept
:match_data(_md), s(_s),
ovector(pcre2_get_ovector_pointer_8(match_data))
{
}
public:
MatchData() = default;
MatchData(MatchData &&src) noexcept
:match_data(std::exchange(src.match_data, nullptr)),
s(src.s), ovector(src.ovector), n(src.n) {}
~MatchData() noexcept {
if (match_data != nullptr)
pcre2_match_data_free_8(match_data);
}
MatchData &operator=(MatchData &&src) noexcept {
using std::swap;
swap(match_data, src.match_data);
swap(s, src.s);
swap(ovector, src.ovector);
swap(n, src.n);
return *this;
}
constexpr operator bool() const noexcept {
return match_data != nullptr;
}
constexpr std::size_t size() const noexcept {
assert(*this);
return static_cast<std::size_t>(n);
}
[[gnu::pure]]
constexpr std::string_view operator[](std::size_t i) const noexcept {
assert(*this);
assert(i < size());
int start = ovector[2 * i];
if (start < 0)
return {};
int end = ovector[2 * i + 1];
assert(end >= start);
return { s + start, std::size_t(end - start) };
}
static constexpr std::size_t npos = ~std::size_t{};
[[gnu::pure]]
constexpr std::size_t GetCaptureStart(std::size_t i) const noexcept {
assert(*this);
assert(i < size());
int start = ovector[2 * i];
if (start < 0)
return npos;
return std::size_t(start);
}
[[gnu::pure]]
constexpr std::size_t GetCaptureEnd(std::size_t i) const noexcept {
assert(*this);
assert(i < size());
int end = ovector[2 * i + 1];
if (end < 0)
return npos;
return std::size_t(end);
}
};

@@ -1,5 +1,5 @@
/*
* Copyright 2007-2018 Content Management AG
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
@@ -30,27 +30,17 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REGEX_POINTER_HXX
#define REGEX_POINTER_HXX
#pragma once
#include "util/StringView.hxx"
#include "util/Compiler.h"
#include "MatchData.hxx"
#include <pcre.h>
#include <pcre2.h>
#include <array>
#if GCC_CHECK_VERSION(11,0)
#pragma GCC diagnostic push
/* bogus GCC 11 warning "ovector may be used uninitialized" in the
ovector.size() call */
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#include <string_view>
class RegexPointer {
protected:
pcre *re = nullptr;
pcre_extra *extra = nullptr;
pcre2_code_8 *re = nullptr;
unsigned n_capture = 0;
@@ -60,18 +50,28 @@ public:
}
[[gnu::pure]]
bool Match(StringView s) const noexcept {
/* we don't need the data written to ovector, but PCRE can
omit internal allocations if we pass a buffer to
pcre_exec() */
std::array<int, 16> ovector;
return pcre_exec(re, extra, s.data, s.size,
0, 0, &ovector.front(), ovector.size()) >= 0;
MatchData Match(std::string_view s) const noexcept {
MatchData match_data{
pcre2_match_data_create_from_pattern_8(re, nullptr),
s.data(),
};
int n = pcre2_match_8(re, (PCRE2_SPTR8)s.data(), s.size(),
0, 0,
match_data.match_data, nullptr);
if (n < 0)
/* no match (or error) */
return {};
match_data.n = n;
if (n_capture >= match_data.n)
/* in its return value, PCRE omits mismatching
optional captures if (and only if) they are
the last capture; this kludge works around
this */
match_data.n = n_capture + 1;
return match_data;
}
};
#if GCC_CHECK_VERSION(11,0)
#pragma GCC diagnostic pop
#endif
#endif

@@ -1,5 +1,5 @@
/*
* Copyright 2007-2018 Content Management AG
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
@@ -31,41 +31,40 @@
*/
#include "UniqueRegex.hxx"
#include "util/RuntimeError.hxx"
#include "Error.hxx"
#include <stdio.h>
void
UniqueRegex::Compile(const char *pattern, bool anchored, bool capture,
bool caseless)
{
constexpr int default_options = PCRE_DOTALL|PCRE_NO_AUTO_CAPTURE|PCRE_UTF8;
constexpr int default_options = PCRE2_DOTALL|PCRE2_NO_AUTO_CAPTURE;
int options = default_options;
uint32_t options = default_options;
if (anchored)
options |= PCRE_ANCHORED;
options |= PCRE2_ANCHORED;
if (capture)
options &= ~PCRE_NO_AUTO_CAPTURE;
options &= ~PCRE2_NO_AUTO_CAPTURE;
if (caseless)
options |= PCRE_CASELESS;
options |= PCRE2_CASELESS;
const char *error_string;
int error_offset;
re = pcre_compile(pattern, options, &error_string, &error_offset, nullptr);
if (re == nullptr)
throw FormatRuntimeError("Error in regex at offset %d: %s",
error_offset, error_string);
int study_options = 0;
#ifdef PCRE_CONFIG_JIT
study_options |= PCRE_STUDY_JIT_COMPILE;
#endif
extra = pcre_study(re, study_options, &error_string);
if (extra == nullptr && error_string != nullptr) {
pcre_free(re);
re = nullptr;
throw FormatRuntimeError("Regex study error: %s", error_string);
int error_number;
PCRE2_SIZE error_offset;
re = pcre2_compile_8(PCRE2_SPTR8(pattern),
PCRE2_ZERO_TERMINATED, options,
&error_number, &error_offset,
nullptr);
if (re == nullptr) {
char msg[256];
snprintf(msg, sizeof(msg), "Error in regex at offset %zu",
error_offset);
throw Pcre::MakeError(error_number, msg);
}
int n;
if (capture && pcre_fullinfo(re, extra, PCRE_INFO_CAPTURECOUNT, &n) == 0)
pcre2_jit_compile_8(re, PCRE2_JIT_COMPLETE);
if (int n; capture &&
pcre2_pattern_info_8(re, PCRE2_INFO_CAPTURECOUNT, &n) == 0)
n_capture = n;
}

@@ -1,5 +1,5 @@
/*
* Copyright 2007-2018 Content Management AG
* Copyright 2007-2021 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
@@ -30,15 +30,12 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef UNIQUE_REGEX_HXX
#define UNIQUE_REGEX_HXX
#pragma once
#include "RegexPointer.hxx"
#include <utility>
#include <pcre.h>
class UniqueRegex : public RegexPointer {
public:
UniqueRegex() = default;
@@ -50,29 +47,22 @@ public:
UniqueRegex(UniqueRegex &&src) noexcept:RegexPointer(src) {
src.re = nullptr;
src.extra = nullptr;
}
~UniqueRegex() noexcept {
pcre_free(re);
#ifdef PCRE_CONFIG_JIT
pcre_free_study(extra);
#else
pcre_free(extra);
#endif
if (re != nullptr)
pcre2_code_free_8(re);
}
UniqueRegex &operator=(UniqueRegex &&src) {
UniqueRegex &operator=(UniqueRegex &&src) noexcept {
using std::swap;
swap<RegexPointer>(*this, src);
return *this;
}
/**
* Throws std::runtime_error on error.
* Throws Pcre::Error on error.
*/
void Compile(const char *pattern, bool anchored, bool capture,
bool caseless);
};
#endif

@@ -1,11 +1,17 @@
pcre_dep = dependency('libpcre', required: get_option('pcre'))
pcre_dep = dependency('libpcre2-8', required: get_option('pcre'))
conf.set('HAVE_PCRE', pcre_dep.found())
if not pcre_dep.found()
subdir_done()
endif
pcre_dep = declare_dependency(
compile_args: '-DPCRE2_CODE_UNIT_WIDTH=0',
dependencies: pcre_dep,
)
pcre = static_library(
'pcre',
'Error.cxx',
'UniqueRegex.cxx',
include_directories: inc,
dependencies: [

@@ -31,4 +31,4 @@ ErrorCategory::message(int condition) const
return spa_strerror(condition);
}
} // namespace Avahi
} // namespace PipeWire

@@ -45,7 +45,7 @@ SmbclientContext::New()
SMBCCTX *ctx;
{
const std::lock_guard<Mutex> protect(global_mutex);
const std::scoped_lock<Mutex> protect(global_mutex);
ctx = smbc_new_context();
}

@@ -48,7 +48,7 @@ public:
~SmbclientContext() noexcept {
if (ctx != nullptr) {
const std::lock_guard<Mutex> protect(global_mutex);
const std::scoped_lock<Mutex> protect(global_mutex);
smbc_free_context(ctx, 1);
}
}

@@ -62,7 +62,7 @@ UpnpClientGlobalInit(const char* iface)
UpnpGlobalInit(iface);
try {
const std::lock_guard<Mutex> protect(upnp_client_init_mutex);
const std::scoped_lock<Mutex> protect(upnp_client_init_mutex);
if (upnp_client_ref == 0)
DoInit();
} catch (...) {
@@ -78,7 +78,7 @@ void
UpnpClientGlobalFinish() noexcept
{
{
const std::lock_guard<Mutex> protect(upnp_client_init_mutex);
const std::scoped_lock<Mutex> protect(upnp_client_init_mutex);
assert(upnp_client_ref > 0);
if (--upnp_client_ref == 0)

@@ -41,14 +41,14 @@ UPnPDeviceDirectory::Downloader::Downloader(UPnPDeviceDirectory &_parent,
expires(std::chrono::seconds(UpnpDiscovery_get_Expires(&disco))),
request(*parent.curl, url.c_str(), *this)
{
const std::lock_guard<Mutex> protect(parent.mutex);
const std::scoped_lock<Mutex> protect(parent.mutex);
parent.downloaders.push_back(*this);
}
void
UPnPDeviceDirectory::Downloader::Destroy() noexcept
{
const std::lock_guard<Mutex> protect(parent.mutex);
const std::scoped_lock<Mutex> protect(parent.mutex);
unlink();
delete this;
}
@@ -139,7 +139,7 @@ AnnounceLostUPnP(UPnPDiscoveryListener &listener, const UPnPDevice &device)
inline void
UPnPDeviceDirectory::LockAdd(ContentDirectoryDescriptor &&d)
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
for (auto &i : directories) {
if (i.id == d.id) {
@@ -157,7 +157,7 @@ UPnPDeviceDirectory::LockAdd(ContentDirectoryDescriptor &&d)
inline void
UPnPDeviceDirectory::LockRemove(const std::string &id)
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
for (auto i = directories.begin(), end = directories.end();
i != end; ++i) {
@@ -265,10 +265,10 @@ UPnPDeviceDirectory::UPnPDeviceDirectory(EventLoop &event_loop,
UPnPDeviceDirectory::~UPnPDeviceDirectory() noexcept
{
BlockingCall(GetEventLoop(), [this](){
const std::lock_guard<Mutex> protect(mutex);
downloaders.clear_and_dispose(DeleteDisposer());
});
BlockingCall(GetEventLoop(), [this]() {
const std::scoped_lock<Mutex> protect(mutex);
downloaders.clear_and_dispose(DeleteDisposer());
});
}
inline EventLoop &
@@ -308,7 +308,7 @@ UPnPDeviceDirectory::Search()
std::vector<ContentDirectoryService>
UPnPDeviceDirectory::GetDirectories()
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
ExpireDevices();
@@ -327,7 +327,7 @@ UPnPDeviceDirectory::GetDirectories()
ContentDirectoryService
UPnPDeviceDirectory::GetServer(std::string_view friendly_name)
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
ExpireDevices();
@@ -339,8 +339,7 @@ UPnPDeviceDirectory::GetServer(std::string_view friendly_name)
for (const auto &service : device.services)
if (isCDService(service.serviceType.c_str()))
return ContentDirectoryService(device,
service);
return {device, service};
}
throw std::runtime_error("Server not found");

@@ -27,7 +27,7 @@
#include "lib/curl/Handler.hxx"
#include "lib/curl/Request.hxx"
#include "thread/Mutex.hxx"
#include "event/DeferEvent.hxx"
#include "event/InjectEvent.hxx"
#include "util/IntrusiveList.hxx"
#include <list>
@@ -81,7 +81,7 @@ class UPnPDeviceDirectory final : UpnpCallback {
class Downloader final
: public IntrusiveListHook, CurlResponseHandler
{
DeferEvent defer_start_event;
InjectEvent defer_start_event;
UPnPDeviceDirectory &parent;

@@ -56,7 +56,7 @@ DoInit(const char* iface)
void
UpnpGlobalInit(const char* iface)
{
const std::lock_guard<Mutex> protect(upnp_init_mutex);
const std::scoped_lock<Mutex> protect(upnp_init_mutex);
if (upnp_ref == 0)
DoInit(iface);
@@ -67,7 +67,7 @@ UpnpGlobalInit(const char* iface)
void
UpnpGlobalFinish() noexcept
{
const std::lock_guard<Mutex> protect(upnp_init_mutex);
const std::scoped_lock<Mutex> protect(upnp_init_mutex);
assert(upnp_ref > 0);

@@ -21,12 +21,12 @@
#include "FlacAudioFormat.hxx"
#include "ScanVorbisComment.hxx"
#include "pcm/CheckAudioFormat.hxx"
#include "MixRampInfo.hxx"
#include "tag/Handler.hxx"
#include "tag/Builder.hxx"
#include "tag/Tag.hxx"
#include "tag/ReplayGain.hxx"
#include "tag/MixRamp.hxx"
#include "tag/MixRampInfo.hxx"
#include "tag/MixRampParser.hxx"
#include "ReplayGainInfo.hxx"
#include "util/StringView.hxx"

@@ -36,8 +36,7 @@ ScanVorbisPicture(StringView value, TagHandler &handler) noexcept
return;
size_t debase64_size = CalculateBase64OutputSize(value.size);
std::unique_ptr<uint8_t[]> debase64_buffer;
debase64_buffer.reset(new uint8_t[debase64_size]);
auto debase64_buffer = std::make_unique<uint8_t[]>(debase64_size);
try {
debase64_size =

@@ -32,7 +32,7 @@
#include <yajl/yajl_parse.h>
#include <algorithm>
#include <utility>
namespace Yajl {

@@ -52,7 +52,7 @@ mixer_open(Mixer *mixer)
{
assert(mixer != nullptr);
const std::lock_guard<Mutex> protect(mixer->mutex);
const std::scoped_lock<Mutex> protect(mixer->mutex);
if (mixer->open)
return;
@@ -82,7 +82,7 @@ mixer_close(Mixer *mixer)
{
assert(mixer != nullptr);
const std::lock_guard<Mutex> protect(mixer->mutex);
const std::scoped_lock<Mutex> protect(mixer->mutex);
if (mixer->open)
mixer_close_internal(mixer);
@@ -119,7 +119,7 @@ mixer_get_volume(Mixer *mixer)
if (mixer->plugin.global && !mixer->failed)
mixer_open(mixer);
const std::lock_guard<Mutex> protect(mixer->mutex);
const std::scoped_lock<Mutex> protect(mixer->mutex);
if (mixer->open) {
try {
@@ -143,7 +143,7 @@ mixer_set_volume(Mixer *mixer, unsigned volume)
if (mixer->plugin.global && !mixer->failed)
mixer_open(mixer);
const std::lock_guard<Mutex> protect(mixer->mutex);
const std::scoped_lock<Mutex> protect(mixer->mutex);
if (mixer->open)
mixer->SetVolume(volume);

@@ -128,13 +128,13 @@ private:
}
[[gnu::pure]]
double GetNormalizedVolume() const noexcept {
[[nodiscard]] double GetNormalizedVolume() const noexcept {
return get_normalized_playback_volume(elem,
SND_MIXER_SCHN_FRONT_LEFT);
}
[[gnu::pure]]
unsigned GetPercentVolume() const noexcept {
[[nodiscard]] unsigned GetPercentVolume() const noexcept {
return NormalizedToPercent(GetNormalizedVolume());
}

@@ -99,7 +99,7 @@ void
SmbclientNeighborExplorer::Close() noexcept
{
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
quit = true;
cond.notify_one();
}
@@ -110,7 +110,7 @@ SmbclientNeighborExplorer::Close() noexcept
NeighborExplorer::List
SmbclientNeighborExplorer::GetList() const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return list;
}

@@ -175,7 +175,7 @@ UdisksNeighborExplorer::Close() noexcept
NeighborExplorer::List
UdisksNeighborExplorer::GetList() const noexcept
{
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
NeighborExplorer::List result;
@@ -192,7 +192,7 @@ UdisksNeighborExplorer::Insert(UDisks2::Object &&o) noexcept
const NeighborInfo info = ToNeighborInfo(o);
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
auto i = by_uri.emplace(o.GetUri(), info);
if (!i.second)
i.first->second = info;

@@ -30,9 +30,10 @@
#include "AddressInfo.hxx"
#include "Features.hxx"
#include <array>
#include <cassert>
static constexpr int address_family_ranking[] = {
static constexpr auto address_family_ranking = std::array {
#ifdef HAVE_UN
AF_LOCAL,
#endif

@@ -187,11 +187,18 @@ public:
return address.sin_family != AF_UNSPEC;
}
/**
* @return the port number in network byte order
*/
constexpr uint16_t GetPortBE() const noexcept {
return address.sin_port;
}
/**
* @return the port number in host byte order
*/
constexpr uint16_t GetPort() const noexcept {
return FromBE16(address.sin_port);
return FromBE16(GetPortBE());
}
/**

@@ -32,7 +32,6 @@
#include "SocketDescriptor.hxx"
#include <algorithm>
#include <utility>
class StaticSocketAddress;

@@ -79,7 +79,7 @@ AudioOutputControl::Steal() noexcept
StopThread();
/* now we can finally remove it */
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return std::exchange(output, nullptr);
}
@@ -91,7 +91,7 @@ AudioOutputControl::ReplaceDummy(std::unique_ptr<FilteredAudioOutput> new_output
assert(new_output);
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
output = std::move(new_output);
enabled = _enabled;
}
@@ -146,7 +146,7 @@ AudioOutputControl::SetAttribute(std::string &&attribute_name,
bool
AudioOutputControl::LockSetEnabled(bool new_value) noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (new_value == enabled)
return false;
@@ -158,7 +158,7 @@ AudioOutputControl::LockSetEnabled(bool new_value) noexcept
bool
AudioOutputControl::LockToggleEnabled() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return enabled = !enabled;
}
@@ -342,14 +342,14 @@ AudioOutputControl::IsChunkConsumed(const MusicChunk &chunk) const noexcept
bool
AudioOutputControl::LockIsChunkConsumed(const MusicChunk &chunk) const noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
return IsChunkConsumed(chunk);
}
void
AudioOutputControl::LockPlay() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(allow_play);
@@ -371,7 +371,7 @@ AudioOutputControl::LockPauseAsync() noexcept
if (output)
output->Interrupt();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(allow_play);
if (IsOpen())
@@ -381,7 +381,7 @@ AudioOutputControl::LockPauseAsync() noexcept
void
AudioOutputControl::LockDrainAsync() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
assert(allow_play);
if (IsOpen())
@@ -394,7 +394,7 @@ AudioOutputControl::LockCancelAsync() noexcept
if (output)
output->Interrupt();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (IsOpen()) {
allow_play = false;
@@ -405,7 +405,7 @@ AudioOutputControl::LockCancelAsync() noexcept
void
AudioOutputControl::LockAllowPlay() noexcept
{
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
allow_play = true;
if (IsOpen())
@@ -457,7 +457,7 @@ AudioOutputControl::BeginDestroy() noexcept
if (output)
output->Interrupt();
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
if (!killed) {
killed = true;
CommandAsync(Command::KILL);

@@ -405,7 +405,7 @@ public:
void EnableDisableAsync();
void LockEnableDisableAsync() {
const std::lock_guard<Mutex> protect(mutex);
const std::scoped_lock<Mutex> protect(mutex);
EnableDisableAsync();
}
@@ -480,7 +480,7 @@ public:
* Locking wrapper for ClearTailChunk().
*/
void LockClearTailChunk(const MusicChunk &chunk) noexcept {
const std::lock_guard<Mutex> lock(mutex);
const std::scoped_lock<Mutex> lock(mutex);
ClearTailChunk(chunk);
}

@@ -229,7 +229,7 @@ MultipleOutputs::Open(const AudioFormat audio_format)
std::exception_ptr first_error;
for (const auto &ao : outputs) {
const std::lock_guard<Mutex> lock(ao->mutex);
const std::scoped_lock<Mutex> lock(ao->mutex);
if (ao->IsEnabled())
enabled = true;

Some files were not shown because too many files have changed in this diff Show More