aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AudioConfig.cxx6
-rw-r--r--src/AudioConfig.hxx5
-rw-r--r--src/AudioFormat.cxx2
-rw-r--r--src/AudioFormat.hxx18
-rw-r--r--src/AudioParser.cxx2
-rw-r--r--src/AudioParser.hxx6
-rw-r--r--src/BulkEdit.hxx2
-rw-r--r--src/CheckAudioFormat.cxx2
-rw-r--r--src/CheckAudioFormat.hxx2
-rw-r--r--src/Chrono.hxx4
-rw-r--r--src/CommandLine.cxx151
-rw-r--r--src/CommandLine.hxx2
-rw-r--r--src/Compiler.h26
-rw-r--r--src/DetachedSong.cxx2
-rw-r--r--src/DetachedSong.hxx9
-rw-r--r--src/GlobalEvents.cxx2
-rw-r--r--src/GlobalEvents.hxx2
-rw-r--r--src/IOThread.cxx2
-rw-r--r--src/IOThread.hxx12
-rw-r--r--src/IcyMetaDataParser.cxx5
-rw-r--r--src/IcyMetaDataParser.hxx2
-rw-r--r--src/Idle.cxx2
-rw-r--r--src/Idle.hxx6
-rw-r--r--src/Instance.cxx5
-rw-r--r--src/Instance.hxx2
-rw-r--r--src/Listen.cxx14
-rw-r--r--src/Listen.hxx5
-rw-r--r--src/LocateUri.cxx120
-rw-r--r--src/LocateUri.hxx109
-rw-r--r--src/Log.cxx2
-rw-r--r--src/Log.hxx2
-rw-r--r--src/LogBackend.cxx38
-rw-r--r--src/LogBackend.hxx9
-rw-r--r--src/LogInit.cxx32
-rw-r--r--src/LogInit.hxx7
-rw-r--r--src/LogLevel.hxx2
-rw-r--r--src/LogV.hxx2
-rw-r--r--src/Main.cxx86
-rw-r--r--src/Main.hxx6
-rw-r--r--src/Mapper.cxx19
-rw-r--r--src/Mapper.hxx10
-rw-r--r--src/MixRampInfo.hxx2
-rw-r--r--src/MusicBuffer.cxx2
-rw-r--r--src/MusicBuffer.hxx2
-rw-r--r--src/MusicChunk.cxx2
-rw-r--r--src/MusicChunk.hxx10
-rw-r--r--src/MusicPipe.cxx2
-rw-r--r--src/MusicPipe.hxx2
-rw-r--r--src/Partition.cxx9
-rw-r--r--src/Partition.hxx13
-rw-r--r--src/Permission.cxx8
-rw-r--r--src/Permission.hxx8
-rw-r--r--src/PlaylistDatabase.cxx2
-rw-r--r--src/PlaylistDatabase.hxx2
-rw-r--r--src/PlaylistError.cxx2
-rw-r--r--src/PlaylistError.hxx2
-rw-r--r--src/PlaylistFile.cxx114
-rw-r--r--src/PlaylistFile.hxx11
-rw-r--r--src/PlaylistGlobal.cxx2
-rw-r--r--src/PlaylistGlobal.hxx2
-rw-r--r--src/PlaylistPrint.cxx52
-rw-r--r--src/PlaylistPrint.hxx27
-rw-r--r--src/PlaylistSave.cxx57
-rw-r--r--src/PlaylistSave.hxx21
-rw-r--r--src/ReplayGainConfig.cxx14
-rw-r--r--src/ReplayGainConfig.hxx7
-rw-r--r--src/ReplayGainInfo.cxx2
-rw-r--r--src/ReplayGainInfo.hxx10
-rw-r--r--src/SongFilter.cxx23
-rw-r--r--src/SongFilter.hxx16
-rw-r--r--src/SongLoader.cxx91
-rw-r--r--src/SongLoader.hxx12
-rw-r--r--src/SongPrint.cxx86
-rw-r--r--src/SongPrint.hxx17
-rw-r--r--src/SongSave.cxx2
-rw-r--r--src/SongSave.hxx2
-rw-r--r--src/SongUpdate.cxx60
-rw-r--r--src/StateFile.cxx2
-rw-r--r--src/StateFile.hxx2
-rw-r--r--src/Stats.cxx47
-rw-r--r--src/Stats.hxx10
-rw-r--r--src/TagArchive.cxx45
-rw-r--r--src/TagArchive.hxx39
-rw-r--r--src/TagFile.cxx8
-rw-r--r--src/TagFile.hxx2
-rw-r--r--src/TagPrint.cxx40
-rw-r--r--src/TagPrint.hxx13
-rw-r--r--src/TagSave.cxx2
-rw-r--r--src/TagSave.hxx2
-rw-r--r--src/TagStream.cxx2
-rw-r--r--src/TagStream.hxx2
-rw-r--r--src/TimePrint.cxx8
-rw-r--r--src/TimePrint.hxx6
-rw-r--r--src/android/Context.cxx2
-rw-r--r--src/android/Context.hxx2
-rw-r--r--src/android/Environment.cxx2
-rw-r--r--src/android/Environment.hxx2
-rw-r--r--src/archive/ArchiveDomain.cxx2
-rw-r--r--src/archive/ArchiveDomain.hxx2
-rw-r--r--src/archive/ArchiveFile.hxx2
-rw-r--r--src/archive/ArchiveList.cxx8
-rw-r--r--src/archive/ArchiveList.hxx8
-rw-r--r--src/archive/ArchiveLookup.cxx2
-rw-r--r--src/archive/ArchiveLookup.hxx2
-rw-r--r--src/archive/ArchivePlugin.cxx2
-rw-r--r--src/archive/ArchivePlugin.hxx6
-rw-r--r--src/archive/ArchiveVisitor.hxx2
-rw-r--r--src/archive/plugins/Bzip2ArchivePlugin.cxx4
-rw-r--r--src/archive/plugins/Bzip2ArchivePlugin.hxx2
-rw-r--r--src/archive/plugins/Iso9660ArchivePlugin.cxx2
-rw-r--r--src/archive/plugins/Iso9660ArchivePlugin.hxx2
-rw-r--r--src/archive/plugins/ZzipArchivePlugin.cxx2
-rw-r--r--src/archive/plugins/ZzipArchivePlugin.hxx2
-rw-r--r--src/check.h2
-rw-r--r--src/client/Client.cxx2
-rw-r--r--src/client/Client.hxx17
-rw-r--r--src/client/ClientEvent.cxx5
-rw-r--r--src/client/ClientExpire.cxx2
-rw-r--r--src/client/ClientFile.cxx13
-rw-r--r--src/client/ClientGlobal.cxx8
-rw-r--r--src/client/ClientIdle.cxx2
-rw-r--r--src/client/ClientInternal.hxx2
-rw-r--r--src/client/ClientList.cxx7
-rw-r--r--src/client/ClientList.hxx2
-rw-r--r--src/client/ClientMessage.cxx2
-rw-r--r--src/client/ClientMessage.hxx6
-rw-r--r--src/client/ClientNew.cxx11
-rw-r--r--src/client/ClientProcess.cxx13
-rw-r--r--src/client/ClientRead.cxx2
-rw-r--r--src/client/ClientSubscribe.cxx2
-rw-r--r--src/client/ClientWrite.cxx20
-rw-r--r--src/client/Response.cxx76
-rw-r--r--src/client/Response.hxx65
-rw-r--r--src/command/AllCommands.cxx199
-rw-r--r--src/command/AllCommands.hxx8
-rw-r--r--src/command/CommandError.cxx61
-rw-r--r--src/command/CommandError.hxx8
-rw-r--r--src/command/CommandListBuilder.cxx3
-rw-r--r--src/command/CommandListBuilder.hxx5
-rw-r--r--src/command/CommandResult.hxx2
-rw-r--r--src/command/DatabaseCommands.cxx145
-rw-r--r--src/command/DatabaseCommands.hxx26
-rw-r--r--src/command/FileCommands.cxx183
-rw-r--r--src/command/FileCommands.hxx10
-rw-r--r--src/command/MessageCommands.cxx66
-rw-r--r--src/command/MessageCommands.hxx14
-rw-r--r--src/command/NeighborCommands.cxx21
-rw-r--r--src/command/NeighborCommands.hxx6
-rw-r--r--src/command/OtherCommands.cxx336
-rw-r--r--src/command/OtherCommands.hxx36
-rw-r--r--src/command/OutputCommands.cxx37
-rw-r--r--src/command/OutputCommands.hxx12
-rw-r--r--src/command/PlayerCommands.cxx232
-rw-r--r--src/command/PlayerCommands.hxx46
-rw-r--r--src/command/PlaylistCommands.cxx140
-rw-r--r--src/command/PlaylistCommands.hxx31
-rw-r--r--src/command/QueueCommands.cxx305
-rw-r--r--src/command/QueueCommands.hxx44
-rw-r--r--src/command/Request.hxx74
-rw-r--r--src/command/StickerCommands.cxx152
-rw-r--r--src/command/StickerCommands.hxx6
-rw-r--r--src/command/StorageCommands.cxx96
-rw-r--r--src/command/StorageCommands.hxx14
-rw-r--r--src/command/TagCommands.cxx32
-rw-r--r--src/command/TagCommands.hxx8
-rw-r--r--src/config/Block.cxx (renamed from src/config/ConfigData.cxx)49
-rw-r--r--src/config/Block.hxx (renamed from src/config/ConfigData.hxx)54
-rw-r--r--src/config/ConfigDefaults.hxx2
-rw-r--r--src/config/ConfigError.cxx2
-rw-r--r--src/config/ConfigError.hxx2
-rw-r--r--src/config/ConfigFile.cxx262
-rw-r--r--src/config/ConfigFile.hxx2
-rw-r--r--src/config/ConfigGlobal.cxx46
-rw-r--r--src/config/ConfigGlobal.hxx23
-rw-r--r--src/config/ConfigOption.hxx142
-rw-r--r--src/config/ConfigParser.cxx6
-rw-r--r--src/config/ConfigParser.hxx2
-rw-r--r--src/config/ConfigPath.cxx4
-rw-r--r--src/config/ConfigPath.hxx2
-rw-r--r--src/config/ConfigTemplates.cxx162
-rw-r--r--src/config/ConfigTemplates.hxx15
-rw-r--r--src/config/Data.cxx37
-rw-r--r--src/config/Data.hxx37
-rw-r--r--src/config/Param.cxx29
-rw-r--r--src/config/Param.hxx67
-rw-r--r--src/db/Configured.cxx23
-rw-r--r--src/db/Configured.hxx2
-rw-r--r--src/db/Count.cxx29
-rw-r--r--src/db/Count.hxx9
-rw-r--r--src/db/DatabaseError.cxx2
-rw-r--r--src/db/DatabaseError.hxx2
-rw-r--r--src/db/DatabaseGlue.cxx10
-rw-r--r--src/db/DatabaseGlue.hxx8
-rw-r--r--src/db/DatabaseListener.hxx2
-rw-r--r--src/db/DatabaseLock.cxx2
-rw-r--r--src/db/DatabaseLock.hxx2
-rw-r--r--src/db/DatabasePlaylist.cxx2
-rw-r--r--src/db/DatabasePlaylist.hxx2
-rw-r--r--src/db/DatabasePlugin.hxx6
-rw-r--r--src/db/DatabasePrint.cxx122
-rw-r--r--src/db/DatabasePrint.hxx20
-rw-r--r--src/db/DatabaseQueue.cxx2
-rw-r--r--src/db/DatabaseQueue.hxx2
-rw-r--r--src/db/DatabaseSong.cxx2
-rw-r--r--src/db/DatabaseSong.hxx2
-rw-r--r--src/db/Helpers.cxx6
-rw-r--r--src/db/Helpers.hxx2
-rw-r--r--src/db/Interface.hxx6
-rw-r--r--src/db/LightDirectory.hxx2
-rw-r--r--src/db/LightSong.cxx2
-rw-r--r--src/db/LightSong.hxx2
-rw-r--r--src/db/PlaylistInfo.hxx2
-rw-r--r--src/db/PlaylistVector.cxx2
-rw-r--r--src/db/PlaylistVector.hxx2
-rw-r--r--src/db/Registry.cxx6
-rw-r--r--src/db/Registry.hxx2
-rw-r--r--src/db/Selection.cxx9
-rw-r--r--src/db/Selection.hxx2
-rw-r--r--src/db/Stats.hxx2
-rw-r--r--src/db/UniqueTags.cxx6
-rw-r--r--src/db/UniqueTags.hxx7
-rw-r--r--src/db/Uri.hxx2
-rw-r--r--src/db/Visitor.hxx2
-rw-r--r--src/db/plugins/LazyDatabase.cxx4
-rw-r--r--src/db/plugins/LazyDatabase.hxx4
-rw-r--r--src/db/plugins/ProxyDatabasePlugin.cxx36
-rw-r--r--src/db/plugins/ProxyDatabasePlugin.hxx2
-rw-r--r--src/db/plugins/simple/DatabaseSave.cxx8
-rw-r--r--src/db/plugins/simple/DatabaseSave.hxx2
-rw-r--r--src/db/plugins/simple/Directory.cxx10
-rw-r--r--src/db/plugins/simple/Directory.hxx8
-rw-r--r--src/db/plugins/simple/DirectorySave.cxx2
-rw-r--r--src/db/plugins/simple/DirectorySave.hxx2
-rw-r--r--src/db/plugins/simple/Mount.cxx2
-rw-r--r--src/db/plugins/simple/Mount.hxx2
-rw-r--r--src/db/plugins/simple/PrefixedLightSong.hxx2
-rw-r--r--src/db/plugins/simple/SimpleDatabasePlugin.cxx76
-rw-r--r--src/db/plugins/simple/SimpleDatabasePlugin.hxx12
-rw-r--r--src/db/plugins/simple/Song.cxx2
-rw-r--r--src/db/plugins/simple/Song.hxx6
-rw-r--r--src/db/plugins/simple/SongSort.cxx2
-rw-r--r--src/db/plugins/simple/SongSort.hxx2
-rw-r--r--src/db/plugins/upnp/ContentDirectoryService.cxx2
-rw-r--r--src/db/plugins/upnp/Directory.cxx79
-rw-r--r--src/db/plugins/upnp/Directory.hxx2
-rw-r--r--src/db/plugins/upnp/Object.cxx2
-rw-r--r--src/db/plugins/upnp/Object.hxx29
-rw-r--r--src/db/plugins/upnp/Tags.cxx2
-rw-r--r--src/db/plugins/upnp/Tags.hxx2
-rw-r--r--src/db/plugins/upnp/UpnpDatabasePlugin.cxx46
-rw-r--r--src/db/plugins/upnp/UpnpDatabasePlugin.hxx2
-rw-r--r--src/db/update/Archive.cxx6
-rw-r--r--src/db/update/Container.cxx11
-rw-r--r--src/db/update/Editor.cxx2
-rw-r--r--src/db/update/Editor.hxx2
-rw-r--r--src/db/update/ExcludeList.cxx60
-rw-r--r--src/db/update/ExcludeList.hxx47
-rw-r--r--src/db/update/InotifyDomain.cxx2
-rw-r--r--src/db/update/InotifyDomain.hxx2
-rw-r--r--src/db/update/InotifyQueue.cxx2
-rw-r--r--src/db/update/InotifyQueue.hxx2
-rw-r--r--src/db/update/InotifySource.cxx12
-rw-r--r--src/db/update/InotifySource.hxx13
-rw-r--r--src/db/update/InotifyUpdate.cxx17
-rw-r--r--src/db/update/InotifyUpdate.hxx4
-rw-r--r--src/db/update/Queue.cxx2
-rw-r--r--src/db/update/Queue.hxx2
-rw-r--r--src/db/update/Remove.cxx2
-rw-r--r--src/db/update/Remove.hxx2
-rw-r--r--src/db/update/Service.cxx2
-rw-r--r--src/db/update/Service.hxx2
-rw-r--r--src/db/update/UpdateDomain.cxx2
-rw-r--r--src/db/update/UpdateDomain.hxx2
-rw-r--r--src/db/update/UpdateIO.cxx12
-rw-r--r--src/db/update/UpdateIO.hxx8
-rw-r--r--src/db/update/UpdateSong.cxx6
-rw-r--r--src/db/update/Walk.cxx51
-rw-r--r--src/db/update/Walk.hxx30
-rw-r--r--src/decoder/DecoderAPI.cxx2
-rw-r--r--src/decoder/DecoderAPI.hxx14
-rw-r--r--src/decoder/DecoderBuffer.cxx2
-rw-r--r--src/decoder/DecoderBuffer.hxx2
-rw-r--r--src/decoder/DecoderCommand.hxx2
-rw-r--r--src/decoder/DecoderControl.cxx2
-rw-r--r--src/decoder/DecoderControl.hxx2
-rw-r--r--src/decoder/DecoderError.cxx2
-rw-r--r--src/decoder/DecoderError.hxx2
-rw-r--r--src/decoder/DecoderInternal.cxx2
-rw-r--r--src/decoder/DecoderInternal.hxx2
-rw-r--r--src/decoder/DecoderList.cxx37
-rw-r--r--src/decoder/DecoderList.hxx8
-rw-r--r--src/decoder/DecoderPlugin.cxx2
-rw-r--r--src/decoder/DecoderPlugin.hxx17
-rw-r--r--src/decoder/DecoderPrint.cxx16
-rw-r--r--src/decoder/DecoderPrint.hxx6
-rw-r--r--src/decoder/DecoderThread.cxx15
-rw-r--r--src/decoder/DecoderThread.hxx2
-rw-r--r--src/decoder/plugins/AdPlugDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/AdPlugDecoderPlugin.h2
-rw-r--r--src/decoder/plugins/AudiofileDecoderPlugin.cxx4
-rw-r--r--src/decoder/plugins/AudiofileDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/DsdLib.cxx28
-rw-r--r--src/decoder/plugins/DsdLib.hxx4
-rw-r--r--src/decoder/plugins/DsdiffDecoderPlugin.cxx12
-rw-r--r--src/decoder/plugins/DsdiffDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/DsfDecoderPlugin.cxx10
-rw-r--r--src/decoder/plugins/DsfDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/FaadDecoderPlugin.cxx2
-rw-r--r--src/decoder/plugins/FaadDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx668
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/FfmpegIo.cxx110
-rw-r--r--src/decoder/plugins/FfmpegIo.hxx55
-rw-r--r--src/decoder/plugins/FfmpegMetaData.cxx40
-rw-r--r--src/decoder/plugins/FfmpegMetaData.hxx16
-rw-r--r--src/decoder/plugins/FlacCommon.cxx2
-rw-r--r--src/decoder/plugins/FlacCommon.hxx2
-rw-r--r--src/decoder/plugins/FlacDecoderPlugin.cxx9
-rw-r--r--src/decoder/plugins/FlacDecoderPlugin.h2
-rw-r--r--src/decoder/plugins/FlacDomain.cxx2
-rw-r--r--src/decoder/plugins/FlacDomain.hxx2
-rw-r--r--src/decoder/plugins/FlacIOHandle.cxx2
-rw-r--r--src/decoder/plugins/FlacIOHandle.hxx2
-rw-r--r--src/decoder/plugins/FlacInput.cxx2
-rw-r--r--src/decoder/plugins/FlacInput.hxx2
-rw-r--r--src/decoder/plugins/FlacMetadata.cxx6
-rw-r--r--src/decoder/plugins/FlacMetadata.hxx2
-rw-r--r--src/decoder/plugins/FlacPcm.cxx2
-rw-r--r--src/decoder/plugins/FlacPcm.hxx2
-rw-r--r--src/decoder/plugins/FluidsynthDecoderPlugin.cxx12
-rw-r--r--src/decoder/plugins/FluidsynthDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx218
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/MadDecoderPlugin.cxx42
-rw-r--r--src/decoder/plugins/MadDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/MikmodDecoderPlugin.cxx10
-rw-r--r--src/decoder/plugins/MikmodDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/ModplugDecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/ModplugDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/MpcdecDecoderPlugin.cxx11
-rw-r--r--src/decoder/plugins/MpcdecDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/Mpg123DecoderPlugin.cxx7
-rw-r--r--src/decoder/plugins/Mpg123DecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/OggCodec.cxx2
-rw-r--r--src/decoder/plugins/OggCodec.hxx2
-rw-r--r--src/decoder/plugins/OggFind.cxx2
-rw-r--r--src/decoder/plugins/OggFind.hxx2
-rw-r--r--src/decoder/plugins/OggSyncState.hxx2
-rw-r--r--src/decoder/plugins/OggUtil.cxx2
-rw-r--r--src/decoder/plugins/OggUtil.hxx2
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.cxx4
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.h2
-rw-r--r--src/decoder/plugins/OpusDomain.cxx2
-rw-r--r--src/decoder/plugins/OpusDomain.hxx2
-rw-r--r--src/decoder/plugins/OpusHead.cxx2
-rw-r--r--src/decoder/plugins/OpusHead.hxx2
-rw-r--r--src/decoder/plugins/OpusReader.hxx2
-rw-r--r--src/decoder/plugins/OpusTags.cxx2
-rw-r--r--src/decoder/plugins/OpusTags.hxx2
-rw-r--r--src/decoder/plugins/PcmDecoderPlugin.cxx2
-rw-r--r--src/decoder/plugins/PcmDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/SidplayDecoderPlugin.cxx190
-rw-r--r--src/decoder/plugins/SidplayDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/SndfileDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/SndfileDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/VorbisComments.cxx6
-rw-r--r--src/decoder/plugins/VorbisComments.hxx2
-rw-r--r--src/decoder/plugins/VorbisDecoderPlugin.cxx18
-rw-r--r--src/decoder/plugins/VorbisDecoderPlugin.h2
-rw-r--r--src/decoder/plugins/VorbisDomain.cxx2
-rw-r--r--src/decoder/plugins/VorbisDomain.hxx2
-rw-r--r--src/decoder/plugins/WavpackDecoderPlugin.cxx10
-rw-r--r--src/decoder/plugins/WavpackDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/WildmidiDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/WildmidiDecoderPlugin.hxx2
-rw-r--r--src/decoder/plugins/XiphTags.cxx3
-rw-r--r--src/decoder/plugins/XiphTags.hxx2
-rw-r--r--src/encoder/EncoderAPI.hxx5
-rw-r--r--src/encoder/EncoderInterface.hxx256
-rw-r--r--src/encoder/EncoderList.cxx12
-rw-r--r--src/encoder/EncoderList.hxx2
-rw-r--r--src/encoder/EncoderPlugin.hxx258
-rw-r--r--src/encoder/ToOutputStream.cxx41
-rw-r--r--src/encoder/ToOutputStream.hxx32
-rw-r--r--src/encoder/plugins/FlacEncoderPlugin.cxx12
-rw-r--r--src/encoder/plugins/FlacEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/LameEncoderPlugin.cxx18
-rw-r--r--src/encoder/plugins/LameEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/NullEncoderPlugin.cxx4
-rw-r--r--src/encoder/plugins/NullEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/OggSerial.cxx2
-rw-r--r--src/encoder/plugins/OggSerial.hxx2
-rw-r--r--src/encoder/plugins/OggStream.hxx2
-rw-r--r--src/encoder/plugins/OpusEncoderPlugin.cxx16
-rw-r--r--src/encoder/plugins/OpusEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/ShineEncoderPlugin.cxx15
-rw-r--r--src/encoder/plugins/ShineEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/TwolameEncoderPlugin.cxx18
-rw-r--r--src/encoder/plugins/TwolameEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/VorbisEncoderPlugin.cxx155
-rw-r--r--src/encoder/plugins/VorbisEncoderPlugin.hxx2
-rw-r--r--src/encoder/plugins/WaveEncoderPlugin.cxx4
-rw-r--r--src/encoder/plugins/WaveEncoderPlugin.hxx2
-rw-r--r--src/event/BufferedSocket.cxx4
-rw-r--r--src/event/BufferedSocket.hxx2
-rw-r--r--src/event/Call.cxx2
-rw-r--r--src/event/Call.hxx2
-rw-r--r--src/event/DeferredMonitor.cxx2
-rw-r--r--src/event/DeferredMonitor.hxx2
-rw-r--r--src/event/FullyBufferedSocket.cxx4
-rw-r--r--src/event/FullyBufferedSocket.hxx2
-rw-r--r--src/event/IdleMonitor.cxx2
-rw-r--r--src/event/IdleMonitor.hxx2
-rw-r--r--src/event/Loop.cxx2
-rw-r--r--src/event/Loop.hxx2
-rw-r--r--src/event/MultiSocketMonitor.cxx2
-rw-r--r--src/event/MultiSocketMonitor.hxx2
-rw-r--r--src/event/PollGroup.hxx2
-rw-r--r--src/event/PollGroupEPoll.hxx2
-rw-r--r--src/event/PollGroupPoll.cxx2
-rw-r--r--src/event/PollGroupPoll.hxx2
-rw-r--r--src/event/PollGroupWinSelect.cxx2
-rw-r--r--src/event/PollGroupWinSelect.hxx2
-rw-r--r--src/event/PollResultGeneric.hxx2
-rw-r--r--src/event/ServerSocket.cxx98
-rw-r--r--src/event/ServerSocket.hxx26
-rw-r--r--src/event/SignalMonitor.cxx2
-rw-r--r--src/event/SignalMonitor.hxx2
-rw-r--r--src/event/SocketMonitor.cxx2
-rw-r--r--src/event/SocketMonitor.hxx2
-rw-r--r--src/event/TimeoutMonitor.cxx2
-rw-r--r--src/event/TimeoutMonitor.hxx2
-rw-r--r--src/event/WakeFD.hxx2
-rw-r--r--src/filter/FilterConfig.cxx9
-rw-r--r--src/filter/FilterConfig.hxx4
-rw-r--r--src/filter/FilterInternal.hxx10
-rw-r--r--src/filter/FilterPlugin.cxx14
-rw-r--r--src/filter/FilterPlugin.hxx14
-rw-r--r--src/filter/FilterRegistry.cxx2
-rw-r--r--src/filter/FilterRegistry.hxx2
-rw-r--r--src/filter/plugins/AutoConvertFilterPlugin.cxx6
-rw-r--r--src/filter/plugins/AutoConvertFilterPlugin.hxx2
-rw-r--r--src/filter/plugins/ChainFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/ChainFilterPlugin.hxx4
-rw-r--r--src/filter/plugins/ConvertFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/ConvertFilterPlugin.hxx2
-rw-r--r--src/filter/plugins/NormalizeFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/NullFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/ReplayGainFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/ReplayGainFilterPlugin.hxx6
-rw-r--r--src/filter/plugins/RouteFilterPlugin.cxx16
-rw-r--r--src/filter/plugins/VolumeFilterPlugin.cxx4
-rw-r--r--src/filter/plugins/VolumeFilterPlugin.hxx2
-rw-r--r--src/fs/AllocatedPath.cxx51
-rw-r--r--src/fs/AllocatedPath.hxx31
-rw-r--r--src/fs/Charset.cxx157
-rw-r--r--src/fs/Charset.hxx28
-rw-r--r--src/fs/CheckFile.cxx36
-rw-r--r--src/fs/CheckFile.hxx2
-rw-r--r--src/fs/Config.cxx46
-rw-r--r--src/fs/Config.hxx9
-rw-r--r--src/fs/DirectoryReader.hxx87
-rw-r--r--src/fs/Domain.cxx2
-rw-r--r--src/fs/Domain.hxx2
-rw-r--r--src/fs/FileInfo.hxx156
-rw-r--r--src/fs/FileSystem.cxx2
-rw-r--r--src/fs/FileSystem.hxx94
-rw-r--r--src/fs/Glob.hxx68
-rw-r--r--src/fs/Limits.hxx2
-rw-r--r--src/fs/NarrowPath.hxx71
-rw-r--r--src/fs/Path.cxx15
-rw-r--r--src/fs/Path.hxx62
-rw-r--r--src/fs/Path2.cxx28
-rw-r--r--src/fs/StandardDirectory.cxx6
-rw-r--r--src/fs/StandardDirectory.hxx2
-rw-r--r--src/fs/Traits.cxx12
-rw-r--r--src/fs/Traits.hxx47
-rw-r--r--src/fs/io/AutoGunzipReader.cxx2
-rw-r--r--src/fs/io/AutoGunzipReader.hxx2
-rw-r--r--src/fs/io/BufferedOutputStream.cxx7
-rw-r--r--src/fs/io/BufferedOutputStream.hxx20
-rw-r--r--src/fs/io/BufferedReader.cxx7
-rw-r--r--src/fs/io/BufferedReader.hxx11
-rw-r--r--src/fs/io/FileOutputStream.cxx187
-rw-r--r--src/fs/io/FileOutputStream.hxx115
-rw-r--r--src/fs/io/FileReader.cxx78
-rw-r--r--src/fs/io/FileReader.hxx35
-rw-r--r--src/fs/io/GunzipReader.cxx2
-rw-r--r--src/fs/io/GunzipReader.hxx2
-rw-r--r--src/fs/io/GzipOutputStream.cxx2
-rw-r--r--src/fs/io/GzipOutputStream.hxx2
-rw-r--r--src/fs/io/OutputStream.hxx2
-rw-r--r--src/fs/io/PeekReader.cxx2
-rw-r--r--src/fs/io/PeekReader.hxx2
-rw-r--r--src/fs/io/Reader.hxx2
-rw-r--r--src/fs/io/StdioOutputStream.hxx2
-rw-r--r--src/fs/io/TextFile.cxx8
-rw-r--r--src/fs/io/TextFile.hxx5
-rw-r--r--src/haiku/App_MusicPDbin0 -> 46028 bytes
-rw-r--r--src/haiku/mpd.rdef69
-rw-r--r--src/input/AsyncInputStream.cxx2
-rw-r--r--src/input/AsyncInputStream.hxx6
-rw-r--r--src/input/Domain.cxx2
-rw-r--r--src/input/Domain.hxx2
-rw-r--r--src/input/IcyInputStream.cxx2
-rw-r--r--src/input/IcyInputStream.hxx2
-rw-r--r--src/input/Init.cxx19
-rw-r--r--src/input/Init.hxx9
-rw-r--r--src/input/InputPlugin.hxx8
-rw-r--r--src/input/InputStream.cxx33
-rw-r--r--src/input/InputStream.hxx29
-rw-r--r--src/input/LocalOpen.cxx2
-rw-r--r--src/input/LocalOpen.hxx2
-rw-r--r--src/input/Offset.hxx2
-rw-r--r--src/input/Open.cxx13
-rw-r--r--src/input/ProxyInputStream.cxx2
-rw-r--r--src/input/ProxyInputStream.hxx2
-rw-r--r--src/input/Registry.cxx10
-rw-r--r--src/input/Registry.hxx2
-rw-r--r--src/input/TextInputStream.cxx2
-rw-r--r--src/input/TextInputStream.hxx6
-rw-r--r--src/input/ThreadInputStream.cxx2
-rw-r--r--src/input/ThreadInputStream.hxx2
-rw-r--r--src/input/plugins/AlsaInputPlugin.cxx2
-rw-r--r--src/input/plugins/AlsaInputPlugin.hxx2
-rw-r--r--src/input/plugins/ArchiveInputPlugin.cxx2
-rw-r--r--src/input/plugins/ArchiveInputPlugin.hxx2
-rw-r--r--src/input/plugins/CdioParanoiaInputPlugin.cxx11
-rw-r--r--src/input/plugins/CdioParanoiaInputPlugin.hxx2
-rw-r--r--src/input/plugins/CurlInputPlugin.cxx29
-rw-r--r--src/input/plugins/CurlInputPlugin.hxx2
-rw-r--r--src/input/plugins/FfmpegInputPlugin.cxx8
-rw-r--r--src/input/plugins/FfmpegInputPlugin.hxx2
-rw-r--r--src/input/plugins/FileInputPlugin.cxx57
-rw-r--r--src/input/plugins/FileInputPlugin.hxx2
-rw-r--r--src/input/plugins/MmsInputPlugin.cxx2
-rw-r--r--src/input/plugins/MmsInputPlugin.hxx2
-rw-r--r--src/input/plugins/NfsInputPlugin.cxx8
-rw-r--r--src/input/plugins/NfsInputPlugin.hxx2
-rw-r--r--src/input/plugins/RewindInputPlugin.cxx2
-rw-r--r--src/input/plugins/RewindInputPlugin.hxx2
-rw-r--r--src/input/plugins/SmbclientInputPlugin.cxx6
-rw-r--r--src/input/plugins/SmbclientInputPlugin.hxx2
-rw-r--r--src/lib/expat/ExpatParser.cxx2
-rw-r--r--src/lib/expat/ExpatParser.hxx5
-rw-r--r--src/lib/ffmpeg/Buffer.hxx73
-rw-r--r--src/lib/ffmpeg/Domain.cxx2
-rw-r--r--src/lib/ffmpeg/Domain.hxx2
-rw-r--r--src/lib/ffmpeg/Error.cxx2
-rw-r--r--src/lib/ffmpeg/Error.hxx2
-rw-r--r--src/lib/ffmpeg/Init.cxx38
-rw-r--r--src/lib/ffmpeg/Init.hxx (renamed from src/tag/TagSettings.c)13
-rw-r--r--src/lib/ffmpeg/LogCallback.cxx66
-rw-r--r--src/lib/ffmpeg/LogCallback.hxx30
-rw-r--r--src/lib/ffmpeg/LogError.cxx45
-rw-r--r--src/lib/ffmpeg/LogError.hxx29
-rw-r--r--src/lib/ffmpeg/Time.hxx110
-rw-r--r--src/lib/icu/Collate.cxx151
-rw-r--r--src/lib/icu/Collate.hxx5
-rw-r--r--src/lib/icu/Converter.cxx163
-rw-r--r--src/lib/icu/Converter.hxx97
-rw-r--r--src/lib/icu/Error.cxx2
-rw-r--r--src/lib/icu/Error.hxx2
-rw-r--r--src/lib/icu/Init.cxx2
-rw-r--r--src/lib/icu/Init.hxx2
-rw-r--r--src/lib/icu/Util.cxx74
-rw-r--r--src/lib/icu/Util.hxx45
-rw-r--r--src/lib/icu/Win32.cxx60
-rw-r--r--src/lib/icu/Win32.hxx38
-rw-r--r--src/lib/nfs/Base.cxx2
-rw-r--r--src/lib/nfs/Base.hxx2
-rw-r--r--src/lib/nfs/Blocking.cxx2
-rw-r--r--src/lib/nfs/Blocking.hxx2
-rw-r--r--src/lib/nfs/Callback.hxx2
-rw-r--r--src/lib/nfs/Cancellable.hxx2
-rw-r--r--src/lib/nfs/Connection.cxx2
-rw-r--r--src/lib/nfs/Connection.hxx2
-rw-r--r--src/lib/nfs/Domain.cxx2
-rw-r--r--src/lib/nfs/Domain.hxx2
-rw-r--r--src/lib/nfs/FileReader.cxx2
-rw-r--r--src/lib/nfs/FileReader.hxx2
-rw-r--r--src/lib/nfs/Glue.cxx2
-rw-r--r--src/lib/nfs/Glue.hxx2
-rw-r--r--src/lib/nfs/Lease.hxx2
-rw-r--r--src/lib/nfs/Manager.cxx11
-rw-r--r--src/lib/nfs/Manager.hxx2
-rw-r--r--src/lib/pulse/Domain.cxx24
-rw-r--r--src/lib/pulse/Domain.hxx (renamed from src/tag/TagSettings.h)12
-rw-r--r--src/lib/pulse/Error.cxx33
-rw-r--r--src/lib/pulse/Error.hxx29
-rw-r--r--src/lib/pulse/LogError.cxx33
-rw-r--r--src/lib/pulse/LogError.hxx28
-rw-r--r--src/lib/smbclient/Domain.cxx2
-rw-r--r--src/lib/smbclient/Domain.hxx2
-rw-r--r--src/lib/smbclient/Init.cxx2
-rw-r--r--src/lib/smbclient/Init.hxx2
-rw-r--r--src/lib/smbclient/Mutex.cxx2
-rw-r--r--src/lib/smbclient/Mutex.hxx2
-rw-r--r--src/lib/sqlite/Domain.cxx24
-rw-r--r--src/lib/sqlite/Domain.hxx27
-rw-r--r--src/lib/sqlite/Util.hxx188
-rw-r--r--src/lib/upnp/Action.hxx2
-rw-r--r--src/lib/upnp/Callback.hxx2
-rw-r--r--src/lib/upnp/ClientInit.cxx2
-rw-r--r--src/lib/upnp/ClientInit.hxx2
-rw-r--r--src/lib/upnp/ContentDirectoryService.cxx2
-rw-r--r--src/lib/upnp/ContentDirectoryService.hxx5
-rw-r--r--src/lib/upnp/Device.cxx2
-rw-r--r--src/lib/upnp/Device.hxx2
-rw-r--r--src/lib/upnp/Discovery.cxx59
-rw-r--r--src/lib/upnp/Discovery.hxx29
-rw-r--r--src/lib/upnp/Domain.cxx2
-rw-r--r--src/lib/upnp/Domain.hxx2
-rw-r--r--src/lib/upnp/Init.cxx2
-rw-r--r--src/lib/upnp/Init.hxx2
-rw-r--r--src/lib/upnp/Util.cxx2
-rw-r--r--src/lib/upnp/Util.hxx2
-rw-r--r--src/lib/upnp/WorkQueue.hxx9
-rw-r--r--src/lib/zlib/Domain.cxx2
-rw-r--r--src/lib/zlib/Domain.hxx2
-rw-r--r--src/ls.cxx21
-rw-r--r--src/ls.hxx6
-rw-r--r--src/mixer/Listener.hxx2
-rw-r--r--src/mixer/MixerAll.cxx5
-rw-r--r--src/mixer/MixerControl.cxx6
-rw-r--r--src/mixer/MixerControl.hxx8
-rw-r--r--src/mixer/MixerInternal.hxx2
-rw-r--r--src/mixer/MixerList.hxx4
-rw-r--r--src/mixer/MixerPlugin.hxx6
-rw-r--r--src/mixer/MixerType.cxx14
-rw-r--r--src/mixer/MixerType.hxx25
-rw-r--r--src/mixer/Volume.cxx2
-rw-r--r--src/mixer/Volume.hxx4
-rw-r--r--src/mixer/plugins/AlsaMixerPlugin.cxx16
-rw-r--r--src/mixer/plugins/HaikuMixerPlugin.cxx73
-rw-r--r--src/mixer/plugins/NullMixerPlugin.cxx67
-rw-r--r--src/mixer/plugins/OssMixerPlugin.cxx16
-rw-r--r--src/mixer/plugins/PulseMixerPlugin.cxx30
-rw-r--r--src/mixer/plugins/PulseMixerPlugin.hxx2
-rw-r--r--src/mixer/plugins/RoarMixerPlugin.cxx4
-rw-r--r--src/mixer/plugins/SoftwareMixerPlugin.cxx8
-rw-r--r--src/mixer/plugins/SoftwareMixerPlugin.hxx2
-rw-r--r--src/mixer/plugins/WinmmMixerPlugin.cxx4
-rw-r--r--src/neighbor/Explorer.hxx2
-rw-r--r--src/neighbor/Glue.cxx18
-rw-r--r--src/neighbor/Glue.hxx2
-rw-r--r--src/neighbor/Info.hxx2
-rw-r--r--src/neighbor/Listener.hxx2
-rw-r--r--src/neighbor/NeighborPlugin.hxx6
-rw-r--r--src/neighbor/Registry.cxx4
-rw-r--r--src/neighbor/Registry.hxx2
-rw-r--r--src/neighbor/plugins/SmbclientNeighborPlugin.cxx6
-rw-r--r--src/neighbor/plugins/SmbclientNeighborPlugin.hxx2
-rw-r--r--src/neighbor/plugins/UpnpNeighborPlugin.cxx6
-rw-r--r--src/neighbor/plugins/UpnpNeighborPlugin.hxx2
-rw-r--r--src/net/AllocatedSocketAddress.cxx85
-rw-r--r--src/net/AllocatedSocketAddress.hxx151
-rw-r--r--src/net/Features.hxx27
-rw-r--r--src/net/Resolver.cxx (renamed from src/system/Resolver.cxx)78
-rw-r--r--src/net/Resolver.hxx (renamed from src/system/Resolver.hxx)19
-rw-r--r--src/net/SocketAddress.cxx38
-rw-r--r--src/net/SocketAddress.hxx103
-rw-r--r--src/net/SocketError.cxx (renamed from src/system/SocketError.cxx)27
-rw-r--r--src/net/SocketError.hxx (renamed from src/system/SocketError.hxx)2
-rw-r--r--src/net/SocketUtil.cxx (renamed from src/system/SocketUtil.cxx)18
-rw-r--r--src/net/SocketUtil.hxx (renamed from src/system/SocketUtil.hxx)9
-rw-r--r--src/net/StaticSocketAddress.cxx43
-rw-r--r--src/net/StaticSocketAddress.hxx104
-rw-r--r--src/net/ToString.cxx152
-rw-r--r--src/net/ToString.hxx48
-rw-r--r--src/notify.cxx2
-rw-r--r--src/notify.hxx4
-rw-r--r--src/open.h2
-rw-r--r--src/output/Domain.cxx2
-rw-r--r--src/output/Domain.hxx2
-rw-r--r--src/output/Finish.cxx2
-rw-r--r--src/output/Init.cxx79
-rw-r--r--src/output/Internal.hxx67
-rw-r--r--src/output/MultipleOutputs.cxx18
-rw-r--r--src/output/MultipleOutputs.hxx4
-rw-r--r--src/output/OutputAPI.hxx4
-rw-r--r--src/output/OutputCommand.cxx4
-rw-r--r--src/output/OutputCommand.hxx2
-rw-r--r--src/output/OutputControl.cxx28
-rw-r--r--src/output/OutputControl.hxx2
-rw-r--r--src/output/OutputPlugin.cxx8
-rw-r--r--src/output/OutputPlugin.hxx15
-rw-r--r--src/output/OutputPrint.cxx15
-rw-r--r--src/output/OutputPrint.hxx6
-rw-r--r--src/output/OutputState.cxx2
-rw-r--r--src/output/OutputState.hxx4
-rw-r--r--src/output/OutputThread.cxx60
-rw-r--r--src/output/Registry.cxx16
-rw-r--r--src/output/Registry.hxx2
-rw-r--r--src/output/Timer.cxx2
-rw-r--r--src/output/Timer.hxx2
-rw-r--r--src/output/Wrapper.hxx101
-rw-r--r--src/output/plugins/AlsaOutputPlugin.cxx301
-rw-r--r--src/output/plugins/AlsaOutputPlugin.hxx2
-rw-r--r--src/output/plugins/AoOutputPlugin.cxx44
-rw-r--r--src/output/plugins/AoOutputPlugin.hxx2
-rw-r--r--src/output/plugins/FifoOutputPlugin.cxx150
-rw-r--r--src/output/plugins/FifoOutputPlugin.hxx2
-rw-r--r--src/output/plugins/HaikuOutputPlugin.cxx532
-rw-r--r--src/output/plugins/HaikuOutputPlugin.hxx34
-rw-r--r--src/output/plugins/JackOutputPlugin.cxx728
-rw-r--r--src/output/plugins/JackOutputPlugin.hxx2
-rw-r--r--src/output/plugins/NullOutputPlugin.cxx133
-rw-r--r--src/output/plugins/NullOutputPlugin.hxx2
-rw-r--r--src/output/plugins/OSXOutputPlugin.cxx28
-rw-r--r--src/output/plugins/OSXOutputPlugin.hxx2
-rw-r--r--src/output/plugins/OpenALOutputPlugin.cxx245
-rw-r--r--src/output/plugins/OpenALOutputPlugin.hxx2
-rw-r--r--src/output/plugins/OssOutputPlugin.cxx251
-rw-r--r--src/output/plugins/OssOutputPlugin.hxx2
-rw-r--r--src/output/plugins/PipeOutputPlugin.cxx100
-rw-r--r--src/output/plugins/PipeOutputPlugin.hxx2
-rw-r--r--src/output/plugins/PulseOutputPlugin.cxx882
-rw-r--r--src/output/plugins/PulseOutputPlugin.hxx4
-rw-r--r--src/output/plugins/RecorderOutputPlugin.cxx352
-rw-r--r--src/output/plugins/RecorderOutputPlugin.hxx2
-rw-r--r--src/output/plugins/RoarOutputPlugin.cxx80
-rw-r--r--src/output/plugins/RoarOutputPlugin.hxx2
-rw-r--r--src/output/plugins/ShoutOutputPlugin.cxx71
-rw-r--r--src/output/plugins/ShoutOutputPlugin.hxx2
-rw-r--r--src/output/plugins/SolarisOutputPlugin.cxx12
-rw-r--r--src/output/plugins/SolarisOutputPlugin.hxx2
-rw-r--r--src/output/plugins/WinmmOutputPlugin.cxx52
-rw-r--r--src/output/plugins/WinmmOutputPlugin.hxx2
-rw-r--r--src/output/plugins/httpd/HttpdClient.cxx4
-rw-r--r--src/output/plugins/httpd/HttpdClient.hxx10
-rw-r--r--src/output/plugins/httpd/HttpdInternal.hxx33
-rw-r--r--src/output/plugins/httpd/HttpdOutputPlugin.cxx80
-rw-r--r--src/output/plugins/httpd/HttpdOutputPlugin.hxx2
-rw-r--r--src/output/plugins/httpd/IcyMetaDataServer.cxx58
-rw-r--r--src/output/plugins/httpd/IcyMetaDataServer.hxx2
-rw-r--r--src/output/plugins/httpd/Page.cxx2
-rw-r--r--src/output/plugins/httpd/Page.hxx2
-rw-r--r--src/output/plugins/sles/SlesOutputPlugin.cxx108
-rw-r--r--src/output/plugins/sles/SlesOutputPlugin.hxx2
-rw-r--r--src/pcm/ChannelsConverter.cxx2
-rw-r--r--src/pcm/ChannelsConverter.hxx2
-rw-r--r--src/pcm/ConfiguredResampler.cxx141
-rw-r--r--src/pcm/ConfiguredResampler.hxx2
-rw-r--r--src/pcm/Domain.cxx2
-rw-r--r--src/pcm/Domain.hxx2
-rw-r--r--src/pcm/FallbackResampler.cxx2
-rw-r--r--src/pcm/FallbackResampler.hxx2
-rw-r--r--src/pcm/FloatConvert.hxx2
-rw-r--r--src/pcm/FormatConverter.cxx2
-rw-r--r--src/pcm/FormatConverter.hxx2
-rw-r--r--src/pcm/GlueResampler.cxx2
-rw-r--r--src/pcm/GlueResampler.hxx2
-rw-r--r--src/pcm/Interleave.cxx115
-rw-r--r--src/pcm/Interleave.hxx54
-rw-r--r--src/pcm/LibsamplerateResampler.cxx6
-rw-r--r--src/pcm/LibsamplerateResampler.hxx6
-rw-r--r--src/pcm/Neon.hxx2
-rw-r--r--src/pcm/PcmBuffer.cxx2
-rw-r--r--src/pcm/PcmBuffer.hxx2
-rw-r--r--src/pcm/PcmChannels.cxx2
-rw-r--r--src/pcm/PcmChannels.hxx2
-rw-r--r--src/pcm/PcmConvert.cxx2
-rw-r--r--src/pcm/PcmConvert.hxx7
-rw-r--r--src/pcm/PcmDither.cxx2
-rw-r--r--src/pcm/PcmDither.hxx8
-rw-r--r--src/pcm/PcmDop.cxx2
-rw-r--r--src/pcm/PcmDop.hxx2
-rw-r--r--src/pcm/PcmDsd.cxx2
-rw-r--r--src/pcm/PcmDsd.hxx2
-rw-r--r--src/pcm/PcmExport.cxx2
-rw-r--r--src/pcm/PcmExport.hxx4
-rw-r--r--src/pcm/PcmFormat.cxx2
-rw-r--r--src/pcm/PcmFormat.hxx18
-rw-r--r--src/pcm/PcmMix.cxx2
-rw-r--r--src/pcm/PcmMix.hxx2
-rw-r--r--src/pcm/PcmPack.cxx2
-rw-r--r--src/pcm/PcmPack.hxx4
-rw-r--r--src/pcm/PcmPrng.hxx2
-rw-r--r--src/pcm/PcmUtils.hxx2
-rw-r--r--src/pcm/Resampler.hxx7
-rw-r--r--src/pcm/ShiftConvert.hxx2
-rw-r--r--src/pcm/SoxrResampler.cxx98
-rw-r--r--src/pcm/SoxrResampler.hxx5
-rw-r--r--src/pcm/Traits.hxx2
-rw-r--r--src/pcm/Volume.cxx2
-rw-r--r--src/pcm/Volume.hxx2
-rw-r--r--src/player/Control.cxx (renamed from src/PlayerControl.cxx)4
-rw-r--r--src/player/Control.hxx (renamed from src/PlayerControl.hxx)2
-rw-r--r--src/player/CrossFade.cxx (renamed from src/CrossFade.cxx)2
-rw-r--r--src/player/CrossFade.hxx (renamed from src/CrossFade.hxx)2
-rw-r--r--src/player/Listener.hxx (renamed from src/PlayerListener.hxx)2
-rw-r--r--src/player/Thread.cxx (renamed from src/PlayerThread.cxx)8
-rw-r--r--src/player/Thread.hxx (renamed from src/PlayerThread.hxx)4
-rw-r--r--src/playlist/CloseSongEnumerator.cxx2
-rw-r--r--src/playlist/CloseSongEnumerator.hxx2
-rw-r--r--src/playlist/MemorySongEnumerator.cxx2
-rw-r--r--src/playlist/MemorySongEnumerator.hxx2
-rw-r--r--src/playlist/PlaylistAny.cxx2
-rw-r--r--src/playlist/PlaylistAny.hxx2
-rw-r--r--src/playlist/PlaylistMapper.cxx2
-rw-r--r--src/playlist/PlaylistMapper.hxx2
-rw-r--r--src/playlist/PlaylistPlugin.hxx16
-rw-r--r--src/playlist/PlaylistQueue.cxx2
-rw-r--r--src/playlist/PlaylistQueue.hxx2
-rw-r--r--src/playlist/PlaylistRegistry.cxx23
-rw-r--r--src/playlist/PlaylistRegistry.hxx8
-rw-r--r--src/playlist/PlaylistSong.cxx2
-rw-r--r--src/playlist/PlaylistSong.hxx2
-rw-r--r--src/playlist/PlaylistStream.cxx13
-rw-r--r--src/playlist/PlaylistStream.hxx4
-rw-r--r--src/playlist/Print.cxx23
-rw-r--r--src/playlist/Print.hxx11
-rw-r--r--src/playlist/SongEnumerator.hxx2
-rw-r--r--src/playlist/cue/CueParser.cxx10
-rw-r--r--src/playlist/cue/CueParser.hxx8
-rw-r--r--src/playlist/plugins/AsxPlaylistPlugin.cxx8
-rw-r--r--src/playlist/plugins/AsxPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/CuePlaylistPlugin.cxx2
-rw-r--r--src/playlist/plugins/CuePlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx6
-rw-r--r--src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/ExtM3uPlaylistPlugin.cxx2
-rw-r--r--src/playlist/plugins/ExtM3uPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/FlacPlaylistPlugin.cxx135
-rw-r--r--src/playlist/plugins/FlacPlaylistPlugin.hxx25
-rw-r--r--src/playlist/plugins/M3uPlaylistPlugin.cxx2
-rw-r--r--src/playlist/plugins/M3uPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/PlsPlaylistPlugin.cxx198
-rw-r--r--src/playlist/plugins/PlsPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/RssPlaylistPlugin.cxx8
-rw-r--r--src/playlist/plugins/RssPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/SoundCloudPlaylistPlugin.cxx110
-rw-r--r--src/playlist/plugins/SoundCloudPlaylistPlugin.hxx2
-rw-r--r--src/playlist/plugins/XspfPlaylistPlugin.cxx8
-rw-r--r--src/playlist/plugins/XspfPlaylistPlugin.hxx2
-rw-r--r--src/poison.h2
-rw-r--r--src/protocol/Ack.cxx2
-rw-r--r--src/protocol/Ack.hxx2
-rw-r--r--src/protocol/ArgParser.cxx102
-rw-r--r--src/protocol/ArgParser.hxx44
-rw-r--r--src/protocol/Result.cxx30
-rw-r--r--src/protocol/Result.hxx17
-rw-r--r--src/queue/IdTable.hxx2
-rw-r--r--src/queue/Playlist.cxx86
-rw-r--r--src/queue/Playlist.hxx33
-rw-r--r--src/queue/PlaylistControl.cxx4
-rw-r--r--src/queue/PlaylistEdit.cxx4
-rw-r--r--src/queue/PlaylistState.cxx9
-rw-r--r--src/queue/PlaylistState.hxx2
-rw-r--r--src/queue/PlaylistTag.cxx2
-rw-r--r--src/queue/PlaylistUpdate.cxx2
-rw-r--r--src/queue/Queue.cxx7
-rw-r--r--src/queue/Queue.hxx5
-rw-r--r--src/queue/QueuePrint.cxx38
-rw-r--r--src/queue/QueuePrint.hxx15
-rw-r--r--src/queue/QueueSave.cxx2
-rw-r--r--src/queue/QueueSave.hxx2
-rw-r--r--src/sticker/Match.hxx49
-rw-r--r--src/sticker/SongSticker.cxx43
-rw-r--r--src/sticker/SongSticker.hxx24
-rw-r--r--src/sticker/StickerDatabase.cxx398
-rw-r--r--src/sticker/StickerDatabase.hxx38
-rw-r--r--src/sticker/StickerPrint.cxx16
-rw-r--r--src/sticker/StickerPrint.hxx10
-rw-r--r--src/storage/CompositeStorage.cxx14
-rw-r--r--src/storage/CompositeStorage.hxx4
-rw-r--r--src/storage/Configured.cxx8
-rw-r--r--src/storage/Configured.hxx2
-rw-r--r--src/storage/FileInfo.hxx4
-rw-r--r--src/storage/MemoryDirectoryReader.cxx5
-rw-r--r--src/storage/MemoryDirectoryReader.hxx7
-rw-r--r--src/storage/Registry.cxx2
-rw-r--r--src/storage/Registry.hxx2
-rw-r--r--src/storage/StorageInterface.cxx2
-rw-r--r--src/storage/StorageInterface.hxx10
-rw-r--r--src/storage/StoragePlugin.hxx2
-rw-r--r--src/storage/plugins/LocalStorage.cxx50
-rw-r--r--src/storage/plugins/LocalStorage.hxx2
-rw-r--r--src/storage/plugins/NfsStorage.cxx26
-rw-r--r--src/storage/plugins/NfsStorage.hxx2
-rw-r--r--src/storage/plugins/SmbclientStorage.cxx20
-rw-r--r--src/storage/plugins/SmbclientStorage.hxx2
-rw-r--r--src/system/ByteOrder.hxx44
-rw-r--r--src/system/Clock.cxx2
-rw-r--r--src/system/Clock.hxx2
-rw-r--r--src/system/EPollFD.cxx2
-rw-r--r--src/system/EPollFD.hxx2
-rw-r--r--src/system/EventFD.cxx23
-rw-r--r--src/system/EventFD.hxx11
-rw-r--r--src/system/EventPipe.cxx2
-rw-r--r--src/system/EventPipe.hxx2
-rw-r--r--src/system/FatalError.cxx29
-rw-r--r--src/system/FatalError.hxx14
-rw-r--r--src/system/FileDescriptor.cxx215
-rw-r--r--src/system/FileDescriptor.hxx176
-rw-r--r--src/system/PeriodClock.hxx2
-rw-r--r--src/system/SignalFD.cxx16
-rw-r--r--src/system/SignalFD.hxx7
-rw-r--r--src/system/fd_util.c146
-rw-r--r--src/system/fd_util.h72
-rw-r--r--src/tag/Aiff.cxx2
-rw-r--r--src/tag/Aiff.hxx2
-rw-r--r--src/tag/ApeLoader.cxx7
-rw-r--r--src/tag/ApeLoader.hxx6
-rw-r--r--src/tag/ApeReplayGain.cxx18
-rw-r--r--src/tag/ApeReplayGain.hxx2
-rw-r--r--src/tag/ApeTag.cxx19
-rw-r--r--src/tag/ApeTag.hxx2
-rw-r--r--src/tag/Format.cxx133
-rw-r--r--src/tag/Format.hxx32
-rw-r--r--src/tag/Mask.hxx27
-rw-r--r--src/tag/MixRamp.cxx2
-rw-r--r--src/tag/MixRamp.hxx2
-rw-r--r--src/tag/ReplayGain.cxx2
-rw-r--r--src/tag/ReplayGain.hxx2
-rw-r--r--src/tag/Riff.cxx2
-rw-r--r--src/tag/Riff.hxx2
-rw-r--r--src/tag/Set.cxx20
-rw-r--r--src/tag/Set.hxx10
-rw-r--r--src/tag/Settings.cxx22
-rw-r--r--src/tag/Settings.hxx45
-rw-r--r--src/tag/Tag.cxx3
-rw-r--r--src/tag/Tag.hxx2
-rw-r--r--src/tag/TagBuilder.cxx38
-rw-r--r--src/tag/TagBuilder.hxx9
-rw-r--r--src/tag/TagConfig.cxx10
-rw-r--r--src/tag/TagConfig.hxx2
-rw-r--r--src/tag/TagHandler.cxx17
-rw-r--r--src/tag/TagHandler.hxx2
-rw-r--r--src/tag/TagId3.cxx65
-rw-r--r--src/tag/TagId3.hxx4
-rw-r--r--src/tag/TagItem.hxx2
-rw-r--r--src/tag/TagNames.c2
-rw-r--r--src/tag/TagPool.cxx46
-rw-r--r--src/tag/TagPool.hxx5
-rw-r--r--src/tag/TagRva2.cxx44
-rw-r--r--src/tag/TagRva2.hxx4
-rw-r--r--src/tag/TagString.cxx49
-rw-r--r--src/tag/TagString.hxx5
-rw-r--r--src/tag/TagTable.cxx2
-rw-r--r--src/tag/TagTable.hxx2
-rw-r--r--src/tag/TagType.h2
-rw-r--r--src/tag/VorbisComment.cxx2
-rw-r--r--src/tag/VorbisComment.hxx2
-rw-r--r--src/thread/Cond.hxx4
-rw-r--r--src/thread/Id.hxx2
-rw-r--r--src/thread/Mutex.hxx4
-rw-r--r--src/thread/Name.hxx2
-rw-r--r--src/thread/PosixCond.hxx16
-rw-r--r--src/thread/PosixMutex.hxx16
-rw-r--r--src/thread/Slack.hxx2
-rw-r--r--src/thread/Thread.cxx2
-rw-r--r--src/thread/Thread.hxx2
-rw-r--r--src/unix/Daemon.cxx23
-rw-r--r--src/unix/Daemon.hxx18
-rw-r--r--src/unix/PidFile.hxx61
-rw-r--r--src/unix/SignalHandlers.cxx2
-rw-r--r--src/unix/SignalHandlers.hxx2
-rw-r--r--src/util/ASCII.hxx4
-rw-r--r--src/util/Alloc.cxx86
-rw-r--r--src/util/Alloc.hxx21
-rw-r--r--src/util/AllocatedString.cxx38
-rw-r--r--src/util/AllocatedString.hxx126
-rw-r--r--src/util/ByteReverse.cxx2
-rw-r--r--src/util/ByteReverse.hxx2
-rw-r--r--src/util/Cast.hxx4
-rw-r--r--src/util/CharUtil.hxx2
-rw-r--r--src/util/ConstBuffer.hxx14
-rw-r--r--src/util/DeleteDisposer.hxx44
-rw-r--r--src/util/DivideString.cxx48
-rw-r--r--src/util/DivideString.hxx75
-rw-r--r--src/util/DynamicFifoBuffer.hxx6
-rw-r--r--src/util/Error.cxx8
-rw-r--r--src/util/FormatString.cxx2
-rw-r--r--src/util/FormatString.hxx2
-rw-r--r--src/util/LazyRandomEngine.cxx2
-rw-r--r--src/util/LazyRandomEngine.hxx2
-rw-r--r--src/util/Manual.hxx37
-rw-r--r--src/util/OptionDef.hxx2
-rw-r--r--src/util/OptionParser.cxx2
-rw-r--r--src/util/OptionParser.hxx2
-rw-r--r--src/util/PeakBuffer.cxx2
-rw-r--r--src/util/PeakBuffer.hxx2
-rw-r--r--src/util/RefCount.hxx2
-rw-r--r--src/util/SliceBuffer.hxx2
-rw-r--r--src/util/SplitString.cxx44
-rw-r--r--src/util/SplitString.hxx58
-rw-r--r--src/util/StringAPI.hxx148
-rw-r--r--src/util/StringPointer.hxx64
-rw-r--r--src/util/StringUtil.cxx113
-rw-r--r--src/util/StringUtil.hxx71
-rw-r--r--src/util/StringView.cxx45
-rw-r--r--src/util/StringView.hxx118
-rw-r--r--src/util/Tokenizer.hxx8
-rw-r--r--src/util/UriUtil.cxx2
-rw-r--r--src/util/UriUtil.hxx2
-rw-r--r--src/util/VarSize.hxx2
-rw-r--r--src/util/WStringAPI.hxx147
-rw-r--r--src/util/WStringUtil.cxx73
-rw-r--r--src/util/WStringUtil.hxx52
-rw-r--r--src/util/bit_reverse.c2
-rw-r--r--src/util/bit_reverse.h2
-rw-r--r--src/util/format.c259
-rw-r--r--src/util/format.h51
-rw-r--r--src/win32/Win32Main.cxx35
-rw-r--r--src/win32/mpd.icobin353118 -> 0 bytes
-rw-r--r--src/win32/mpd_win32_rc.rc.in34
-rw-r--r--src/zeroconf/AvahiPoll.cxx2
-rw-r--r--src/zeroconf/AvahiPoll.hxx2
-rw-r--r--src/zeroconf/ZeroconfAvahi.cxx2
-rw-r--r--src/zeroconf/ZeroconfAvahi.hxx2
-rw-r--r--src/zeroconf/ZeroconfBonjour.cxx2
-rw-r--r--src/zeroconf/ZeroconfBonjour.hxx2
-rw-r--r--src/zeroconf/ZeroconfGlue.cxx7
-rw-r--r--src/zeroconf/ZeroconfGlue.hxx2
-rw-r--r--src/zeroconf/ZeroconfInternal.hxx2
1017 files changed, 15889 insertions, 8779 deletions
diff --git a/src/AudioConfig.cxx b/src/AudioConfig.cxx
index d54f59e17..8ee17f301 100644
--- a/src/AudioConfig.cxx
+++ b/src/AudioConfig.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include "AudioConfig.hxx"
#include "AudioFormat.hxx"
#include "AudioParser.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "util/Error.hxx"
@@ -39,7 +39,7 @@ getOutputAudioFormat(AudioFormat inAudioFormat)
void initAudioConfig(void)
{
- const struct config_param *param = config_get_param(CONF_AUDIO_OUTPUT_FORMAT);
+ const struct config_param *param = config_get_param(ConfigOption::AUDIO_OUTPUT_FORMAT);
if (param == nullptr)
return;
diff --git a/src/AudioConfig.hxx b/src/AudioConfig.hxx
index 471e60e51..1056eb8ff 100644
--- a/src/AudioConfig.hxx
+++ b/src/AudioConfig.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@ AudioFormat
getOutputAudioFormat(AudioFormat inFormat);
/* make sure initPlayerData is called before this function!! */
-void initAudioConfig(void);
+void
+initAudioConfig();
#endif
diff --git a/src/AudioFormat.cxx b/src/AudioFormat.cxx
index edfb9d8fe..fb30dd93d 100644
--- a/src/AudioFormat.cxx
+++ b/src/AudioFormat.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/AudioFormat.hxx b/src/AudioFormat.hxx
index 0937ab8ae..a00e761a8 100644
--- a/src/AudioFormat.hxx
+++ b/src/AudioFormat.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -99,8 +99,8 @@ struct AudioFormat {
}
/**
- * Clears the #audio_format object, i.e. sets all attributes to an
- * undefined (invalid) value.
+ * Clears the object, i.e. sets all attributes to an undefined
+ * (invalid) value.
*/
void Clear() {
sample_rate = 0;
@@ -185,8 +185,6 @@ audio_valid_sample_rate(unsigned sample_rate)
/**
* Checks whether the sample format is valid.
- *
- * @param bits the number of significant bits per sample
*/
static inline bool
audio_valid_sample_format(SampleFormat format)
@@ -289,10 +287,10 @@ AudioFormat::GetTimeToSize() const
}
/**
- * Renders a #sample_format enum into a string, e.g. for printing it
+ * Renders a #SampleFormat enum into a string, e.g. for printing it
* in a log file.
*
- * @param format a #sample_format enum value
+ * @param format a #SampleFormat enum value
* @return the string
*/
gcc_pure gcc_malloc
@@ -300,12 +298,12 @@ const char *
sample_format_to_string(SampleFormat format);
/**
- * Renders the #audio_format object into a string, e.g. for printing
+ * Renders the #AudioFormat object into a string, e.g. for printing
* it in a log file.
*
- * @param af the #audio_format object
+ * @param af the #AudioFormat object
* @param s a buffer to print into
- * @return the string, or nullptr if the #audio_format object is invalid
+ * @return the string, or nullptr if the #AudioFormat object is invalid
*/
gcc_pure gcc_malloc
const char *
diff --git a/src/AudioParser.cxx b/src/AudioParser.cxx
index 74bb04abc..b7051b4b2 100644
--- a/src/AudioParser.cxx
+++ b/src/AudioParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/AudioParser.hxx b/src/AudioParser.hxx
index 07ad7cb4a..247d0d6f0 100644
--- a/src/AudioParser.hxx
+++ b/src/AudioParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,12 +30,12 @@ class Error;
/**
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
- * #audio_format.
+ * #AudioFormat.
*
* @param dest the destination #audio_format struct
* @param src the input string
* @param mask if true, then "*" is allowed for any number of items
- * @param error_r location to store the error occurring, or NULL to
+ * @param error location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/
diff --git a/src/BulkEdit.hxx b/src/BulkEdit.hxx
index 422dc4f38..89c148f0c 100644
--- a/src/BulkEdit.hxx
+++ b/src/BulkEdit.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/CheckAudioFormat.cxx b/src/CheckAudioFormat.cxx
index 03e67e07e..3f4176dc1 100644
--- a/src/CheckAudioFormat.cxx
+++ b/src/CheckAudioFormat.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/CheckAudioFormat.hxx b/src/CheckAudioFormat.hxx
index 67bd88a61..25d82cd5b 100644
--- a/src/CheckAudioFormat.hxx
+++ b/src/CheckAudioFormat.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Chrono.hxx b/src/Chrono.hxx
index cc87c5ba1..d71202841 100644
--- a/src/Chrono.hxx
+++ b/src/Chrono.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#include <utility>
#include <cstdint>
-#if defined(__GNUC__) && !GCC_CHECK_VERSION(4,7) && !defined(__clang__)
+#if GCC_OLDER_THAN(4,7)
/* std::chrono::duration operators are "constexpr" since gcc 4.7 */
#define chrono_constexpr gcc_pure
#else
diff --git a/src/CommandLine.cxx b/src/CommandLine.cxx
index c6e9c69c5..b59a39e40 100644
--- a/src/CommandLine.cxx
+++ b/src/CommandLine.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
#include "fs/StandardDirectory.hxx"
+#include "util/Macros.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/OptionDef.hxx"
@@ -66,12 +67,12 @@
#include <stdlib.h>
#ifdef WIN32
-#define CONFIG_FILE_LOCATION "mpd\\mpd.conf"
-#define APP_CONFIG_FILE_LOCATION "conf\\mpd.conf"
+#define CONFIG_FILE_LOCATION PATH_LITERAL("mpd\\mpd.conf")
+#define APP_CONFIG_FILE_LOCATION PATH_LITERAL("conf\\mpd.conf")
#else
-#define USER_CONFIG_FILE_LOCATION1 ".mpdconf"
-#define USER_CONFIG_FILE_LOCATION2 ".mpd/mpd.conf"
-#define USER_CONFIG_FILE_LOCATION_XDG "mpd/mpd.conf"
+#define USER_CONFIG_FILE_LOCATION1 PATH_LITERAL(".mpdconf")
+#define USER_CONFIG_FILE_LOCATION2 PATH_LITERAL(".mpd/mpd.conf")
+#define USER_CONFIG_FILE_LOCATION_XDG PATH_LITERAL("mpd/mpd.conf")
#endif
static constexpr OptionDef opt_kill(
@@ -98,40 +99,44 @@ static constexpr Domain cmdline_domain("cmdline");
gcc_noreturn
static void version(void)
{
- puts("Music Player Daemon " VERSION
+ printf("Music Player Daemon " VERSION
#ifdef GIT_COMMIT
- " (" GIT_COMMIT ")"
+ " (" GIT_COMMIT ")"
#endif
- "\n"
- "\n"
- "Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
- "Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\n"
- "This is free software; see the source for copying conditions. There is NO\n"
- "warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
+ "\n"
+ "\n"
+ "Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
+ "Copyright (C) 2008-2015 Max Kellermann <max@duempel.org>\n"
+ "This is free software; see the source for copying conditions. There is NO\n"
+ "warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
#ifdef ENABLE_DATABASE
- puts("\n"
- "Database plugins:");
+ "\n"
+ "Database plugins:\n");
for (auto i = database_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name);
- puts("\n\n"
- "Storage plugins:");
+ printf("\n\n"
+ "Storage plugins:\n");
for (auto i = storage_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name);
+
+ printf("\n"
#endif
#ifdef ENABLE_NEIGHBOR_PLUGINS
- puts("\n\n"
- "Neighbor plugins:");
+ "\n"
+ "Neighbor plugins:\n");
for (auto i = neighbor_plugins; *i != nullptr; ++i)
printf(" %s", (*i)->name);
+
+ printf("\n"
#endif
- puts("\n\n"
- "Decoders plugins:");
+ "\n"
+ "Decoders plugins:\n");
decoder_plugins_for_each([](const DecoderPlugin &plugin){
printf(" [%s]", plugin.name);
@@ -141,26 +146,39 @@ static void version(void)
for (; *suffixes != nullptr; ++suffixes)
printf(" %s", *suffixes);
- puts("");
+ printf("\n");
});
- puts("\n"
- "Output plugins:");
+ printf("\n"
+ "Filters:\n"
+#ifdef ENABLE_LIBSAMPLERATE
+ " libsamplerate"
+#endif
+#ifdef ENABLE_SOXR
+ " soxr"
+#endif
+ "\n\n"
+ "Tag plugins:\n"
+#ifdef ENABLE_ID3TAG
+ " id3tag"
+#endif
+ "\n\n"
+ "Output plugins:\n");
audio_output_plugins_for_each(plugin)
printf(" %s", plugin->name);
- puts("");
+ printf("\n"
#ifdef ENABLE_ENCODER
- puts("\n"
- "Encoder plugins:");
+ "\n"
+ "Encoder plugins:\n");
encoder_plugins_for_each(plugin)
printf(" %s", plugin->name);
- puts("");
+ printf("\n"
#endif
#ifdef ENABLE_ARCHIVE
- puts("\n"
- "Archive plugins:");
+ "\n"
+ "Archive plugins:\n");
archive_plugins_for_each(plugin) {
printf(" [%s]", plugin->name);
@@ -169,24 +187,57 @@ static void version(void)
for (; *suffixes != nullptr; ++suffixes)
printf(" %s", *suffixes);
- puts("");
+ printf("\n");
}
+
+ printf(""
#endif
- puts("\n"
- "Input plugins:");
+ "\n"
+ "Input plugins:\n");
input_plugins_for_each(plugin)
printf(" %s", plugin->name);
- puts("\n\n"
- "Playlist plugins:");
+ printf("\n\n"
+ "Playlist plugins:\n");
playlist_plugins_for_each(plugin)
printf(" %s", plugin->name);
- puts("\n\n"
- "Protocols:");
+ printf("\n\n"
+ "Protocols:\n");
print_supported_uri_schemes_to_fp(stdout);
+ printf("\n"
+ "Other features:\n"
+#ifdef HAVE_AVAHI
+ " avahi"
+#endif
+#ifdef USE_EPOLL
+ " epoll"
+#endif
+#ifdef HAVE_ICONV
+ " iconv"
+#endif
+#ifdef HAVE_ICU
+ " icu"
+#endif
+#ifdef ENABLE_INOTIFY
+ " inotify"
+#endif
+#ifdef HAVE_IPV6
+ " ipv6"
+#endif
+#ifdef ENABLE_SYSTEMD_DAEMON
+ " systemd"
+#endif
+#ifdef HAVE_TCP
+ " tcp"
+#endif
+#ifdef HAVE_UN
+ " un"
+#endif
+ "\n");
+
exit(EXIT_SUCCESS);
}
@@ -206,12 +257,12 @@ static void PrintOption(const OptionDef &opt)
gcc_noreturn
static void help(void)
{
- puts("Usage:\n"
- " mpd [OPTION...] [path/to/mpd.conf]\n"
- "\n"
- "Music Player Daemon - a daemon for playing music.\n"
- "\n"
- "Options:");
+ printf("Usage:\n"
+ " mpd [OPTION...] [path/to/mpd.conf]\n"
+ "\n"
+ "Music Player Daemon - a daemon for playing music.\n"
+ "\n"
+ "Options:\n");
PrintOption(opt_help);
PrintOption(opt_kill);
@@ -326,7 +377,19 @@ parse_cmdline(int argc, char **argv, struct options *options,
if (config_file != nullptr) {
/* use specified configuration file */
+#ifdef _UNICODE
+ wchar_t buffer[MAX_PATH];
+ auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
+ buffer, ARRAY_SIZE(buffer));
+ if (result <= 0) {
+ error.SetLastError("MultiByteToWideChar() failed");
+ return false;
+ }
+
+ return ReadConfigFile(Path::FromFS(buffer), error);
+#else
return ReadConfigFile(Path::FromFS(config_file), error);
+#endif
}
/* use default configuration file path */
diff --git a/src/CommandLine.hxx b/src/CommandLine.hxx
index d8dedb1fb..38adfdc4d 100644
--- a/src/CommandLine.hxx
+++ b/src/CommandLine.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Compiler.h b/src/Compiler.h
index fea971526..87142fa08 100644
--- a/src/Compiler.h
+++ b/src/Compiler.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,20 @@
#define GCC_VERSION 0
#endif
+/**
+ * Are we building with the specified version of gcc (not clang or any
+ * other compiler) or newer?
+ */
#define GCC_CHECK_VERSION(major, minor) \
- (defined(__GNUC__) && GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
+ (defined(__GNUC__) && !defined(__clang__) && \
+ GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
+
+/**
+ * Are we building with clang (any version) or at least the specified
+ * gcc version?
+ */
+#define CLANG_OR_GCC_VERSION(major, minor) \
+ (defined(__clang__) || GCC_CHECK_VERSION(major, minor))
/**
* Are we building with gcc (not clang or any other compiler) and a
@@ -59,7 +71,7 @@
(defined(__clang__) && \
CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
-#if GCC_CHECK_VERSION(4,0)
+#if CLANG_OR_GCC_VERSION(4,0)
/* GCC 4.x */
@@ -119,7 +131,7 @@
#endif
-#if GCC_CHECK_VERSION(4,3)
+#if CLANG_OR_GCC_VERSION(4,3)
#define gcc_hot __attribute__((hot))
#define gcc_cold __attribute__((cold))
@@ -131,7 +143,7 @@
#endif /* ! GCC_UNUSED >= 40300 */
-#if GCC_CHECK_VERSION(4,6) && !defined(__clang__)
+#if GCC_CHECK_VERSION(4,6)
#define gcc_flatten __attribute__((flatten))
#else
#define gcc_flatten
@@ -140,7 +152,7 @@
#ifndef __cplusplus
/* plain C99 has "restrict" */
#define gcc_restrict restrict
-#elif GCC_CHECK_VERSION(4,0)
+#elif CLANG_OR_GCC_VERSION(4,0)
/* "__restrict__" is a GCC extension for C++ */
#define gcc_restrict __restrict__
#else
@@ -158,7 +170,7 @@
#define final
#endif
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
#define gcc_alignas(T, fallback) alignas(T)
#else
#define gcc_alignas(T, fallback) gcc_aligned(fallback)
diff --git a/src/DetachedSong.cxx b/src/DetachedSong.cxx
index 906e29bba..ca914498b 100644
--- a/src/DetachedSong.cxx
+++ b/src/DetachedSong.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/DetachedSong.hxx b/src/DetachedSong.hxx
index 021b5de29..844283dcf 100644
--- a/src/DetachedSong.hxx
+++ b/src/DetachedSong.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,9 +32,9 @@
struct LightSong;
class Storage;
+class Path;
class DetachedSong {
- friend DetachedSong map_song_detach(const LightSong &song);
friend DetachedSong DatabaseDetachSong(const Storage &db,
const LightSong &song);
@@ -221,6 +221,11 @@ public:
* @return true on success
*/
bool Update();
+
+ /**
+ * Load #tag and #mtime from a local file.
+ */
+ bool LoadFile(Path path);
};
#endif
diff --git a/src/GlobalEvents.cxx b/src/GlobalEvents.cxx
index 9c60f6357..8cbb85861 100644
--- a/src/GlobalEvents.cxx
+++ b/src/GlobalEvents.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/GlobalEvents.hxx b/src/GlobalEvents.hxx
index a9df03724..15ef58a89 100644
--- a/src/GlobalEvents.hxx
+++ b/src/GlobalEvents.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/IOThread.cxx b/src/IOThread.cxx
index e21ede4f3..654433c06 100644
--- a/src/IOThread.cxx
+++ b/src/IOThread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/IOThread.hxx b/src/IOThread.hxx
index f6f5dffec..c7edd67b4 100644
--- a/src/IOThread.hxx
+++ b/src/IOThread.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
class EventLoop;
void
-io_thread_init(void);
+io_thread_init();
void
io_thread_start();
@@ -36,7 +36,7 @@ io_thread_start();
* only.
*/
void
-io_thread_run(void);
+io_thread_run();
/**
* Ask the I/O thread to quit, but does not wait for it. Usually, you
@@ -44,10 +44,10 @@ io_thread_run(void);
* includes this.
*/
void
-io_thread_quit(void);
+io_thread_quit();
void
-io_thread_deinit(void);
+io_thread_deinit();
gcc_const
EventLoop &
@@ -58,6 +58,6 @@ io_thread_get();
*/
gcc_pure
bool
-io_thread_inside(void);
+io_thread_inside();
#endif
diff --git a/src/IcyMetaDataParser.cxx b/src/IcyMetaDataParser.cxx
index 4c13c2c2c..9fb97d4d4 100644
--- a/src/IcyMetaDataParser.cxx
+++ b/src/IcyMetaDataParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,7 @@
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"
#include "util/Domain.hxx"
+#include "util/StringView.hxx"
#include "Log.hxx"
#include <assert.h>
@@ -76,7 +77,7 @@ icy_add_item(TagBuilder &tag, TagType type, const char *value)
}
if (length > 0)
- tag.AddItem(type, value, length);
+ tag.AddItem(type, {value, length});
}
static void
diff --git a/src/IcyMetaDataParser.hxx b/src/IcyMetaDataParser.hxx
index 3075485b2..75aa1a9da 100644
--- a/src/IcyMetaDataParser.hxx
+++ b/src/IcyMetaDataParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Idle.cxx b/src/Idle.cxx
index 0b66065de..ee0e3c3da 100644
--- a/src/Idle.cxx
+++ b/src/Idle.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Idle.hxx b/src/Idle.hxx
index fb7150f98..cc89427ea 100644
--- a/src/Idle.hxx
+++ b/src/Idle.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -78,13 +78,13 @@ idle_add(unsigned flags);
* Atomically reads and resets the global idle flags value.
*/
unsigned
-idle_get(void);
+idle_get();
/**
* Get idle names
*/
const char*const*
-idle_get_names(void);
+idle_get_names();
/**
* Parse an idle name and return its mask. Returns 0 if the given
diff --git a/src/Instance.cxx b/src/Instance.cxx
index 232cd21df..77059c26c 100644
--- a/src/Instance.cxx
+++ b/src/Instance.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,7 @@
#include "Partition.hxx"
#include "Idle.hxx"
#include "Stats.hxx"
+#include "util/Error.hxx"
#ifdef ENABLE_DATABASE
#include "db/DatabaseError.hxx"
@@ -76,7 +77,7 @@ Instance::OnDatabaseSongRemoved(const LightSong &song)
#ifdef ENABLE_SQLITE
/* if the song has a sticker, remove it */
if (sticker_enabled())
- sticker_song_delete(song);
+ sticker_song_delete(song, IgnoreError());
#endif
const auto uri = song.GetURI();
diff --git a/src/Instance.hxx b/src/Instance.hxx
index fa7711ab9..d8e485c74 100644
--- a/src/Instance.hxx
+++ b/src/Instance.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Listen.cxx b/src/Listen.cxx
index d48d795d1..cf4b41352 100644
--- a/src/Listen.cxx
+++ b/src/Listen.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,10 @@
#include "config.h"
#include "Listen.hxx"
#include "client/Client.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
+#include "net/SocketAddress.hxx"
#include "event/ServerSocket.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -48,10 +49,9 @@ public:
:ServerSocket(_loop), partition(_partition) {}
private:
- virtual void OnAccept(int fd, const sockaddr &address,
- size_t address_length, int uid) {
+ void OnAccept(int fd, SocketAddress address, int uid) override {
client_new(GetEventLoop(), partition,
- fd, &address, address_length, uid);
+ fd, address, uid);
}
};
@@ -103,9 +103,9 @@ listen_systemd_activation(Error &error_r)
bool
listen_global_init(EventLoop &loop, Partition &partition, Error &error)
{
- int port = config_get_positive(CONF_PORT, DEFAULT_PORT);
+ int port = config_get_positive(ConfigOption::PORT, DEFAULT_PORT);
const struct config_param *param =
- config_get_param(CONF_BIND_TO_ADDRESS);
+ config_get_param(ConfigOption::BIND_TO_ADDRESS);
listen_socket = new ClientListener(loop, partition);
diff --git a/src/Listen.hxx b/src/Listen.hxx
index d74c1d233..1e24d47f8 100644
--- a/src/Listen.hxx
+++ b/src/Listen.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,7 @@ extern int listen_port;
bool
listen_global_init(EventLoop &loop, Partition &partition, Error &error);
-void listen_global_finish(void);
+void
+listen_global_finish();
#endif
diff --git a/src/LocateUri.cxx b/src/LocateUri.cxx
new file mode 100644
index 000000000..71c8d9093
--- /dev/null
+++ b/src/LocateUri.cxx
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "LocateUri.hxx"
+#include "client/Client.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "ls.hxx"
+#include "util/UriUtil.hxx"
+#include "util/StringUtil.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+
+#ifdef ENABLE_DATABASE
+#include "storage/StorageInterface.hxx"
+#endif
+
+const Domain locate_uri_domain("locate_uri");
+
+static LocatedUri
+LocateFileUri(const char *uri, const Client *client,
+#ifdef ENABLE_DATABASE
+ const Storage *storage,
+#endif
+ Error &error)
+{
+ auto path = AllocatedPath::FromUTF8(uri, error);
+ if (path.IsNull())
+ return LocatedUri::Unknown();
+
+#ifdef ENABLE_DATABASE
+ if (storage != nullptr) {
+ const char *suffix = storage->MapToRelativeUTF8(uri);
+ if (suffix != nullptr)
+ /* this path was relative to the music
+ directory */
+ return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
+ }
+#endif
+
+ if (client != nullptr && !client->AllowFile(path, error))
+ return LocatedUri::Unknown();
+
+ return LocatedUri(LocatedUri::Type::PATH, uri, std::move(path));
+}
+
+static LocatedUri
+LocateAbsoluteUri(const char *uri,
+#ifdef ENABLE_DATABASE
+ const Storage *storage,
+#endif
+ Error &error)
+{
+ if (!uri_supported_scheme(uri)) {
+ error.Set(locate_uri_domain, "Unsupported URI scheme");
+ return LocatedUri::Unknown();
+ }
+
+#ifdef ENABLE_DATABASE
+ if (storage != nullptr) {
+ const char *suffix = storage->MapToRelativeUTF8(uri);
+ if (suffix != nullptr)
+ return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
+ }
+#endif
+
+ return LocatedUri(LocatedUri::Type::ABSOLUTE, uri);
+}
+
+LocatedUri
+LocateUri(const char *uri, const Client *client,
+#ifdef ENABLE_DATABASE
+ const Storage *storage,
+#endif
+ Error &error)
+{
+ /* skip the obsolete "file://" prefix */
+ const char *path_utf8 = StringAfterPrefix(uri, "file://");
+ if (path_utf8 != nullptr) {
+ if (!PathTraitsUTF8::IsAbsolute(path_utf8)) {
+ error.Set(locate_uri_domain, "Malformed file:// URI");
+ return LocatedUri::Unknown();
+ }
+
+ return LocateFileUri(path_utf8, client,
+#ifdef ENABLE_DATABASE
+ storage,
+#endif
+ error);
+ } else if (PathTraitsUTF8::IsAbsolute(uri))
+ return LocateFileUri(uri, client,
+#ifdef ENABLE_DATABASE
+ storage,
+#endif
+ error);
+ else if (uri_has_scheme(uri))
+ return LocateAbsoluteUri(uri,
+#ifdef ENABLE_DATABASE
+ storage,
+#endif
+ error);
+ else
+ return LocatedUri(LocatedUri::Type::RELATIVE, uri);
+}
diff --git a/src/LocateUri.hxx b/src/LocateUri.hxx
new file mode 100644
index 000000000..1cb57ace4
--- /dev/null
+++ b/src/LocateUri.hxx
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_LOCATE_URI_HXX
+#define MPD_LOCATE_URI_HXX
+
+#include "check.h"
+#include "Compiler.h"
+#include "fs/AllocatedPath.hxx"
+
+#ifdef WIN32
+#include <windows.h>
+/* damn you, windows.h! */
+#ifdef ABSOLUTE
+#undef ABSOLUTE
+#endif
+#ifdef RELATIVE
+#undef RELATIVE
+#endif
+#endif
+
+class Domain;
+class Error;
+class Client;
+
+#ifdef ENABLE_DATABASE
+class Storage;
+#endif
+
+struct LocatedUri {
+ enum class Type {
+ /**
+ * Failed to parse the URI.
+ */
+ UNKNOWN,
+
+ /**
+ * An absolute URI with a supported scheme.
+ */
+ ABSOLUTE,
+
+ /**
+ * A relative URI path.
+ */
+ RELATIVE,
+
+ /**
+ * A local file. The #path attribute is valid.
+ */
+ PATH,
+ } type;
+
+ const char *canonical_uri;
+
+ /**
+ * Contains the local file path if type==FILE.
+ */
+ AllocatedPath path;
+
+ LocatedUri(Type _type, const char *_uri,
+ AllocatedPath &&_path=AllocatedPath::Null())
+ :type(_type), canonical_uri(_uri), path(std::move(_path)) {}
+
+ gcc_const
+ static LocatedUri Unknown() {
+ return LocatedUri(Type::UNKNOWN, nullptr);
+ }
+
+ bool IsUnknown() const {
+ return type == Type::UNKNOWN;
+ }
+};
+
+extern const Domain locate_uri_domain;
+
+/**
+ * Classify a URI.
+ *
+ * @param client the #Client that is used to determine whether a local
+ * file is allowed; nullptr disables the check and allows all local
+ * files
+ * @param storage a #Storage instance which may be used to convert
+ * absolute URIs to relative ones, using Storage::MapToRelativeUTF8();
+ * that feature is disabled if this parameter is nullptr
+ */
+LocatedUri
+LocateUri(const char *uri, const Client *client,
+#ifdef ENABLE_DATABASE
+ const Storage *storage,
+#endif
+ Error &error);
+
+#endif
diff --git a/src/Log.cxx b/src/Log.cxx
index ba691581b..585e51f7c 100644
--- a/src/Log.cxx
+++ b/src/Log.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Log.hxx b/src/Log.hxx
index 15077e374..684d5c394 100644
--- a/src/Log.hxx
+++ b/src/Log.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/LogBackend.cxx b/src/LogBackend.cxx
index 04c2e6324..b1b692cd3 100644
--- a/src/LogBackend.cxx
+++ b/src/LogBackend.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,6 @@
#include "util/Domain.hxx"
#include "util/StringUtil.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
#include <assert.h>
#include <stdio.h>
#include <string.h>
@@ -65,10 +61,6 @@ ToAndroidLogLevel(LogLevel log_level)
static LogLevel log_threshold = LogLevel::INFO;
-#ifdef HAVE_GLIB
-static const char *log_charset;
-#endif
-
static bool enable_timestamp;
#ifdef HAVE_SYSLOG
@@ -81,16 +73,6 @@ SetLogThreshold(LogLevel _threshold)
log_threshold = _threshold;
}
-#ifdef HAVE_GLIB
-
-void
-SetLogCharset(const char *_charset)
-{
- log_charset = _charset;
-}
-
-#endif
-
void
EnableLogTimestamp()
{
@@ -175,20 +157,6 @@ LogFinishSysLog()
static void
FileLog(const Domain &domain, const char *message)
{
-#ifdef HAVE_GLIB
- char *converted;
-
- if (log_charset != nullptr) {
- converted = g_convert_with_fallback(message, -1,
- log_charset, "utf-8",
- nullptr, nullptr,
- nullptr, nullptr);
- if (converted != nullptr)
- message = converted;
- } else
- converted = nullptr;
-#endif
-
fprintf(stderr, "%s%s: %.*s\n",
enable_timestamp ? log_date() : "",
domain.GetName(),
@@ -199,10 +167,6 @@ FileLog(const Domain &domain, const char *message)
to have an effect on WIN32 */
fflush(stderr);
#endif
-
-#ifdef HAVE_GLIB
- g_free(converted);
-#endif
}
#endif /* !ANDROID */
diff --git a/src/LogBackend.hxx b/src/LogBackend.hxx
index 23df2037e..d38d9eeb3 100644
--- a/src/LogBackend.hxx
+++ b/src/LogBackend.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,13 +26,6 @@
void
SetLogThreshold(LogLevel _threshold);
-#ifdef HAVE_GLIB
-
-void
-SetLogCharset(const char *_charset);
-
-#endif
-
void
EnableLogTimestamp();
diff --git a/src/LogInit.cxx b/src/LogInit.cxx
index 117c6d8dc..7f3c11b2e 100644
--- a/src/LogInit.cxx
+++ b/src/LogInit.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include "LogInit.hxx"
#include "LogBackend.hxx"
#include "Log.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "system/FatalError.hxx"
@@ -31,10 +31,6 @@
#include "util/Domain.hxx"
#include "system/FatalError.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
#include <assert.h>
#include <string.h>
#include <fcntl.h>
@@ -72,14 +68,14 @@ open_log_file(void)
}
static bool
-log_init_file(unsigned line, Error &error)
+log_init_file(int line, Error &error)
{
assert(!out_path.IsNull());
out_fd = open_log_file();
if (out_fd < 0) {
const std::string out_path_utf8 = out_path.ToUTF8();
- error.FormatErrno("failed to open log file \"%s\" (config line %u)",
+ error.FormatErrno("failed to open log file \"%s\" (config line %d)",
out_path_utf8.c_str(), line);
return false;
}
@@ -89,7 +85,7 @@ log_init_file(unsigned line, Error &error)
}
static inline LogLevel
-parse_log_level(const char *value, unsigned line)
+parse_log_level(const char *value, int line)
{
if (0 == strcmp(value, "default"))
return LogLevel::DEFAULT;
@@ -98,7 +94,7 @@ parse_log_level(const char *value, unsigned line)
else if (0 == strcmp(value, "verbose"))
return LogLevel::DEBUG;
else {
- FormatFatalError("unknown log level \"%s\" at line %u",
+ FormatFatalError("unknown log level \"%s\" at line %d",
value, line);
}
}
@@ -131,22 +127,16 @@ log_init(bool verbose, bool use_stdout, Error &error)
#else
const struct config_param *param;
-#ifdef HAVE_GLIB
- const char *charset;
- g_get_charset(&charset);
- SetLogCharset(charset);
-#endif
-
if (verbose)
SetLogThreshold(LogLevel::DEBUG);
- else if ((param = config_get_param(CONF_LOG_LEVEL)) != nullptr)
+ else if ((param = config_get_param(ConfigOption::LOG_LEVEL)) != nullptr)
SetLogThreshold(parse_log_level(param->value.c_str(),
param->line));
if (use_stdout) {
return true;
} else {
- param = config_get_param(CONF_LOG_FILE);
+ param = config_get_param(ConfigOption::LOG_FILE);
if (param == nullptr) {
#ifdef HAVE_SYSLOG
/* no configuration: default to syslog (if
@@ -164,7 +154,7 @@ log_init(bool verbose, bool use_stdout, Error &error)
return true;
#endif
} else {
- out_path = config_get_path(CONF_LOG_FILE, error);
+ out_path = config_get_path(ConfigOption::LOG_FILE, error);
return !out_path.IsNull() &&
log_init_file(param->line, error);
}
@@ -216,10 +206,6 @@ void setup_log_output(bool use_stdout)
redirect_logs(out_fd);
close(out_fd);
out_fd = -1;
-
-#ifdef HAVE_GLIB
- SetLogCharset(nullptr);
-#endif
#endif
}
diff --git a/src/LogInit.hxx b/src/LogInit.hxx
index d0bcb40f2..30fcb8baa 100644
--- a/src/LogInit.hxx
+++ b/src/LogInit.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,10 +37,11 @@ bool
log_init(bool verbose, bool use_stdout, Error &error);
void
-log_deinit(void);
+log_deinit();
void setup_log_output(bool use_stdout);
-int cycle_log_files(void);
+int
+cycle_log_files();
#endif /* LOG_H */
diff --git a/src/LogLevel.hxx b/src/LogLevel.hxx
index 2614a67d1..64c12e009 100644
--- a/src/LogLevel.hxx
+++ b/src/LogLevel.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/LogV.hxx b/src/LogV.hxx
index 6b16f82b4..7b108936d 100644
--- a/src/LogV.hxx
+++ b/src/LogV.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Main.cxx b/src/Main.cxx
index a3a1b0021..1a074d439 100644
--- a/src/Main.cxx
+++ b/src/Main.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
#include "PlaylistGlobal.hxx"
#include "MusicChunk.hxx"
#include "StateFile.hxx"
-#include "PlayerThread.hxx"
+#include "player/Thread.hxx"
#include "Mapper.hxx"
#include "Permission.hxx"
#include "Listen.hxx"
@@ -50,7 +50,6 @@
#include "AudioConfig.hxx"
#include "pcm/PcmConvert.hxx"
#include "unix/SignalHandlers.hxx"
-#include "unix/Daemon.hxx"
#include "system/FatalError.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
@@ -58,12 +57,16 @@
#include "thread/Slack.hxx"
#include "lib/icu/Init.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigDefaults.hxx"
#include "config/ConfigOption.hxx"
#include "config/ConfigError.hxx"
#include "Stats.hxx"
+#ifdef ENABLE_DAEMON
+#include "unix/Daemon.hxx"
+#endif
+
#ifdef ENABLE_DATABASE
#include "db/update/Service.hxx"
#include "db/Configured.hxx"
@@ -98,8 +101,8 @@
#include "org_musicpd_Bridge.h"
#endif
-#ifdef HAVE_GLIB
-#include <glib.h>
+#ifdef ENABLE_SYSTEMD_DAEMON
+#include <systemd/sd-daemon.h>
#endif
#include <stdlib.h>
@@ -130,17 +133,17 @@ Instance *instance;
static StateFile *state_file;
-#ifndef ANDROID
+#ifdef ENABLE_DAEMON
static bool
glue_daemonize_init(const struct options *options, Error &error)
{
- auto pid_file = config_get_path(CONF_PID_FILE, error);
+ auto pid_file = config_get_path(ConfigOption::PID_FILE, error);
if (pid_file.IsNull() && error.IsDefined())
return false;
- daemonize_init(config_get_string(CONF_USER, nullptr),
- config_get_string(CONF_GROUP, nullptr),
+ daemonize_init(config_get_string(ConfigOption::USER, nullptr),
+ config_get_string(ConfigOption::GROUP, nullptr),
std::move(pid_file));
if (options->kill)
@@ -154,7 +157,7 @@ glue_daemonize_init(const struct options *options, Error &error)
static bool
glue_mapper_init(Error &error)
{
- auto playlist_dir = config_get_path(CONF_PLAYLIST_DIR, error);
+ auto playlist_dir = config_get_path(ConfigOption::PLAYLIST_DIR, error);
if (playlist_dir.IsNull() && error.IsDefined())
return false;
@@ -249,7 +252,7 @@ glue_sticker_init(void)
{
#ifdef ENABLE_SQLITE
Error error;
- auto sticker_file = config_get_path(CONF_STICKER_FILE, error);
+ auto sticker_file = config_get_path(ConfigOption::STICKER_FILE, error);
if (sticker_file.IsNull()) {
if (error.IsDefined())
FatalError(error);
@@ -264,7 +267,7 @@ glue_sticker_init(void)
static bool
glue_state_file_init(Error &error)
{
- auto path_fs = config_get_path(CONF_STATE_FILE, error);
+ auto path_fs = config_get_path(ConfigOption::STATE_FILE, error);
if (path_fs.IsNull()) {
if (error.IsDefined())
return false;
@@ -280,8 +283,9 @@ glue_state_file_init(Error &error)
#endif
}
- unsigned interval = config_get_unsigned(CONF_STATE_FILE_INTERVAL,
- StateFile::DEFAULT_INTERVAL);
+ const unsigned interval =
+ config_get_unsigned(ConfigOption::STATE_FILE_INTERVAL,
+ StateFile::DEFAULT_INTERVAL);
state_file = new StateFile(std::move(path_fs), interval,
*instance->partition,
@@ -318,7 +322,7 @@ initialize_decoder_and_player(void)
const struct config_param *param;
size_t buffer_size;
- param = config_get_param(CONF_AUDIO_BUFFER_SIZE);
+ param = config_get_param(ConfigOption::AUDIO_BUFFER_SIZE);
if (param != nullptr) {
char *test;
long tmp = strtol(param->value.c_str(), &test, 10);
@@ -339,7 +343,7 @@ initialize_decoder_and_player(void)
(unsigned long)buffer_size);
float perc;
- param = config_get_param(CONF_BUFFER_BEFORE_PLAY);
+ param = config_get_param(ConfigOption::BUFFER_BEFORE_PLAY);
if (param != nullptr) {
char *test;
perc = strtod(param->value.c_str(), &test);
@@ -357,7 +361,7 @@ initialize_decoder_and_player(void)
buffered_before_play = buffered_chunks;
const unsigned max_length =
- config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
+ config_get_positive(ConfigOption::MAX_PLAYLIST_LENGTH,
DEFAULT_PLAYLIST_MAX_LENGTH);
instance->partition = new Partition(*instance,
@@ -419,21 +423,15 @@ int mpd_main(int argc, char *argv[])
struct options options;
Error error;
-#ifndef ANDROID
+#ifdef ENABLE_DAEMON
daemonize_close_stdin();
+#endif
+#ifndef ANDROID
#ifdef HAVE_LOCALE_H
/* initialize locale */
setlocale(LC_CTYPE,"");
-#endif
-
-#ifdef HAVE_GLIB
- g_set_application_name("Music Player Daemon");
-
-#if !GLIB_CHECK_VERSION(2,32,0)
- /* enable GLib's thread safety code */
- g_thread_init(nullptr);
-#endif
+ setlocale(LC_COLLATE, "");
#endif
#endif
@@ -467,7 +465,9 @@ int mpd_main(int argc, char *argv[])
LogError(error);
return EXIT_FAILURE;
}
+#endif
+#ifdef ENABLE_DAEMON
if (!glue_daemonize_init(&options, error)) {
LogError(error);
return EXIT_FAILURE;
@@ -498,7 +498,8 @@ int mpd_main(int argc, char *argv[])
}
#endif
- const unsigned max_clients = config_get_positive(CONF_MAX_CONN, 10);
+ const unsigned max_clients =
+ config_get_positive(ConfigOption::MAX_CONN, 10);
instance->client_list = new ClientList(max_clients);
initialize_decoder_and_player();
@@ -509,7 +510,7 @@ int mpd_main(int argc, char *argv[])
return EXIT_FAILURE;
}
-#ifndef ANDROID
+#ifdef ENABLE_DAEMON
daemonize_set_user();
daemonize_begin(options.daemon);
#endif
@@ -541,7 +542,10 @@ static int mpd_main_after_fork(struct options options)
GlobalEvents::Register(GlobalEvents::SHUTDOWN, shutdown_event_emitted);
#endif
- ConfigureFS();
+ if (!ConfigureFS(error)) {
+ LogError(error);
+ return EXIT_FAILURE;
+ }
if (!glue_mapper_init(error)) {
LogError(error);
@@ -582,9 +586,11 @@ static int mpd_main_after_fork(struct options options)
playlist_list_global_init();
-#ifndef ANDROID
+#ifdef ENABLE_DAEMON
daemonize_commit();
+#endif
+#ifndef ANDROID
setup_log_output(options.log_stderr);
SignalHandlersInit(*instance->event_loop);
@@ -620,17 +626,17 @@ static int mpd_main_after_fork(struct options options)
instance->partition->outputs.SetReplayGainMode(replay_gain_get_real_mode(instance->partition->playlist.queue.random));
#ifdef ENABLE_DATABASE
- if (config_get_bool(CONF_AUTO_UPDATE, false)) {
+ if (config_get_bool(ConfigOption::AUTO_UPDATE, false)) {
#ifdef ENABLE_INOTIFY
if (instance->storage != nullptr &&
instance->update != nullptr)
mpd_inotify_init(*instance->event_loop,
*instance->storage,
*instance->update,
- config_get_unsigned(CONF_AUTO_UPDATE_DEPTH,
+ config_get_unsigned(ConfigOption::AUTO_UPDATE_DEPTH,
INT_MAX));
#else
- FormatWarning(main_domain,
+ FormatWarning(config_domain,
"inotify: auto_update was disabled. enable during compilation phase");
#endif
}
@@ -650,6 +656,10 @@ static int mpd_main_after_fork(struct options options)
a huge value to allow the kernel to reduce CPU wakeups */
SetThreadTimerSlackMS(100);
+#ifdef ENABLE_SYSTEMD_DAEMON
+ sd_notify(0, "READY=1");
+#endif
+
/* run the main loop */
instance->event_loop->Run();
@@ -707,6 +717,8 @@ static int mpd_main_after_fork(struct options options)
mapper_finish();
#endif
+ DeinitFS();
+
delete instance->partition;
command_finish();
decoder_plugin_deinit_all();
@@ -721,9 +733,11 @@ static int mpd_main_after_fork(struct options options)
delete instance->event_loop;
delete instance;
instance = nullptr;
-#ifndef ANDROID
+
+#ifdef ENABLE_DAEMON
daemonize_finish();
#endif
+
#ifdef WIN32
WSACleanup();
#endif
diff --git a/src/Main.hxx b/src/Main.hxx
index 7e3fecd0b..0229b788c 100644
--- a/src/Main.hxx
+++ b/src/Main.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -61,7 +61,7 @@ win32_main(int argc, char *argv[]);
* This function should be called just before entering main loop.
*/
void
-win32_app_started(void);
+win32_app_started();
/**
* When running as a service reports to service control manager
@@ -71,7 +71,7 @@ win32_app_started(void);
* This function should be called just after leaving main loop.
*/
void
-win32_app_stopping(void);
+win32_app_stopping();
#endif
diff --git a/src/Mapper.cxx b/src/Mapper.cxx
index 7baad9459..15d706922 100644
--- a/src/Mapper.cxx
+++ b/src/Mapper.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -59,7 +59,8 @@ mapper_init(AllocatedPath &&_playlist_dir)
mapper_set_playlist_dir(std::move(_playlist_dir));
}
-void mapper_finish(void)
+void
+mapper_finish()
{
}
@@ -86,9 +87,9 @@ map_uri_fs(const char *uri)
}
std::string
-map_fs_to_utf8(const char *path_fs)
+map_fs_to_utf8(Path path_fs)
{
- if (PathTraitsFS::IsSeparator(path_fs[0])) {
+ if (path_fs.IsAbsolute()) {
if (instance->storage == nullptr)
return std::string();
@@ -96,18 +97,20 @@ map_fs_to_utf8(const char *path_fs)
if (music_dir_fs.IsNull())
return std::string();
- path_fs = music_dir_fs.RelativeFS(path_fs);
- if (path_fs == nullptr || *path_fs == 0)
+ auto relative = music_dir_fs.Relative(path_fs);
+ if (relative == nullptr || *relative == 0)
return std::string();
+
+ path_fs = Path::FromFS(relative);
}
- return PathToUTF8(path_fs);
+ return path_fs.ToUTF8();
}
#endif
const AllocatedPath &
-map_spl_path(void)
+map_spl_path()
{
return playlist_dir_fs;
}
diff --git a/src/Mapper.hxx b/src/Mapper.hxx
index 7ff41f239..ca5d29810 100644
--- a/src/Mapper.hxx
+++ b/src/Mapper.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,12 +30,14 @@
#define PLAYLIST_FILE_SUFFIX ".m3u"
+class Path;
class AllocatedPath;
void
mapper_init(AllocatedPath &&playlist_dir);
-void mapper_finish(void);
+void
+mapper_finish();
#ifdef ENABLE_DATABASE
@@ -58,7 +60,7 @@ map_uri_fs(const char *uri);
*/
gcc_pure
std::string
-map_fs_to_utf8(const char *path_fs);
+map_fs_to_utf8(Path path_fs);
#endif
@@ -67,7 +69,7 @@ map_fs_to_utf8(const char *path_fs);
*/
gcc_const
const AllocatedPath &
-map_spl_path(void);
+map_spl_path();
/**
* Maps a playlist name (without the ".m3u" suffix) to a file system
diff --git a/src/MixRampInfo.hxx b/src/MixRampInfo.hxx
index 90c2c984a..297adfe07 100644
--- a/src/MixRampInfo.hxx
+++ b/src/MixRampInfo.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/MusicBuffer.cxx b/src/MusicBuffer.cxx
index 709b40413..5de94508a 100644
--- a/src/MusicBuffer.cxx
+++ b/src/MusicBuffer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/MusicBuffer.hxx b/src/MusicBuffer.hxx
index cf7c90f91..60b792f3a 100644
--- a/src/MusicBuffer.hxx
+++ b/src/MusicBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/MusicChunk.cxx b/src/MusicChunk.cxx
index 3cfd232c0..9f09b35c5 100644
--- a/src/MusicChunk.cxx
+++ b/src/MusicChunk.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/MusicChunk.hxx b/src/MusicChunk.hxx
index 805112d02..0f750f049 100644
--- a/src/MusicChunk.hxx
+++ b/src/MusicChunk.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -119,13 +119,10 @@ struct MusicChunk {
* where you may write into. After you are finished, call
* Expand().
*
- * @param chunk the MusicChunk object
- * @param audio_format the audio format for the appended data;
+ * @param af the audio format for the appended data;
* must stay the same for the life cycle of this chunk
* @param data_time the time within the song
* @param bit_rate the current bit rate of the source file
- * @param max_length_r the maximum write length is returned
- * here
* @return a writable buffer, or nullptr if the chunk is full
*/
WritableBuffer<void> Write(AudioFormat af,
@@ -136,8 +133,7 @@ struct MusicChunk {
* Increases the length of the chunk after the caller has written to
* the buffer returned by Write().
*
- * @param chunk the MusicChunk object
- * @param audio_format the audio format for the appended data; must
+ * @param af the audio format for the appended data; must
* stay the same for the life cycle of this chunk
* @param length the number of bytes which were appended
* @return true if the chunk is full
diff --git a/src/MusicPipe.cxx b/src/MusicPipe.cxx
index 43ce2dbb2..cd874eb33 100644
--- a/src/MusicPipe.cxx
+++ b/src/MusicPipe.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/MusicPipe.hxx b/src/MusicPipe.hxx
index 4f29d0728..078530abb 100644
--- a/src/MusicPipe.hxx
+++ b/src/MusicPipe.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Partition.cxx b/src/Partition.cxx
index de1170557..1d48fefdb 100644
--- a/src/Partition.cxx
+++ b/src/Partition.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "Partition.hxx"
+#include "Instance.hxx"
#include "DetachedSong.hxx"
#include "output/MultipleOutputs.hxx"
#include "mixer/Volume.hxx"
@@ -27,6 +28,12 @@
#ifdef ENABLE_DATABASE
+const Database *
+Partition::GetDatabase(Error &error) const
+{
+ return instance.GetDatabase(error);
+}
+
void
Partition::DatabaseModified(const Database &db)
{
diff --git a/src/Partition.hxx b/src/Partition.hxx
index d89c4b41f..cd7b3c66e 100644
--- a/src/Partition.hxx
+++ b/src/Partition.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,8 +23,8 @@
#include "queue/Playlist.hxx"
#include "output/MultipleOutputs.hxx"
#include "mixer/Listener.hxx"
-#include "PlayerControl.hxx"
-#include "PlayerListener.hxx"
+#include "player/Control.hxx"
+#include "player/Listener.hxx"
#include "Chrono.hxx"
#include "Compiler.h"
@@ -177,6 +177,13 @@ struct Partition final : private PlayerListener, private MixerListener {
#ifdef ENABLE_DATABASE
/**
+ * Returns the global #Database instance. May return nullptr
+ * if this MPD configuration has no database (no
+ * music_directory was configured).
+ */
+ const Database *GetDatabase(Error &error) const;
+
+ /**
* The database has been modified. Propagate the change to
* all subsystems.
*/
diff --git a/src/Permission.cxx b/src/Permission.cxx
index d6c267ab7..b6ff39bdb 100644
--- a/src/Permission.cxx
+++ b/src/Permission.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "Permission.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "system/FatalError.hxx"
@@ -92,7 +92,7 @@ void initPermissions(void)
permission_default = PERMISSION_READ | PERMISSION_ADD |
PERMISSION_CONTROL | PERMISSION_ADMIN;
- param = config_get_param(CONF_PASSWORD);
+ param = config_get_param(ConfigOption::PASSWORD);
if (param) {
permission_default = 0;
@@ -118,7 +118,7 @@ void initPermissions(void)
} while ((param = param->next) != nullptr);
}
- param = config_get_param(CONF_DEFAULT_PERMS);
+ param = config_get_param(ConfigOption::DEFAULT_PERMS);
if (param)
permission_default = parsePermissions(param->value.c_str());
diff --git a/src/Permission.hxx b/src/Permission.hxx
index 60761c696..50edc1da4 100644
--- a/src/Permission.hxx
+++ b/src/Permission.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,10 @@ static constexpr unsigned PERMISSION_ADMIN = 8;
int getPermissionFromPassword(char const* password, unsigned* permission);
-unsigned getDefaultPermissions(void);
+unsigned
+getDefaultPermissions();
-void initPermissions(void);
+void
+initPermissions();
#endif
diff --git a/src/PlaylistDatabase.cxx b/src/PlaylistDatabase.cxx
index 3421ecb02..75cb699b8 100644
--- a/src/PlaylistDatabase.cxx
+++ b/src/PlaylistDatabase.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistDatabase.hxx b/src/PlaylistDatabase.hxx
index 17f82f64b..078530c75 100644
--- a/src/PlaylistDatabase.hxx
+++ b/src/PlaylistDatabase.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistError.cxx b/src/PlaylistError.cxx
index 085246f15..d069dd3a3 100644
--- a/src/PlaylistError.cxx
+++ b/src/PlaylistError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistError.hxx b/src/PlaylistError.hxx
index 0f2424f41..500acd711 100644
--- a/src/PlaylistError.hxx
+++ b/src/PlaylistError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistFile.cxx b/src/PlaylistFile.cxx
index ab269378a..9d2b56eae 100644
--- a/src/PlaylistFile.cxx
+++ b/src/PlaylistFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,12 +20,15 @@
#include "config.h"
#include "PlaylistFile.hxx"
#include "PlaylistSave.hxx"
+#include "PlaylistError.hxx"
#include "db/PlaylistInfo.hxx"
#include "db/PlaylistVector.hxx"
#include "DetachedSong.hxx"
#include "SongLoader.hxx"
#include "Mapper.hxx"
#include "fs/io/TextFile.hxx"
+#include "fs/io/FileOutputStream.hxx"
+#include "fs/io/BufferedOutputStream.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "config/ConfigDefaults.hxx"
@@ -35,7 +38,9 @@
#include "fs/Traits.hxx"
#include "fs/Charset.hxx"
#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
+#include "util/Macros.hxx"
#include "util/StringUtil.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
@@ -53,11 +58,12 @@ bool playlist_saveAbsolutePaths = DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS;
void
spl_global_init(void)
{
- playlist_max_length = config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
- DEFAULT_PLAYLIST_MAX_LENGTH);
+ playlist_max_length =
+ config_get_positive(ConfigOption::MAX_PLAYLIST_LENGTH,
+ DEFAULT_PLAYLIST_MAX_LENGTH);
playlist_saveAbsolutePaths =
- config_get_bool(CONF_SAVE_ABSOLUTE_PATHS,
+ config_get_bool(ConfigOption::SAVE_ABSOLUTE_PATHS,
DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS);
}
@@ -106,7 +112,7 @@ spl_check_name(const char *name_utf8, Error &error)
return true;
}
-static AllocatedPath
+AllocatedPath
spl_map_to_fs(const char *name_utf8, Error &error)
{
if (spl_map(error).IsNull() || !spl_check_name(name_utf8, error))
@@ -133,7 +139,7 @@ IsNotFoundError(const Error &error)
#endif
}
-static void
+void
TranslatePlaylistError(Error &error)
{
if (IsNotFoundError(error)) {
@@ -166,29 +172,28 @@ LoadPlaylistFileInfo(PlaylistInfo &info,
const Path parent_path_fs,
const Path name_fs)
{
- const char *name_fs_str = name_fs.c_str();
- size_t name_length = strlen(name_fs_str);
-
- if (name_length < sizeof(PLAYLIST_FILE_SUFFIX) ||
- memchr(name_fs_str, '\n', name_length) != nullptr)
+ if (name_fs.HasNewline())
return false;
- if (!StringEndsWith(name_fs_str, PLAYLIST_FILE_SUFFIX))
+ const auto *const name_fs_str = name_fs.c_str();
+ const auto *const name_fs_end =
+ FindStringSuffix(name_fs_str,
+ PATH_LITERAL(PLAYLIST_FILE_SUFFIX));
+ if (name_fs_end == nullptr)
return false;
- const auto path_fs = AllocatedPath::Build(parent_path_fs, name_fs);
- struct stat st;
- if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode))
+ FileInfo fi;
+ if (!GetFileInfo(AllocatedPath::Build(parent_path_fs, name_fs), fi) ||
+ !fi.IsRegular())
return false;
- std::string name(name_fs_str,
- name_length + 1 - sizeof(PLAYLIST_FILE_SUFFIX));
+ PathTraitsFS::string name(name_fs_str, name_fs_end);
std::string name_utf8 = PathToUTF8(name.c_str());
if (name_utf8.empty())
return false;
info.name = std::move(name_utf8);
- info.mtime = st.st_mtime;
+ info.mtime = fi.GetModificationTime();
return true;
}
@@ -223,24 +228,22 @@ SavePlaylistFile(const PlaylistFileContents &contents, const char *utf8path,
{
assert(utf8path != nullptr);
- if (spl_map(error).IsNull())
- return false;
-
const auto path_fs = spl_map_to_fs(utf8path, error);
if (path_fs.IsNull())
return false;
- FILE *file = FOpen(path_fs, FOpenMode::WriteText);
- if (file == nullptr) {
- playlist_errno(error);
+ FileOutputStream fos(path_fs, error);
+ if (!fos.IsDefined()) {
+ TranslatePlaylistError(error);
return false;
}
+ BufferedOutputStream bos(fos);
+
for (const auto &uri_utf8 : contents)
- playlist_print_uri(file, uri_utf8.c_str());
+ playlist_print_uri(bos, uri_utf8.c_str());
- fclose(file);
- return true;
+ return bos.Flush(error) && fos.Commit(error);
}
PlaylistFileContents
@@ -248,9 +251,6 @@ LoadPlaylistFile(const char *utf8path, Error &error)
{
PlaylistFileContents contents;
- if (spl_map(error).IsNull())
- return contents;
-
const auto path_fs = spl_map_to_fs(utf8path, error);
if (path_fs.IsNull())
return contents;
@@ -266,18 +266,28 @@ LoadPlaylistFile(const char *utf8path, Error &error)
if (*s == 0 || *s == PLAYLIST_COMMENT)
continue;
+#ifdef _UNICODE
+ wchar_t buffer[MAX_PATH];
+ auto result = MultiByteToWideChar(CP_ACP, 0, s, -1,
+ buffer, ARRAY_SIZE(buffer));
+ if (result <= 0)
+ continue;
+
+ const Path path = Path::FromFS(buffer);
+#else
+ const Path path = Path::FromFS(s);
+#endif
+
std::string uri_utf8;
if (!uri_has_scheme(s)) {
#ifdef ENABLE_DATABASE
- uri_utf8 = map_fs_to_utf8(s);
+ uri_utf8 = map_fs_to_utf8(path);
if (uri_utf8.empty()) {
- if (PathTraitsFS::IsAbsolute(s)) {
- uri_utf8 = PathToUTF8(s);
+ if (path.IsAbsolute()) {
+ uri_utf8 = path.ToUTF8();
if (uri_utf8.empty())
continue;
-
- uri_utf8.insert(0, "file://");
} else
continue;
}
@@ -285,7 +295,7 @@ LoadPlaylistFile(const char *utf8path, Error &error)
continue;
#endif
} else {
- uri_utf8 = PathToUTF8(s);
+ uri_utf8 = path.ToUTF8();
if (uri_utf8.empty())
continue;
}
@@ -333,9 +343,6 @@ spl_move_index(const char *utf8path, unsigned src, unsigned dest,
bool
spl_clear(const char *utf8path, Error &error)
{
- if (spl_map(error).IsNull())
- return false;
-
const auto path_fs = spl_map_to_fs(utf8path, error);
if (path_fs.IsNull())
return false;
@@ -392,36 +399,28 @@ spl_remove_index(const char *utf8path, unsigned pos, Error &error)
bool
spl_append_song(const char *utf8path, const DetachedSong &song, Error &error)
{
- if (spl_map(error).IsNull())
- return false;
-
const auto path_fs = spl_map_to_fs(utf8path, error);
if (path_fs.IsNull())
return false;
- FILE *file = FOpen(path_fs, FOpenMode::AppendText);
- if (file == nullptr) {
- playlist_errno(error);
- return false;
- }
-
- struct stat st;
- if (fstat(fileno(file), &st) < 0) {
- playlist_errno(error);
- fclose(file);
+ AppendFileOutputStream fos(path_fs, error);
+ if (!fos.IsDefined()) {
+ TranslatePlaylistError(error);
return false;
}
- if (st.st_size / off_t(MPD_PATH_MAX + 1) >= (off_t)playlist_max_length) {
- fclose(file);
+ if (fos.Tell() / (MPD_PATH_MAX + 1) >= playlist_max_length) {
error.Set(playlist_domain, int(PlaylistResult::TOO_LARGE),
"Stored playlist is too large");
return false;
}
- playlist_print_song(file, song);
+ BufferedOutputStream bos(fos);
- fclose(file);
+ playlist_print_song(bos, song);
+
+ if (!bos.Flush(error) || !fos.Commit(error))
+ return false;
idle_add(IDLE_STORED_PLAYLIST);
return true;
@@ -469,9 +468,6 @@ spl_rename_internal(Path from_path_fs, Path to_path_fs,
bool
spl_rename(const char *utf8from, const char *utf8to, Error &error)
{
- if (spl_map(error).IsNull())
- return false;
-
const auto from_path_fs = spl_map_to_fs(utf8from, error);
if (from_path_fs.IsNull())
return false;
diff --git a/src/PlaylistFile.hxx b/src/PlaylistFile.hxx
index 7154b1f84..5f905480f 100644
--- a/src/PlaylistFile.hxx
+++ b/src/PlaylistFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@ class DetachedSong;
class SongLoader;
class PlaylistVector;
class Error;
+class AllocatedPath;
typedef std::vector<std::string> PlaylistFileContents;
@@ -36,7 +37,7 @@ extern bool playlist_saveAbsolutePaths;
* Perform some global initialization, e.g. load configuration values.
*/
void
-spl_global_init(void);
+spl_global_init();
/**
* Determines whether the specified string is a valid name for a
@@ -45,6 +46,12 @@ spl_global_init(void);
bool
spl_valid_name(const char *name_utf8);
+AllocatedPath
+spl_map_to_fs(const char *name_utf8, Error &error);
+
+void
+TranslatePlaylistError(Error &error);
+
/**
* Returns a list of stored_playlist_info struct pointers. Returns
* nullptr if an error occurred.
diff --git a/src/PlaylistGlobal.cxx b/src/PlaylistGlobal.cxx
index dacfad0c7..fb65843f5 100644
--- a/src/PlaylistGlobal.cxx
+++ b/src/PlaylistGlobal.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistGlobal.hxx b/src/PlaylistGlobal.hxx
index a2e3bb030..244eed702 100644
--- a/src/PlaylistGlobal.hxx
+++ b/src/PlaylistGlobal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlaylistPrint.cxx b/src/PlaylistPrint.cxx
index cfa56c7b3..80f348710 100644
--- a/src/PlaylistPrint.cxx
+++ b/src/PlaylistPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "Instance.hxx"
#include "db/Interface.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "input/InputStream.hxx"
#include "DetachedSong.hxx"
#include "fs/Traits.hxx"
@@ -37,15 +38,17 @@
#define SONG_TIME "Time: "
void
-playlist_print_uris(Client &client, const playlist &playlist)
+playlist_print_uris(Response &r, Partition &partition,
+ const playlist &playlist)
{
const Queue &queue = playlist.queue;
- queue_print_uris(client, queue, 0, queue.GetLength());
+ queue_print_uris(r, partition, queue, 0, queue.GetLength());
}
bool
-playlist_print_info(Client &client, const playlist &playlist,
+playlist_print_info(Response &r, Partition &partition,
+ const playlist &playlist,
unsigned start, unsigned end)
{
const Queue &queue = playlist.queue;
@@ -58,12 +61,12 @@ playlist_print_info(Client &client, const playlist &playlist,
/* an invalid "start" offset is fatal */
return false;
- queue_print_info(client, queue, start, end);
+ queue_print_info(r, partition, queue, start, end);
return true;
}
bool
-playlist_print_id(Client &client, const playlist &playlist,
+playlist_print_id(Response &r, Partition &partition, const playlist &playlist,
unsigned id)
{
int position;
@@ -73,50 +76,53 @@ playlist_print_id(Client &client, const playlist &playlist,
/* no such song */
return false;
- return playlist_print_info(client, playlist, position, position + 1);
+ return playlist_print_info(r, partition,
+ playlist, position, position + 1);
}
bool
-playlist_print_current(Client &client, const playlist &playlist)
+playlist_print_current(Response &r, Partition &partition,
+ const playlist &playlist)
{
int current_position = playlist.GetCurrentPosition();
if (current_position < 0)
return false;
- queue_print_info(client, playlist.queue,
+ queue_print_info(r, partition, playlist.queue,
current_position, current_position + 1);
return true;
}
void
-playlist_print_find(Client &client, const playlist &playlist,
+playlist_print_find(Response &r, Partition &partition,
+ const playlist &playlist,
const SongFilter &filter)
{
- queue_find(client, playlist.queue, filter);
+ queue_find(r, partition, playlist.queue, filter);
}
void
-playlist_print_changes_info(Client &client,
+playlist_print_changes_info(Response &r, Partition &partition,
const playlist &playlist,
uint32_t version)
{
- queue_print_changes_info(client, playlist.queue, version);
+ queue_print_changes_info(r, partition, playlist.queue, version);
}
void
-playlist_print_changes_position(Client &client,
+playlist_print_changes_position(Response &r,
const playlist &playlist,
uint32_t version)
{
- queue_print_changes_position(client, playlist.queue, version);
+ queue_print_changes_position(r, playlist.queue, version);
}
#ifdef ENABLE_DATABASE
static bool
-PrintSongDetails(Client &client, const char *uri_utf8)
+PrintSongDetails(Response &r, Partition &partition, const char *uri_utf8)
{
- const Database *db = client.partition.instance.database;
+ const Database *db = partition.instance.database;
if (db == nullptr)
return false;
@@ -124,7 +130,7 @@ PrintSongDetails(Client &client, const char *uri_utf8)
if (song == nullptr)
return false;
- song_print_info(client, *song);
+ song_print_info(r, partition, *song);
db->ReturnSong(song);
return true;
}
@@ -132,10 +138,12 @@ PrintSongDetails(Client &client, const char *uri_utf8)
#endif
bool
-spl_print(Client &client, const char *name_utf8, bool detail,
+spl_print(Response &r, Partition &partition,
+ const char *name_utf8, bool detail,
Error &error)
{
#ifndef ENABLE_DATABASE
+ (void)partition;
(void)detail;
#endif
@@ -145,10 +153,10 @@ spl_print(Client &client, const char *name_utf8, bool detail,
for (const auto &uri_utf8 : contents) {
#ifdef ENABLE_DATABASE
- if (!detail || !PrintSongDetails(client, uri_utf8.c_str()))
+ if (!detail || !PrintSongDetails(r, partition,
+ uri_utf8.c_str()))
#endif
- client_printf(client, SONG_FILE "%s\n",
- uri_utf8.c_str());
+ r.Format(SONG_FILE "%s\n", uri_utf8.c_str());
}
return true;
diff --git a/src/PlaylistPrint.hxx b/src/PlaylistPrint.hxx
index 38a4cc7cf..bc4c2cb47 100644
--- a/src/PlaylistPrint.hxx
+++ b/src/PlaylistPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,15 +23,18 @@
#include <stdint.h>
struct playlist;
+struct Partition;
class SongFilter;
class Client;
+class Response;
class Error;
/**
* Sends the whole playlist to the client, song URIs only.
*/
void
-playlist_print_uris(Client &client, const playlist &playlist);
+playlist_print_uris(Response &r, Partition &partition,
+ const playlist &playlist);
/**
* Sends a range of the playlist to the client, including all known
@@ -40,7 +43,8 @@ playlist_print_uris(Client &client, const playlist &playlist);
* This function however fails when the start offset is invalid.
*/
bool
-playlist_print_info(Client &client, const playlist &playlist,
+playlist_print_info(Response &r, Partition &partition,
+ const playlist &playlist,
unsigned start, unsigned end);
/**
@@ -49,8 +53,8 @@ playlist_print_info(Client &client, const playlist &playlist,
* @return true on suite, false if there is no such song
*/
bool
-playlist_print_id(Client &client, const playlist &playlist,
- unsigned id);
+playlist_print_id(Response &r, Partition &partition,
+ const playlist &playlist, unsigned id);
/**
* Sends the current song to the client.
@@ -58,20 +62,22 @@ playlist_print_id(Client &client, const playlist &playlist,
* @return true on success, false if there is no current song
*/
bool
-playlist_print_current(Client &client, const playlist &playlist);
+playlist_print_current(Response &r, Partition &partition,
+ const playlist &playlist);
/**
* Find songs in the playlist.
*/
void
-playlist_print_find(Client &client, const playlist &playlist,
+playlist_print_find(Response &r, Partition &partition,
+ const playlist &playlist,
const SongFilter &filter);
/**
* Print detailed changes since the specified playlist version.
*/
void
-playlist_print_changes_info(Client &client,
+playlist_print_changes_info(Response &r, Partition &partition,
const playlist &playlist,
uint32_t version);
@@ -79,7 +85,7 @@ playlist_print_changes_info(Client &client,
* Print changes since the specified playlist version, position only.
*/
void
-playlist_print_changes_position(Client &client,
+playlist_print_changes_position(Response &r,
const playlist &playlist,
uint32_t version);
@@ -92,7 +98,8 @@ playlist_print_changes_position(Client &client,
* @return true on success, false if the playlist does not exist
*/
bool
-spl_print(Client &client, const char *name_utf8, bool detail,
+spl_print(Response &r, Partition &partition,
+ const char *name_utf8, bool detail,
Error &error);
#endif
diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx
index 67f05267f..a2f48ba54 100644
--- a/src/PlaylistSave.cxx
+++ b/src/PlaylistSave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,9 @@
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
#include "fs/FileSystem.hxx"
+#include "fs/NarrowPath.hxx"
+#include "fs/io/FileOutputStream.hxx"
+#include "fs/io/BufferedOutputStream.hxx"
#include "util/Alloc.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
@@ -37,7 +40,7 @@
#include <string.h>
void
-playlist_print_song(FILE *file, const DetachedSong &song)
+playlist_print_song(BufferedOutputStream &os, const DetachedSong &song)
{
const char *uri_utf8 = playlist_saveAbsolutePaths
? song.GetRealURI()
@@ -45,11 +48,11 @@ playlist_print_song(FILE *file, const DetachedSong &song)
const auto uri_fs = AllocatedPath::FromUTF8(uri_utf8);
if (!uri_fs.IsNull())
- fprintf(file, "%s\n", uri_fs.c_str());
+ os.Format("%s\n", NarrowPath(uri_fs).c_str());
}
void
-playlist_print_uri(FILE *file, const char *uri)
+playlist_print_uri(BufferedOutputStream &os, const char *uri)
{
auto path =
#ifdef ENABLE_DATABASE
@@ -61,41 +64,43 @@ playlist_print_uri(FILE *file, const char *uri)
AllocatedPath::FromUTF8(uri);
if (!path.IsNull())
- fprintf(file, "%s\n", path.c_str());
+ os.Format("%s\n", NarrowPath(path).c_str());
}
-PlaylistResult
-spl_save_queue(const char *name_utf8, const Queue &queue)
+bool
+spl_save_queue(const char *name_utf8, const Queue &queue, Error &error)
{
- if (map_spl_path().IsNull())
- return PlaylistResult::DISABLED;
-
- if (!spl_valid_name(name_utf8))
- return PlaylistResult::BAD_NAME;
-
- const auto path_fs = map_spl_utf8_to_fs(name_utf8);
+ const auto path_fs = spl_map_to_fs(name_utf8, error);
if (path_fs.IsNull())
- return PlaylistResult::BAD_NAME;
+ return false;
- if (FileExists(path_fs))
- return PlaylistResult::LIST_EXISTS;
+ if (FileExists(path_fs)) {
+ error.Set(playlist_domain, int(PlaylistResult::LIST_EXISTS),
+ "Playlist already exists");
+ return false;
+ }
- FILE *file = FOpen(path_fs, FOpenMode::WriteText);
+ FileOutputStream fos(path_fs, error);
+ if (!fos.IsDefined()) {
+ TranslatePlaylistError(error);
+ return false;
+ }
- if (file == nullptr)
- return PlaylistResult::ERRNO;
+ BufferedOutputStream bos(fos);
for (unsigned i = 0; i < queue.GetLength(); i++)
- playlist_print_song(file, queue.Get(i));
+ playlist_print_song(bos, queue.Get(i));
- fclose(file);
+ if (!bos.Flush(error) || !fos.Commit(error))
+ return false;
idle_add(IDLE_STORED_PLAYLIST);
- return PlaylistResult::SUCCESS;
+ return true;
}
-PlaylistResult
-spl_save_playlist(const char *name_utf8, const playlist &playlist)
+bool
+spl_save_playlist(const char *name_utf8, const playlist &playlist,
+ Error &error)
{
- return spl_save_queue(name_utf8, playlist.queue);
+ return spl_save_queue(name_utf8, playlist.queue, error);
}
diff --git a/src/PlaylistSave.hxx b/src/PlaylistSave.hxx
index 914c8c086..536c5c8d1 100644
--- a/src/PlaylistSave.hxx
+++ b/src/PlaylistSave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,32 +20,29 @@
#ifndef MPD_PLAYLIST_SAVE_H
#define MPD_PLAYLIST_SAVE_H
-#include "PlaylistError.hxx"
-
-#include <stdio.h>
-
struct Queue;
struct playlist;
-struct PlayerControl;
+class BufferedOutputStream;
class DetachedSong;
class Error;
void
-playlist_print_song(FILE *file, const DetachedSong &song);
+playlist_print_song(BufferedOutputStream &os, const DetachedSong &song);
void
-playlist_print_uri(FILE *fp, const char *uri);
+playlist_print_uri(BufferedOutputStream &os, const char *uri);
/**
* Saves a queue object into a stored playlist file.
*/
-PlaylistResult
-spl_save_queue(const char *name_utf8, const Queue &queue);
+bool
+spl_save_queue(const char *name_utf8, const Queue &queue, Error &error);
/**
* Saves a playlist object into a stored playlist file.
*/
-PlaylistResult
-spl_save_playlist(const char *name_utf8, const playlist &playlist);
+bool
+spl_save_playlist(const char *name_utf8, const playlist &playlist,
+ Error &error);
#endif
diff --git a/src/ReplayGainConfig.cxx b/src/ReplayGainConfig.cxx
index c3bbcac3c..b8a907cdc 100644
--- a/src/ReplayGainConfig.cxx
+++ b/src/ReplayGainConfig.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "ReplayGainConfig.hxx"
#include "Idle.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigGlobal.hxx"
#include "system/FatalError.hxx"
@@ -81,7 +81,8 @@ replay_gain_set_mode_string(const char *p)
void replay_gain_global_init(void)
{
- const struct config_param *param = config_get_param(CONF_REPLAYGAIN);
+ const struct config_param *param =
+ config_get_param(ConfigOption::REPLAYGAIN);
if (param != nullptr &&
!replay_gain_set_mode_string(param->value.c_str())) {
@@ -89,7 +90,7 @@ void replay_gain_global_init(void)
param->value.c_str(), param->line);
}
- param = config_get_param(CONF_REPLAYGAIN_PREAMP);
+ param = config_get_param(ConfigOption::REPLAYGAIN_PREAMP);
if (param) {
char *test;
@@ -110,7 +111,7 @@ void replay_gain_global_init(void)
replay_gain_preamp = pow(10, f / 20.0);
}
- param = config_get_param(CONF_REPLAYGAIN_MISSING_PREAMP);
+ param = config_get_param(ConfigOption::REPLAYGAIN_MISSING_PREAMP);
if (param) {
char *test;
@@ -131,7 +132,8 @@ void replay_gain_global_init(void)
replay_gain_missing_preamp = pow(10, f / 20.0);
}
- replay_gain_limit = config_get_bool(CONF_REPLAYGAIN_LIMIT, DEFAULT_REPLAYGAIN_LIMIT);
+ replay_gain_limit = config_get_bool(ConfigOption::REPLAYGAIN_LIMIT,
+ DEFAULT_REPLAYGAIN_LIMIT);
}
ReplayGainMode
diff --git a/src/ReplayGainConfig.hxx b/src/ReplayGainConfig.hxx
index e498a56dd..986506d8b 100644
--- a/src/ReplayGainConfig.hxx
+++ b/src/ReplayGainConfig.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,14 +29,15 @@ extern float replay_gain_preamp;
extern float replay_gain_missing_preamp;
extern bool replay_gain_limit;
-void replay_gain_global_init(void);
+void
+replay_gain_global_init();
/**
* Returns the current replay gain mode as a machine-readable string.
*/
gcc_pure
const char *
-replay_gain_get_mode_string(void);
+replay_gain_get_mode_string();
/**
* Sets the replay gain mode, parsed from a string.
diff --git a/src/ReplayGainInfo.cxx b/src/ReplayGainInfo.cxx
index 580773521..98aa3360d 100644
--- a/src/ReplayGainInfo.cxx
+++ b/src/ReplayGainInfo.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/ReplayGainInfo.hxx b/src/ReplayGainInfo.hxx
index 37815c933..c94cb1fa8 100644
--- a/src/ReplayGainInfo.hxx
+++ b/src/ReplayGainInfo.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -39,8 +39,7 @@ struct ReplayGainTuple {
peak = 0.0;
}
- gcc_pure
- bool IsDefined() const {
+ constexpr bool IsDefined() const {
return gain > -100;
}
@@ -52,6 +51,11 @@ struct ReplayGainTuple {
struct ReplayGainInfo {
ReplayGainTuple tuples[2];
+ constexpr bool IsDefined() const {
+ return tuples[REPLAY_GAIN_ALBUM].IsDefined() ||
+ tuples[REPLAY_GAIN_TRACK].IsDefined();
+ }
+
void Clear() {
tuples[REPLAY_GAIN_ALBUM].Clear();
tuples[REPLAY_GAIN_TRACK].Clear();
diff --git a/src/SongFilter.cxx b/src/SongFilter.cxx
index dc0a63df3..4fc7145da 100644
--- a/src/SongFilter.cxx
+++ b/src/SongFilter.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,12 +23,12 @@
#include "DetachedSong.hxx"
#include "tag/Tag.hxx"
#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
#include "util/ASCII.hxx"
#include "util/UriUtil.hxx"
#include "lib/icu/Collate.hxx"
#include <assert.h>
-#include <string.h>
#include <stdlib.h>
#define LOCATE_TAG_FILE_KEY "file"
@@ -55,12 +55,12 @@ locate_parse_type(const char *str)
}
gcc_pure
-static std::string
+static AllocatedString<>
ImportString(const char *p, bool fold_case)
{
return fold_case
? IcuCaseFold(p)
- : std::string(p);
+ : AllocatedString<>::Duplicate(p);
}
SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
@@ -70,7 +70,7 @@ SongFilter::Item::Item(unsigned _tag, const char *_value, bool _fold_case)
}
SongFilter::Item::Item(unsigned _tag, time_t _time)
- :tag(_tag), time(_time)
+ :tag(_tag), value(nullptr), time(_time)
{
}
@@ -82,11 +82,14 @@ SongFilter::Item::StringMatch(const char *s) const
assert(s != nullptr);
#endif
+ assert(tag != LOCATE_TAG_MODIFIED_SINCE);
+
if (fold_case) {
- const std::string folded = IcuCaseFold(s);
- return folded.find(value) != folded.npos;
+ const auto folded = IcuCaseFold(s);
+ assert(!folded.IsNull());
+ return StringFind(folded.c_str(), value.c_str()) != nullptr;
} else {
- return s == value;
+ return StringIsEqual(s, value.c_str());
}
}
@@ -300,12 +303,12 @@ SongFilter::HasOtherThanBase() const
return false;
}
-std::string
+const char *
SongFilter::GetBase() const
{
for (const auto &i : items)
if (i.GetTag() == LOCATE_TAG_BASE_TYPE)
return i.GetValue();
- return std::string();
+ return nullptr;
}
diff --git a/src/SongFilter.hxx b/src/SongFilter.hxx
index f51bd85c6..e15f0338f 100644
--- a/src/SongFilter.hxx
+++ b/src/SongFilter.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,10 +20,10 @@
#ifndef MPD_SONG_FILTER_HXX
#define MPD_SONG_FILTER_HXX
+#include "util/AllocatedString.hxx"
#include "Compiler.h"
#include <list>
-#include <string>
#include <stdint.h>
#include <time.h>
@@ -51,7 +51,7 @@ public:
bool fold_case;
- std::string value;
+ AllocatedString<> value;
/**
* For #LOCATE_TAG_MODIFIED_SINCE
@@ -76,8 +76,8 @@ public:
return fold_case;
}
- const std::string &GetValue() const {
- return value;
+ const char *GetValue() const {
+ return value.c_str();
}
gcc_pure gcc_nonnull(2)
@@ -149,11 +149,11 @@ public:
bool HasOtherThanBase() const;
/**
- * Returns the "base" specification (if there is one) or an
- * empty string.
+ * Returns the "base" specification (if there is one) or
+ * nullptr.
*/
gcc_pure
- std::string GetBase() const;
+ const char *GetBase() const;
};
/**
diff --git a/src/SongLoader.cxx b/src/SongLoader.cxx
index 43e57e93b..14f9f4dd6 100644
--- a/src/SongLoader.cxx
+++ b/src/SongLoader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,19 +19,15 @@
#include "config.h"
#include "SongLoader.hxx"
+#include "LocateUri.hxx"
#include "client/Client.hxx"
#include "db/DatabaseSong.hxx"
#include "storage/StorageInterface.hxx"
-#include "ls.hxx"
-#include "fs/AllocatedPath.hxx"
-#include "fs/Traits.hxx"
-#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "DetachedSong.hxx"
#include "PlaylistError.hxx"
#include <assert.h>
-#include <string.h>
#ifdef ENABLE_DATABASE
@@ -42,7 +38,22 @@ SongLoader::SongLoader(const Client &_client)
#endif
DetachedSong *
-SongLoader::LoadFile(const char *path_utf8, Error &error) const
+SongLoader::LoadFromDatabase(const char *uri, Error &error) const
+{
+#ifdef ENABLE_DATABASE
+ if (db != nullptr)
+ return DatabaseDetachSong(*db, *storage, uri, error);
+#else
+ (void)uri;
+#endif
+
+ error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG),
+ "No database");
+ return nullptr;
+}
+
+DetachedSong *
+SongLoader::LoadFile(const char *path_utf8, Path path_fs, Error &error) const
{
#ifdef ENABLE_DATABASE
if (storage != nullptr) {
@@ -50,21 +61,12 @@ SongLoader::LoadFile(const char *path_utf8, Error &error) const
if (suffix != nullptr)
/* this path was relative to the music
directory - obtain it from the database */
- return LoadSong(suffix, error);
+ return LoadFromDatabase(suffix, error);
}
#endif
- if (client != nullptr) {
- const auto path_fs = AllocatedPath::FromUTF8(path_utf8, error);
- if (path_fs.IsNull())
- return nullptr;
-
- if (!client->AllowFile(path_fs, error))
- return nullptr;
- }
-
DetachedSong *song = new DetachedSong(path_utf8);
- if (!song->Update()) {
+ if (!song->LoadFile(path_fs)) {
error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG),
"No such file");
delete song;
@@ -75,6 +77,27 @@ SongLoader::LoadFile(const char *path_utf8, Error &error) const
}
DetachedSong *
+SongLoader::LoadSong(const LocatedUri &located_uri, Error &error) const
+{
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ gcc_unreachable();
+
+ case LocatedUri::Type::ABSOLUTE:
+ return new DetachedSong(located_uri.canonical_uri);
+
+ case LocatedUri::Type::RELATIVE:
+ return LoadFromDatabase(located_uri.canonical_uri, error);
+
+ case LocatedUri::Type::PATH:
+ return LoadFile(located_uri.canonical_uri, located_uri.path,
+ error);
+ }
+
+ gcc_unreachable();
+}
+
+DetachedSong *
SongLoader::LoadSong(const char *uri_utf8, Error &error) const
{
#if !CLANG_CHECK_VERSION(3,6)
@@ -82,33 +105,13 @@ SongLoader::LoadSong(const char *uri_utf8, Error &error) const
assert(uri_utf8 != nullptr);
#endif
- if (memcmp(uri_utf8, "file:///", 8) == 0)
- /* absolute path */
- return LoadFile(uri_utf8 + 7, error);
- else if (PathTraitsUTF8::IsAbsolute(uri_utf8))
- /* absolute path */
- return LoadFile(uri_utf8, error);
- else if (uri_has_scheme(uri_utf8)) {
- /* remove URI */
- if (!uri_supported_scheme(uri_utf8)) {
- error.Set(playlist_domain,
- int(PlaylistResult::NO_SUCH_SONG),
- "Unsupported URI scheme");
- return nullptr;
- }
-
- return new DetachedSong(uri_utf8);
- } else {
- /* URI relative to the music directory */
-
+ const auto located_uri = LocateUri(uri_utf8, client,
#ifdef ENABLE_DATABASE
- if (db != nullptr)
- return DatabaseDetachSong(*db, *storage,
- uri_utf8, error);
+ storage,
#endif
-
- error.Set(playlist_domain, int(PlaylistResult::NO_SUCH_SONG),
- "No database");
+ error);
+ if (located_uri.IsUnknown())
return nullptr;
- }
+
+ return LoadSong(located_uri, error);
}
diff --git a/src/SongLoader.hxx b/src/SongLoader.hxx
index 229703972..1c1300f11 100644
--- a/src/SongLoader.hxx
+++ b/src/SongLoader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,9 @@ class Client;
class Database;
class Storage;
class DetachedSong;
+class Path;
class Error;
+struct LocatedUri;
/**
* A utility class that loads a #DetachedSong object by its URI. If
@@ -66,12 +68,18 @@ public:
}
#endif
+ DetachedSong *LoadSong(const LocatedUri &uri, Error &error) const;
+
gcc_nonnull_all
DetachedSong *LoadSong(const char *uri_utf8, Error &error) const;
private:
gcc_nonnull_all
- DetachedSong *LoadFile(const char *path_utf8, Error &error) const;
+ DetachedSong *LoadFromDatabase(const char *uri, Error &error) const;
+
+ gcc_nonnull_all
+ DetachedSong *LoadFile(const char *path_utf8, Path path_fs,
+ Error &error) const;
};
#endif
diff --git a/src/SongPrint.cxx b/src/SongPrint.cxx
index 05d462b6d..804920f9b 100644
--- a/src/SongPrint.cxx
+++ b/src/SongPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,18 +20,20 @@
#include "config.h"
#include "SongPrint.hxx"
#include "db/LightSong.hxx"
+#include "Partition.hxx"
+#include "Instance.hxx"
#include "storage/StorageInterface.hxx"
#include "DetachedSong.hxx"
#include "TimePrint.hxx"
#include "TagPrint.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "fs/Traits.hxx"
#include "util/UriUtil.hxx"
#define SONG_FILE "file: "
static void
-song_print_uri(Client &client, const char *uri, bool base)
+song_print_uri(Response &r, Partition &partition, const char *uri, bool base)
{
std::string allocated;
@@ -39,12 +41,14 @@ song_print_uri(Client &client, const char *uri, bool base)
uri = PathTraitsUTF8::GetBase(uri);
} else {
#ifdef ENABLE_DATABASE
- const Storage *storage = client.GetStorage();
+ const Storage *storage = partition.instance.storage;
if (storage != nullptr) {
const char *suffix = storage->MapToRelativeUTF8(uri);
if (suffix != nullptr)
uri = suffix;
}
+#else
+ (void)partition;
#endif
allocated = uri_remove_auth(uri);
@@ -52,75 +56,81 @@ song_print_uri(Client &client, const char *uri, bool base)
uri = allocated.c_str();
}
- client_printf(client, "%s%s\n", SONG_FILE, uri);
+ r.Format(SONG_FILE "%s\n", uri);
}
void
-song_print_uri(Client &client, const LightSong &song, bool base)
+song_print_uri(Response &r, Partition &partition,
+ const LightSong &song, bool base)
{
- if (!base && song.directory != nullptr) {
- client_printf(client, "%s%s/%s\n", SONG_FILE,
- song.directory, song.uri);
- } else
- song_print_uri(client, song.uri, base);
+ if (!base && song.directory != nullptr)
+ r.Format(SONG_FILE "%s/%s\n", song.directory, song.uri);
+ else
+ song_print_uri(r, partition, song.uri, base);
}
void
-song_print_uri(Client &client, const DetachedSong &song, bool base)
+song_print_uri(Response &r, Partition &partition,
+ const DetachedSong &song, bool base)
{
- song_print_uri(client, song.GetURI(), base);
+ song_print_uri(r, partition, song.GetURI(), base);
}
void
-song_print_info(Client &client, const LightSong &song, bool base)
+song_print_info(Response &r, Partition &partition,
+ const LightSong &song, bool base)
{
- song_print_uri(client, song, base);
+ song_print_uri(r, partition, song, base);
const unsigned start_ms = song.start_time.ToMS();
const unsigned end_ms = song.end_time.ToMS();
if (end_ms > 0)
- client_printf(client, "Range: %u.%03u-%u.%03u\n",
- start_ms / 1000,
- start_ms % 1000,
- end_ms / 1000,
- end_ms % 1000);
+ r.Format("Range: %u.%03u-%u.%03u\n",
+ start_ms / 1000,
+ start_ms % 1000,
+ end_ms / 1000,
+ end_ms % 1000);
else if (start_ms > 0)
- client_printf(client, "Range: %u.%03u-\n",
- start_ms / 1000,
- start_ms % 1000);
+ r.Format("Range: %u.%03u-\n",
+ start_ms / 1000,
+ start_ms % 1000);
if (song.mtime > 0)
- time_print(client, "Last-Modified", song.mtime);
+ time_print(r, "Last-Modified", song.mtime);
- tag_print(client, *song.tag);
+ tag_print(r, *song.tag);
}
void
-song_print_info(Client &client, const DetachedSong &song, bool base)
+song_print_info(Response &r, Partition &partition,
+ const DetachedSong &song, bool base)
{
- song_print_uri(client, song, base);
+ song_print_uri(r, partition, song, base);
const unsigned start_ms = song.GetStartTime().ToMS();
const unsigned end_ms = song.GetEndTime().ToMS();
if (end_ms > 0)
- client_printf(client, "Range: %u.%03u-%u.%03u\n",
- start_ms / 1000,
- start_ms % 1000,
- end_ms / 1000,
- end_ms % 1000);
+ r.Format("Range: %u.%03u-%u.%03u\n",
+ start_ms / 1000,
+ start_ms % 1000,
+ end_ms / 1000,
+ end_ms % 1000);
else if (start_ms > 0)
- client_printf(client, "Range: %u.%03u-\n",
- start_ms / 1000,
- start_ms % 1000);
+ r.Format("Range: %u.%03u-\n",
+ start_ms / 1000,
+ start_ms % 1000);
if (song.GetLastModified() > 0)
- time_print(client, "Last-Modified", song.GetLastModified());
+ time_print(r, "Last-Modified", song.GetLastModified());
- tag_print_values(client, song.GetTag());
+ tag_print_values(r, song.GetTag());
const auto duration = song.GetDuration();
if (!duration.IsNegative())
- client_printf(client, "Time: %u\n", duration.RoundS());
+ r.Format("Time: %i\n"
+ "duration: %1.3f\n",
+ duration.RoundS(),
+ duration.ToDoubleS());
}
diff --git a/src/SongPrint.hxx b/src/SongPrint.hxx
index 5e4c93a74..50be70fa8 100644
--- a/src/SongPrint.hxx
+++ b/src/SongPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,18 +22,23 @@
struct LightSong;
class DetachedSong;
-class Client;
+class Response;
+struct Partition;
void
-song_print_info(Client &client, const DetachedSong &song, bool base=false);
+song_print_info(Response &r, Partition &partition,
+ const DetachedSong &song, bool base=false);
void
-song_print_info(Client &client, const LightSong &song, bool base=false);
+song_print_info(Response &r, Partition &partition,
+ const LightSong &song, bool base=false);
void
-song_print_uri(Client &client, const LightSong &song, bool base=false);
+song_print_uri(Response &r, Partition &partition,
+ const LightSong &song, bool base=false);
void
-song_print_uri(Client &client, const DetachedSong &song, bool base=false);
+song_print_uri(Response &r, Partition &partition,
+ const DetachedSong &song, bool base=false);
#endif
diff --git a/src/SongSave.cxx b/src/SongSave.cxx
index 895e9805b..8cf3a17ba 100644
--- a/src/SongSave.cxx
+++ b/src/SongSave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/SongSave.hxx b/src/SongSave.hxx
index 28c217249..318f3cf33 100644
--- a/src/SongSave.hxx
+++ b/src/SongSave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/SongUpdate.cxx b/src/SongUpdate.cxx
index 0245b9117..cf90fb9a2 100644
--- a/src/SongUpdate.cxx
+++ b/src/SongUpdate.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#include "util/Error.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/Traits.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "decoder/DecoderList.hxx"
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"
@@ -37,6 +37,10 @@
#include "TagFile.hxx"
#include "TagStream.hxx"
+#ifdef ENABLE_ARCHIVE
+#include "TagArchive.hxx"
+#endif
+
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
@@ -52,9 +56,13 @@ Song::LoadFile(Storage &storage, const char *path_utf8, Directory &parent)
Song *song = NewFile(path_utf8, parent);
//in archive ?
- bool success = parent.device == DEVICE_INARCHIVE
+ bool success =
+#ifdef ENABLE_ARCHIVE
+ parent.device == DEVICE_INARCHIVE
? song->UpdateFileInArchive(storage)
- : song->UpdateFile(storage);
+ :
+#endif
+ song->UpdateFile(storage);
if (!success) {
song->Free();
return nullptr;
@@ -83,7 +91,7 @@ Song::UpdateFile(Storage &storage)
{
const auto &relative_uri = GetURI();
- FileInfo info;
+ StorageFileInfo info;
if (!storage.GetInfo(relative_uri.c_str(), true, info, IgnoreError()))
return false;
@@ -113,6 +121,10 @@ Song::UpdateFile(Storage &storage)
return true;
}
+#endif
+
+#ifdef ENABLE_ARCHIVE
+
bool
Song::UpdateFileInArchive(const Storage &storage)
{
@@ -132,7 +144,7 @@ Song::UpdateFileInArchive(const Storage &storage)
return false;
TagBuilder tag_builder;
- if (!tag_stream_scan(path_fs.c_str(), full_tag_handler, &tag_builder))
+ if (!tag_archive_scan(path_fs, full_tag_handler, &tag_builder))
return false;
tag_builder.Commit(tag);
@@ -142,27 +154,35 @@ Song::UpdateFileInArchive(const Storage &storage)
#endif
bool
+DetachedSong::LoadFile(Path path)
+{
+ FileInfo fi;
+ if (!GetFileInfo(path, fi) || !fi.IsRegular())
+ return false;
+
+ TagBuilder tag_builder;
+ if (!tag_file_scan(path, full_tag_handler, &tag_builder))
+ return false;
+
+ if (tag_builder.IsEmpty())
+ tag_scan_fallback(path, &full_tag_handler,
+ &tag_builder);
+
+ mtime = fi.GetModificationTime();
+ tag_builder.Commit(tag);
+ return true;
+}
+
+bool
DetachedSong::Update()
{
if (IsAbsoluteFile()) {
const AllocatedPath path_fs =
AllocatedPath::FromUTF8(GetRealURI());
-
- struct stat st;
- if (!StatFile(path_fs, st) || !S_ISREG(st.st_mode))
- return false;
-
- TagBuilder tag_builder;
- if (!tag_file_scan(path_fs, full_tag_handler, &tag_builder))
+ if (path_fs.IsNull())
return false;
- if (tag_builder.IsEmpty())
- tag_scan_fallback(path_fs, &full_tag_handler,
- &tag_builder);
-
- mtime = st.st_mtime;
- tag_builder.Commit(tag);
- return true;
+ return LoadFile(path_fs);
} else if (IsRemote()) {
TagBuilder tag_builder;
if (!tag_stream_scan(uri.c_str(), full_tag_handler,
diff --git a/src/StateFile.cxx b/src/StateFile.cxx
index 7e9e35cc3..ebf6cf576 100644
--- a/src/StateFile.cxx
+++ b/src/StateFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/StateFile.hxx b/src/StateFile.hxx
index 15ba13b97..b96b89dfb 100644
--- a/src/StateFile.hxx
+++ b/src/StateFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/Stats.cxx b/src/Stats.cxx
index 39d371ace..0f92b4f47 100644
--- a/src/Stats.cxx
+++ b/src/Stats.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,8 +19,8 @@
#include "config.h"
#include "Stats.hxx"
-#include "PlayerControl.hxx"
-#include "client/Client.hxx"
+#include "player/Control.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "db/Selection.hxx"
@@ -94,7 +94,7 @@ stats_update(const Database &db)
}
static void
-db_stats_print(Client &client, const Database &db)
+db_stats_print(Response &r, const Database &db)
{
if (!stats_update(db))
return;
@@ -102,41 +102,38 @@ db_stats_print(Client &client, const Database &db)
unsigned total_duration_s =
std::chrono::duration_cast<std::chrono::seconds>(stats.total_duration).count();
- client_printf(client,
- "artists: %u\n"
- "albums: %u\n"
- "songs: %u\n"
- "db_playtime: %u\n",
- stats.artist_count,
- stats.album_count,
- stats.song_count,
- total_duration_s);
+ r.Format("artists: %u\n"
+ "albums: %u\n"
+ "songs: %u\n"
+ "db_playtime: %u\n",
+ stats.artist_count,
+ stats.album_count,
+ stats.song_count,
+ total_duration_s);
const time_t update_stamp = db.GetUpdateStamp();
if (update_stamp > 0)
- client_printf(client,
- "db_update: %lu\n",
- (unsigned long)update_stamp);
+ r.Format("db_update: %lu\n",
+ (unsigned long)update_stamp);
}
#endif
void
-stats_print(Client &client)
+stats_print(Response &r, const Partition &partition)
{
- client_printf(client,
- "uptime: %u\n"
- "playtime: %lu\n",
+ r.Format("uptime: %u\n"
+ "playtime: %lu\n",
#ifdef WIN32
- GetProcessUptimeS(),
+ GetProcessUptimeS(),
#else
- MonotonicClockS() - start_time,
+ MonotonicClockS() - start_time,
#endif
- (unsigned long)(client.player_control.GetTotalPlayTime() + 0.5));
+ (unsigned long)(partition.pc.GetTotalPlayTime() + 0.5));
#ifdef ENABLE_DATABASE
- const Database *db = client.partition.instance.database;
+ const Database *db = partition.instance.database;
if (db != nullptr)
- db_stats_print(client, *db);
+ db_stats_print(r, *db);
#endif
}
diff --git a/src/Stats.hxx b/src/Stats.hxx
index 0d36ec0b2..879e1b7be 100644
--- a/src/Stats.hxx
+++ b/src/Stats.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,14 +20,16 @@
#ifndef MPD_STATS_HXX
#define MPD_STATS_HXX
-class Client;
+class Response;
+struct Partition;
-void stats_global_init(void);
+void
+stats_global_init();
void
stats_invalidate();
void
-stats_print(Client &client);
+stats_print(Response &r, const Partition &partition);
#endif
diff --git a/src/TagArchive.cxx b/src/TagArchive.cxx
new file mode 100644
index 000000000..49f66d8f5
--- /dev/null
+++ b/src/TagArchive.cxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "TagArchive.hxx"
+#include "TagStream.hxx"
+#include "fs/Path.hxx"
+#include "util/Error.hxx"
+#include "input/InputStream.hxx"
+#include "input/plugins/ArchiveInputPlugin.hxx"
+#include "thread/Cond.hxx"
+
+#include <assert.h>
+
+bool
+tag_archive_scan(Path path, const tag_handler &handler, void *handler_ctx)
+{
+ assert(!path.IsNull());
+
+ Mutex mutex;
+ Cond cond;
+ auto *is = OpenArchiveInputStream(path, mutex, cond, IgnoreError());
+ if (is == nullptr)
+ return false;
+
+ bool result = tag_stream_scan(*is, handler, handler_ctx);
+ delete is;
+ return result;
+}
diff --git a/src/TagArchive.hxx b/src/TagArchive.hxx
new file mode 100644
index 000000000..f14d892ff
--- /dev/null
+++ b/src/TagArchive.hxx
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_TAG_ARCHIVE_HXX
+#define MPD_TAG_ARCHIVE_HXX
+
+#include "check.h"
+
+class Path;
+struct tag_handler;
+
+/**
+ * Scan the tags of a song file inside an archive. Invokes matching
+ * decoder plugins, but does not invoke the special "APE" and "ID3"
+ * scanners.
+ *
+ * @return true if the file was recognized (even if no metadata was
+ * found)
+ */
+bool
+tag_archive_scan(Path path, const tag_handler &handler, void *handler_ctx);
+
+#endif
diff --git a/src/TagFile.cxx b/src/TagFile.cxx
index 7655b96ff..0640c132e 100644
--- a/src/TagFile.cxx
+++ b/src/TagFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -87,11 +87,13 @@ tag_file_scan(Path path_fs, const tag_handler &handler, void *handler_ctx)
/* check if there's a suffix and a plugin */
- const char *suffix = uri_get_suffix(path_fs.c_str());
+ const auto *suffix = path_fs.GetSuffix();
if (suffix == nullptr)
return false;
- TagFileScan tfs(path_fs, suffix, handler, handler_ctx);
+ const auto suffix_utf8 = Path::FromFS(suffix).ToUTF8();
+
+ TagFileScan tfs(path_fs, suffix_utf8.c_str(), handler, handler_ctx);
return decoder_plugins_try([&](const DecoderPlugin &plugin){
return tfs.Scan(plugin);
});
diff --git a/src/TagFile.hxx b/src/TagFile.hxx
index b11a8ac1c..6c2c5b4bf 100644
--- a/src/TagFile.hxx
+++ b/src/TagFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/TagPrint.cxx b/src/TagPrint.cxx
index 4937fa622..d938d8fa5 100644
--- a/src/TagPrint.cxx
+++ b/src/TagPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,40 +20,38 @@
#include "config.h"
#include "TagPrint.hxx"
#include "tag/Tag.hxx"
-#include "tag/TagSettings.h"
-#include "client/Client.hxx"
+#include "tag/Settings.hxx"
+#include "client/Response.hxx"
-#define SONG_TIME "Time: "
-
-void tag_print_types(Client &client)
+void
+tag_print_types(Response &r)
{
- int i;
-
- for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
- if (!ignore_tag_items[i])
- client_printf(client, "tagtype: %s\n",
- tag_item_names[i]);
- }
+ for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++)
+ if (IsTagEnabled(i))
+ r.Format("tagtype: %s\n", tag_item_names[i]);
}
void
-tag_print(Client &client, TagType type, const char *value)
+tag_print(Response &r, TagType type, const char *value)
{
- client_printf(client, "%s: %s\n", tag_item_names[type], value);
+ r.Format("%s: %s\n", tag_item_names[type], value);
}
void
-tag_print_values(Client &client, const Tag &tag)
+tag_print_values(Response &r, const Tag &tag)
{
for (const auto &i : tag)
- client_printf(client, "%s: %s\n",
- tag_item_names[i.type], i.value);
+ r.Format("%s: %s\n", tag_item_names[i.type], i.value);
}
-void tag_print(Client &client, const Tag &tag)
+void
+tag_print(Response &r, const Tag &tag)
{
if (!tag.duration.IsNegative())
- client_printf(client, SONG_TIME "%i\n", tag.duration.RoundS());
+ r.Format("Time: %i\n"
+ "duration: %1.3f\n",
+ tag.duration.RoundS(),
+ tag.duration.ToDoubleS());
- tag_print_values(client, tag);
+ tag_print_values(r, tag);
}
diff --git a/src/TagPrint.hxx b/src/TagPrint.hxx
index 6675bb7d8..30405638e 100644
--- a/src/TagPrint.hxx
+++ b/src/TagPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,17 +25,18 @@
enum TagType : uint8_t;
struct Tag;
-class Client;
+class Response;
-void tag_print_types(Client &client);
+void
+tag_print_types(Response &response);
void
-tag_print(Client &client, TagType type, const char *value);
+tag_print(Response &response, TagType type, const char *value);
void
-tag_print_values(Client &client, const Tag &tag);
+tag_print_values(Response &response, const Tag &tag);
void
-tag_print(Client &client, const Tag &tag);
+tag_print(Response &response, const Tag &tag);
#endif
diff --git a/src/TagSave.cxx b/src/TagSave.cxx
index 107aca7db..e81de8dfd 100644
--- a/src/TagSave.cxx
+++ b/src/TagSave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/TagSave.hxx b/src/TagSave.hxx
index fd4b91f98..9b71849b9 100644
--- a/src/TagSave.hxx
+++ b/src/TagSave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/TagStream.cxx b/src/TagStream.cxx
index 6201028f6..dd5d8f7ec 100644
--- a/src/TagStream.cxx
+++ b/src/TagStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/TagStream.hxx b/src/TagStream.hxx
index 71dd71ff7..e1bd25b56 100644
--- a/src/TagStream.hxx
+++ b/src/TagStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/TimePrint.cxx b/src/TimePrint.cxx
index 5526ec7d6..f9a4dbd94 100644
--- a/src/TimePrint.cxx
+++ b/src/TimePrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,10 @@
#include "config.h"
#include "TimePrint.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
void
-time_print(Client &client, const char *name, time_t t)
+time_print(Response &r, const char *name, time_t t)
{
#ifdef WIN32
const struct tm *tm2 = gmtime(&t);
@@ -41,5 +41,5 @@ time_print(Client &client, const char *name, time_t t)
"%FT%TZ",
#endif
tm2);
- client_printf(client, "%s: %s\n", name, buffer);
+ r.Format("%s: %s\n", name, buffer);
}
diff --git a/src/TimePrint.hxx b/src/TimePrint.hxx
index afdb3c1c9..6ded9cca0 100644
--- a/src/TimePrint.hxx
+++ b/src/TimePrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,12 +22,12 @@
#include <time.h>
-class Client;
+class Response;
/**
* Write a line with a time stamp to the client.
*/
void
-time_print(Client &client, const char *name, time_t t);
+time_print(Response &r, const char *name, time_t t);
#endif
diff --git a/src/android/Context.cxx b/src/android/Context.cxx
index f75e1503e..eba00363c 100644
--- a/src/android/Context.cxx
+++ b/src/android/Context.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/android/Context.hxx b/src/android/Context.hxx
index b8a47777d..0dd1cc124 100644
--- a/src/android/Context.hxx
+++ b/src/android/Context.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/android/Environment.cxx b/src/android/Environment.cxx
index 9813b0b79..29b2a9841 100644
--- a/src/android/Environment.cxx
+++ b/src/android/Environment.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/android/Environment.hxx b/src/android/Environment.hxx
index 5a54ea361..c2e5ff3bd 100644
--- a/src/android/Environment.hxx
+++ b/src/android/Environment.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchiveDomain.cxx b/src/archive/ArchiveDomain.cxx
index 4adf4a886..801b3879a 100644
--- a/src/archive/ArchiveDomain.cxx
+++ b/src/archive/ArchiveDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchiveDomain.hxx b/src/archive/ArchiveDomain.hxx
index 817ae5835..50ac7235e 100644
--- a/src/archive/ArchiveDomain.hxx
+++ b/src/archive/ArchiveDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchiveFile.hxx b/src/archive/ArchiveFile.hxx
index 473eef70b..2afd9f7f7 100644
--- a/src/archive/ArchiveFile.hxx
+++ b/src/archive/ArchiveFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchiveList.cxx b/src/archive/ArchiveList.cxx
index 79c3a16fe..709db4dc0 100644
--- a/src/archive/ArchiveList.cxx
+++ b/src/archive/ArchiveList.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,13 @@
#include <string.h>
const ArchivePlugin *const archive_plugins[] = {
-#ifdef HAVE_BZ2
+#ifdef ENABLE_BZ2
&bz2_archive_plugin,
#endif
-#ifdef HAVE_ZZIP
+#ifdef ENABLE_ZZIP
&zzip_archive_plugin,
#endif
-#ifdef HAVE_ISO9660
+#ifdef ENABLE_ISO9660
&iso9660_archive_plugin,
#endif
nullptr
diff --git a/src/archive/ArchiveList.hxx b/src/archive/ArchiveList.hxx
index 1f1b0ae96..73d17dd13 100644
--- a/src/archive/ArchiveList.hxx
+++ b/src/archive/ArchiveList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -39,9 +39,11 @@ const ArchivePlugin *
archive_plugin_from_name(const char *name);
/* this is where we "load" all the "plugins" ;-) */
-void archive_plugin_init_all(void);
+void
+archive_plugin_init_all();
/* this is where we "unload" all the "plugins" */
-void archive_plugin_deinit_all(void);
+void
+archive_plugin_deinit_all();
#endif
diff --git a/src/archive/ArchiveLookup.cxx b/src/archive/ArchiveLookup.cxx
index 53730c504..78e2c48d0 100644
--- a/src/archive/ArchiveLookup.cxx
+++ b/src/archive/ArchiveLookup.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchiveLookup.hxx b/src/archive/ArchiveLookup.hxx
index 0c08951a9..4154e4e2f 100644
--- a/src/archive/ArchiveLookup.hxx
+++ b/src/archive/ArchiveLookup.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchivePlugin.cxx b/src/archive/ArchivePlugin.cxx
index 67f469e08..ff16c0dd5 100644
--- a/src/archive/ArchivePlugin.cxx
+++ b/src/archive/ArchivePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/ArchivePlugin.hxx b/src/archive/ArchivePlugin.hxx
index eb24bbdf9..eaf2c83c1 100644
--- a/src/archive/ArchivePlugin.hxx
+++ b/src/archive/ArchivePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,13 +32,13 @@ struct ArchivePlugin {
* have/need one this must false if there is an error and
* true otherwise
*/
- bool (*init)(void);
+ bool (*init)();
/**
* optional, set this to nullptr if the archive plugin doesn't
* have/need one
*/
- void (*finish)(void);
+ void (*finish)();
/**
* tryes to open archive file and associates handle with archive
diff --git a/src/archive/ArchiveVisitor.hxx b/src/archive/ArchiveVisitor.hxx
index 6759695ca..c0b09da28 100644
--- a/src/archive/ArchiveVisitor.hxx
+++ b/src/archive/ArchiveVisitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/plugins/Bzip2ArchivePlugin.cxx b/src/archive/plugins/Bzip2ArchivePlugin.cxx
index 2b92049dd..3b40e0b36 100644
--- a/src/archive/plugins/Bzip2ArchivePlugin.cxx
+++ b/src/archive/plugins/Bzip2ArchivePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -53,7 +53,7 @@ public:
Bzip2ArchiveFile(Path path, InputStream *_is)
:ArchiveFile(bz2_archive_plugin),
- name(PathTraitsFS::GetBase(path.c_str())),
+ name(path.GetBase().c_str()),
istream(_is) {
// remove .bz2 suffix
const size_t len = name.length();
diff --git a/src/archive/plugins/Bzip2ArchivePlugin.hxx b/src/archive/plugins/Bzip2ArchivePlugin.hxx
index 1a0a578d1..6bb439d7a 100644
--- a/src/archive/plugins/Bzip2ArchivePlugin.hxx
+++ b/src/archive/plugins/Bzip2ArchivePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/plugins/Iso9660ArchivePlugin.cxx b/src/archive/plugins/Iso9660ArchivePlugin.cxx
index ba415d3c5..e25cd0af7 100644
--- a/src/archive/plugins/Iso9660ArchivePlugin.cxx
+++ b/src/archive/plugins/Iso9660ArchivePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/plugins/Iso9660ArchivePlugin.hxx b/src/archive/plugins/Iso9660ArchivePlugin.hxx
index 9335e83b3..baec9c407 100644
--- a/src/archive/plugins/Iso9660ArchivePlugin.hxx
+++ b/src/archive/plugins/Iso9660ArchivePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/plugins/ZzipArchivePlugin.cxx b/src/archive/plugins/ZzipArchivePlugin.cxx
index 21cb693d8..4be12b7ed 100644
--- a/src/archive/plugins/ZzipArchivePlugin.cxx
+++ b/src/archive/plugins/ZzipArchivePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/archive/plugins/ZzipArchivePlugin.hxx b/src/archive/plugins/ZzipArchivePlugin.hxx
index cc92b7c52..f214584bc 100644
--- a/src/archive/plugins/ZzipArchivePlugin.hxx
+++ b/src/archive/plugins/ZzipArchivePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/check.h b/src/check.h
index efb4556d1..72826a1dc 100644
--- a/src/check.h
+++ b/src/check.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/Client.cxx b/src/client/Client.cxx
index 01ead4645..d5d153a46 100644
--- a/src/client/Client.cxx
+++ b/src/client/Client.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/Client.hxx b/src/client/Client.hxx
index c0a940ded..38127b124 100644
--- a/src/client/Client.hxx
+++ b/src/client/Client.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@
#include <stddef.h>
#include <stdarg.h>
-struct sockaddr;
+class SocketAddress;
class EventLoop;
class Path;
struct Partition;
@@ -51,12 +51,6 @@ public:
struct playlist &playlist;
struct PlayerControl &player_control;
- struct Disposer {
- void operator()(Client *client) const {
- delete client;
- }
- };
-
unsigned permission;
/** the uid of the client process, or -1 if unknown */
@@ -112,7 +106,7 @@ public:
void Close();
void SetExpired();
- using FullyBufferedSocket::Write;
+ bool Write(const void *data, size_t length);
/**
* returns the uid of the client process, or a negative value
@@ -200,11 +194,12 @@ private:
virtual void OnTimeout() override;
};
-void client_manager_init(void);
+void
+client_manager_init();
void
client_new(EventLoop &loop, Partition &partition,
- int fd, const sockaddr *sa, size_t sa_length, int uid);
+ int fd, SocketAddress address, int uid);
/**
* Write a C string to the client.
diff --git a/src/client/ClientEvent.cxx b/src/client/ClientEvent.cxx
index fd9f24b0d..0d330e975 100644
--- a/src/client/ClientEvent.cxx
+++ b/src/client/ClientEvent.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,7 @@
*/
#include "config.h"
-#include "ClientInternal.hxx"
-#include "util/Error.hxx"
+#include "Client.hxx"
#include "Log.hxx"
void
diff --git a/src/client/ClientExpire.cxx b/src/client/ClientExpire.cxx
index 5891756b6..70527312d 100644
--- a/src/client/ClientExpire.cxx
+++ b/src/client/ClientExpire.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientFile.cxx b/src/client/ClientFile.cxx
index 3ea8034d2..37979c1f9 100644
--- a/src/client/ClientFile.cxx
+++ b/src/client/ClientFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,10 +21,9 @@
#include "Client.hxx"
#include "protocol/Ack.hxx"
#include "fs/Path.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
-#include <sys/stat.h>
#include <unistd.h>
bool
@@ -47,13 +46,11 @@ Client::AllowFile(Path path_fs, Error &error) const
return false;
}
- struct stat st;
- if (!StatFile(path_fs, st)) {
- error.SetErrno();
+ FileInfo fi;
+ if (!GetFileInfo(path_fs, fi, error))
return false;
- }
- if (st.st_uid != (uid_t)uid && (st.st_mode & 0444) != 0444) {
+ if (fi.GetUid() != (uid_t)uid && (fi.GetMode() & 0444) != 0444) {
/* client is not owner */
error.Set(ack_domain, ACK_ERROR_PERMISSION, "Access denied");
return false;
diff --git a/src/client/ClientGlobal.cxx b/src/client/ClientGlobal.cxx
index 8d90721e9..078fd0981 100644
--- a/src/client/ClientGlobal.cxx
+++ b/src/client/ClientGlobal.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -31,15 +31,15 @@ size_t client_max_output_buffer_size;
void client_manager_init(void)
{
- client_timeout = config_get_positive(CONF_CONN_TIMEOUT,
+ client_timeout = config_get_positive(ConfigOption::CONN_TIMEOUT,
CLIENT_TIMEOUT_DEFAULT);
client_max_command_list_size =
- config_get_positive(CONF_MAX_COMMAND_LIST_SIZE,
+ config_get_positive(ConfigOption::MAX_COMMAND_LIST_SIZE,
CLIENT_MAX_COMMAND_LIST_DEFAULT / 1024)
* 1024;
client_max_output_buffer_size =
- config_get_positive(CONF_MAX_OUTPUT_BUFFER_SIZE,
+ config_get_positive(ConfigOption::MAX_OUTPUT_BUFFER_SIZE,
CLIENT_MAX_OUTPUT_BUFFER_SIZE_DEFAULT / 1024)
* 1024;
}
diff --git a/src/client/ClientIdle.cxx b/src/client/ClientIdle.cxx
index 0b4fa5751..b43647b6c 100644
--- a/src/client/ClientIdle.cxx
+++ b/src/client/ClientIdle.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientInternal.hxx b/src/client/ClientInternal.hxx
index a819d64b8..66bdfbb0f 100644
--- a/src/client/ClientInternal.hxx
+++ b/src/client/ClientInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientList.cxx b/src/client/ClientList.cxx
index a1f286928..375e99090 100644
--- a/src/client/ClientList.cxx
+++ b/src/client/ClientList.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,8 +20,7 @@
#include "config.h"
#include "ClientList.hxx"
#include "ClientInternal.hxx"
-
-#include <algorithm>
+#include "util/DeleteDisposer.hxx"
#include <assert.h>
@@ -36,7 +35,7 @@ ClientList::Remove(Client &client)
void
ClientList::CloseAll()
{
- list.clear_and_dispose(Client::Disposer());
+ list.clear_and_dispose(DeleteDisposer());
}
void
diff --git a/src/client/ClientList.hxx b/src/client/ClientList.hxx
index 7d20a8737..68292097c 100644
--- a/src/client/ClientList.hxx
+++ b/src/client/ClientList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientMessage.cxx b/src/client/ClientMessage.cxx
index be6d2f007..84838219e 100644
--- a/src/client/ClientMessage.cxx
+++ b/src/client/ClientMessage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientMessage.hxx b/src/client/ClientMessage.hxx
index bc6a4cd41..13804e715 100644
--- a/src/client/ClientMessage.hxx
+++ b/src/client/ClientMessage.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_CLIENT_MESSAGE_H
-#define MPD_CLIENT_MESSAGE_H
+#ifndef MPD_CLIENT_MESSAGE_HXX
+#define MPD_CLIENT_MESSAGE_HXX
#include "Compiler.h"
diff --git a/src/client/ClientNew.cxx b/src/client/ClientNew.cxx
index a080e9ec6..90c81f2c6 100644
--- a/src/client/ClientNew.cxx
+++ b/src/client/ClientNew.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,8 @@
#include "Partition.hxx"
#include "Instance.hxx"
#include "system/fd_util.h"
-#include "system/Resolver.hxx"
+#include "net/SocketAddress.hxx"
+#include "net/ToString.hxx"
#include "Permission.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -58,15 +59,15 @@ Client::Client(EventLoop &_loop, Partition &_partition,
void
client_new(EventLoop &loop, Partition &partition,
- int fd, const struct sockaddr *sa, size_t sa_length, int uid)
+ int fd, SocketAddress address, int uid)
{
static unsigned int next_client_num;
- const auto remote = sockaddr_to_string(sa, sa_length);
+ const auto remote = ToString(address);
assert(fd >= 0);
#ifdef HAVE_LIBWRAP
- if (sa->sa_family != AF_UNIX) {
+ if (address.GetFamily() != AF_UNIX) {
// TODO: shall we obtain the program name from argv[0]?
const char *progname = "mpd";
diff --git a/src/client/ClientProcess.cxx b/src/client/ClientProcess.cxx
index 0b6953371..1502e0d96 100644
--- a/src/client/ClientProcess.cxx
+++ b/src/client/ClientProcess.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,7 @@
#include "protocol/Result.hxx"
#include "command/AllCommands.hxx"
#include "Log.hxx"
-
-#include <string.h>
+#include "util/StringAPI.hxx"
#define CLIENT_LIST_MODE_BEGIN "command_list_begin"
#define CLIENT_LIST_OK_MODE_BEGIN "command_list_ok_begin"
@@ -56,7 +55,7 @@ client_process_line(Client &client, char *line)
{
CommandResult ret;
- if (strcmp(line, "noidle") == 0) {
+ if (StringIsEqual(line, "noidle")) {
if (client.idle_waiting) {
/* send empty idle response and leave idle mode */
client.idle_waiting = false;
@@ -78,7 +77,7 @@ client_process_line(Client &client, char *line)
}
if (client.cmd_list.IsActive()) {
- if (strcmp(line, CLIENT_LIST_MODE_END) == 0) {
+ if (StringIsEqual(line, CLIENT_LIST_MODE_END)) {
FormatDebug(client_domain,
"[%u] process command list",
client.num);
@@ -113,10 +112,10 @@ client_process_line(Client &client, char *line)
ret = CommandResult::OK;
}
} else {
- if (strcmp(line, CLIENT_LIST_MODE_BEGIN) == 0) {
+ if (StringIsEqual(line, CLIENT_LIST_MODE_BEGIN)) {
client.cmd_list.Begin(false);
ret = CommandResult::OK;
- } else if (strcmp(line, CLIENT_LIST_OK_MODE_BEGIN) == 0) {
+ } else if (StringIsEqual(line, CLIENT_LIST_OK_MODE_BEGIN)) {
client.cmd_list.Begin(true);
ret = CommandResult::OK;
} else {
diff --git a/src/client/ClientRead.cxx b/src/client/ClientRead.cxx
index 9cfb1271f..7a1e937ed 100644
--- a/src/client/ClientRead.cxx
+++ b/src/client/ClientRead.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientSubscribe.cxx b/src/client/ClientSubscribe.cxx
index 8ea2e363b..ebc4848f5 100644
--- a/src/client/ClientSubscribe.cxx
+++ b/src/client/ClientSubscribe.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/client/ClientWrite.cxx b/src/client/ClientWrite.cxx
index b5d172a8d..f30f2f8b3 100644
--- a/src/client/ClientWrite.cxx
+++ b/src/client/ClientWrite.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,35 +18,29 @@
*/
#include "config.h"
-#include "ClientInternal.hxx"
+#include "Client.hxx"
#include "util/FormatString.hxx"
#include <string.h>
-/**
- * Write a block of data to the client.
- */
-static void
-client_write(Client &client, const char *data, size_t length)
+bool
+Client::Write(const void *data, size_t length)
{
/* if the client is going to be closed, do nothing */
- if (client.IsExpired() || length == 0)
- return;
-
- client.Write(data, length);
+ return !IsExpired() && FullyBufferedSocket::Write(data, length);
}
void
client_puts(Client &client, const char *s)
{
- client_write(client, s, strlen(s));
+ client.Write(s, strlen(s));
}
void
client_vprintf(Client &client, const char *fmt, va_list args)
{
char *p = FormatNewV(fmt, args);
- client_write(client, p, strlen(p));
+ client.Write(p, strlen(p));
delete[] p;
}
diff --git a/src/client/Response.cxx b/src/client/Response.cxx
new file mode 100644
index 000000000..d443e66a5
--- /dev/null
+++ b/src/client/Response.cxx
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Response.hxx"
+#include "Client.hxx"
+#include "util/FormatString.hxx"
+
+#include <string.h>
+
+bool
+Response::Write(const void *data, size_t length)
+{
+ return client.Write(data, length);
+}
+
+bool
+Response::Write(const char *data)
+{
+ return Write(data, strlen(data));
+}
+
+bool
+Response::FormatV(const char *fmt, va_list args)
+{
+ char *p = FormatNewV(fmt, args);
+ bool success = Write(p);
+ delete[] p;
+ return success;
+}
+
+bool
+Response::Format(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ bool success = FormatV(fmt, args);
+ va_end(args);
+ return success;
+}
+
+void
+Response::Error(enum ack code, const char *msg)
+{
+ FormatError(code, "%s", msg);
+}
+
+void
+Response::FormatError(enum ack code, const char *fmt, ...)
+{
+ Format("ACK [%i@%u] {%s} ",
+ (int)code, list_index, command);
+
+ va_list args;
+ va_start(args, fmt);
+ FormatV(fmt, args);
+ va_end(args);
+
+ Write("\n");
+}
diff --git a/src/client/Response.hxx b/src/client/Response.hxx
new file mode 100644
index 000000000..5841e7f61
--- /dev/null
+++ b/src/client/Response.hxx
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_RESPONSE_HXX
+#define MPD_RESPONSE_HXX
+
+#include "check.h"
+#include "protocol/Ack.hxx"
+
+#include <stddef.h>
+#include <stdarg.h>
+
+class Client;
+
+class Response {
+ Client &client;
+
+ /**
+ * This command's index in the command list. Used to generate
+ * error messages.
+ */
+ const unsigned list_index;
+
+ /**
+ * This command's name. Used to generate error messages.
+ */
+ const char *command;
+
+public:
+ Response(Client &_client, unsigned _list_index)
+ :client(_client), list_index(_list_index), command("") {}
+
+ Response(const Response &) = delete;
+ Response &operator=(const Response &) = delete;
+
+ void SetCommand(const char *_command) {
+ command = _command;
+ }
+
+ bool Write(const void *data, size_t length);
+ bool Write(const char *data);
+ bool FormatV(const char *fmt, va_list args);
+ bool Format(const char *fmt, ...);
+
+ void Error(enum ack code, const char *msg);
+ void FormatError(enum ack code, const char *fmt, ...);
+};
+
+#endif
diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index 6a4b18198..8e8865ff3 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "AllCommands.hxx"
+#include "Request.hxx"
#include "QueueCommands.hxx"
#include "TagCommands.hxx"
#include "PlayerCommands.hxx"
@@ -32,11 +33,14 @@
#include "OtherCommands.hxx"
#include "Permission.hxx"
#include "tag/TagType.h"
-#include "protocol/Result.hxx"
#include "Partition.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
+#include "util/Macros.hxx"
#include "util/Tokenizer.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
#ifdef ENABLE_SQLITE
#include "StickerCommands.hxx"
@@ -60,22 +64,22 @@ struct command {
unsigned permission;
int min;
int max;
- CommandResult (*handler)(Client &client, unsigned argc, char **argv);
+ CommandResult (*handler)(Client &client, Request request, Response &response);
};
/* don't be fooled, this is the command handler for "commands" command */
static CommandResult
-handle_commands(Client &client, unsigned argc, char *argv[]);
+handle_commands(Client &client, Request request, Response &response);
static CommandResult
-handle_not_commands(Client &client, unsigned argc, char *argv[]);
+handle_not_commands(Client &client, Request request, Response &response);
/**
* The command registry.
*
* This array must be sorted!
*/
-static const struct command commands[] = {
+static constexpr struct command commands[] = {
{ "add", PERMISSION_ADD, 1, 1, handle_add },
{ "addid", PERMISSION_ADD, 1, 2, handle_addid },
{ "addtagid", PERMISSION_ADD, 3, 3, handle_addtagid },
@@ -194,62 +198,79 @@ static const struct command commands[] = {
{ "volume", PERMISSION_CONTROL, 1, 1, handle_volume },
};
-static const unsigned num_commands = sizeof(commands) / sizeof(commands[0]);
+static constexpr unsigned num_commands = ARRAY_SIZE(commands);
static bool
command_available(gcc_unused const Partition &partition,
gcc_unused const struct command *cmd)
{
#ifdef ENABLE_SQLITE
- if (strcmp(cmd->cmd, "sticker") == 0)
+ if (StringIsEqual(cmd->cmd, "sticker"))
return sticker_enabled();
#endif
#ifdef ENABLE_NEIGHBOR_PLUGINS
- if (strcmp(cmd->cmd, "listneighbors") == 0)
+ if (StringIsEqual(cmd->cmd, "listneighbors"))
return neighbor_commands_available(partition.instance);
#endif
+ if (StringIsEqual(cmd->cmd, "save") ||
+ StringIsEqual(cmd->cmd, "rm") ||
+ StringIsEqual(cmd->cmd, "rename") ||
+ StringIsEqual(cmd->cmd, "playlistdelete") ||
+ StringIsEqual(cmd->cmd, "playlistmove") ||
+ StringIsEqual(cmd->cmd, "playlistclear") ||
+ StringIsEqual(cmd->cmd, "playlistadd") ||
+ StringIsEqual(cmd->cmd, "listplaylists"))
+ return playlist_commands_available();
+
return true;
}
-/* don't be fooled, this is the command handler for "commands" command */
static CommandResult
-handle_commands(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+PrintAvailableCommands(Response &r, const Partition &partition,
+ unsigned permission)
{
- const unsigned permission = client.GetPermission();
- const struct command *cmd;
-
for (unsigned i = 0; i < num_commands; ++i) {
- cmd = &commands[i];
+ const struct command *cmd = &commands[i];
if (cmd->permission == (permission & cmd->permission) &&
- command_available(client.partition, cmd))
- client_printf(client, "command: %s\n", cmd->cmd);
+ command_available(partition, cmd))
+ r.Format("command: %s\n", cmd->cmd);
}
return CommandResult::OK;
}
static CommandResult
-handle_not_commands(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+PrintUnavailableCommands(Response &r, unsigned permission)
{
- const unsigned permission = client.GetPermission();
- const struct command *cmd;
-
for (unsigned i = 0; i < num_commands; ++i) {
- cmd = &commands[i];
+ const struct command *cmd = &commands[i];
if (cmd->permission != (permission & cmd->permission))
- client_printf(client, "command: %s\n", cmd->cmd);
+ r.Format("command: %s\n", cmd->cmd);
}
return CommandResult::OK;
}
-void command_init(void)
+/* don't be fooled, this is the command handler for "commands" command */
+static CommandResult
+handle_commands(Client &client, gcc_unused Request request, Response &r)
+{
+ return PrintAvailableCommands(r, client.partition,
+ client.GetPermission());
+}
+
+static CommandResult
+handle_not_commands(Client &client, gcc_unused Request request, Response &r)
+{
+ return PrintUnavailableCommands(r, client.GetPermission());
+}
+
+void
+command_init()
{
#ifndef NDEBUG
/* ensure that the command list is sorted */
@@ -258,7 +279,8 @@ void command_init(void)
#endif
}
-void command_finish(void)
+void
+command_finish()
{
}
@@ -266,13 +288,12 @@ static const struct command *
command_lookup(const char *name)
{
unsigned a = 0, b = num_commands, i;
- int cmp;
/* binary search */
do {
i = (a + b) / 2;
- cmp = strcmp(name, commands[i].cmd);
+ const auto cmp = strcmp(name, commands[i].cmd);
if (cmp == 0)
return &commands[i];
else if (cmp < 0)
@@ -285,60 +306,53 @@ command_lookup(const char *name)
}
static bool
-command_check_request(const struct command *cmd, Client &client,
- unsigned permission, unsigned argc, char *argv[])
+command_check_request(const struct command *cmd, Response &r,
+ unsigned permission, Request args)
{
- const unsigned min = cmd->min + 1;
- const unsigned max = cmd->max + 1;
-
if (cmd->permission != (permission & cmd->permission)) {
- command_error(client, ACK_ERROR_PERMISSION,
+ r.FormatError(ACK_ERROR_PERMISSION,
"you don't have permission for \"%s\"",
cmd->cmd);
return false;
}
- if (min == 0)
+ const int min = cmd->min;
+ const int max = cmd->max;
+
+ if (min < 0)
return true;
- if (min == max && max != argc) {
- command_error(client, ACK_ERROR_ARG,
+ if (min == max && unsigned(max) != args.size) {
+ r.FormatError(ACK_ERROR_ARG,
"wrong number of arguments for \"%s\"",
- argv[0]);
+ cmd->cmd);
return false;
- } else if (argc < min) {
- command_error(client, ACK_ERROR_ARG,
- "too few arguments for \"%s\"", argv[0]);
+ } else if (args.size < unsigned(min)) {
+ r.FormatError(ACK_ERROR_ARG,
+ "too few arguments for \"%s\"", cmd->cmd);
return false;
- } else if (argc > max && max /* != 0 */ ) {
- command_error(client, ACK_ERROR_ARG,
- "too many arguments for \"%s\"", argv[0]);
+ } else if (max >= 0 && args.size > unsigned(max)) {
+ r.FormatError(ACK_ERROR_ARG,
+ "too many arguments for \"%s\"", cmd->cmd);
return false;
} else
return true;
}
static const struct command *
-command_checked_lookup(Client &client, unsigned permission,
- unsigned argc, char *argv[])
+command_checked_lookup(Response &r, unsigned permission,
+ const char *cmd_name, Request args)
{
- const struct command *cmd;
-
- current_command = "";
-
- if (argc == 0)
- return nullptr;
-
- cmd = command_lookup(argv[0]);
+ const struct command *cmd = command_lookup(cmd_name);
if (cmd == nullptr) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "unknown command \"%s\"", argv[0]);
+ r.FormatError(ACK_ERROR_UNKNOWN,
+ "unknown command \"%s\"", cmd_name);
return nullptr;
}
- current_command = cmd->cmd;
+ r.SetCommand(cmd->cmd);
- if (!command_check_request(cmd, client, permission, argc, argv))
+ if (!command_check_request(cmd, r, permission, args))
return nullptr;
return cmd;
@@ -347,68 +361,59 @@ command_checked_lookup(Client &client, unsigned permission,
CommandResult
command_process(Client &client, unsigned num, char *line)
{
+ Response r(client, num);
Error error;
- char *argv[COMMAND_ARGV_MAX] = { nullptr };
- const struct command *cmd;
- CommandResult ret = CommandResult::ERROR;
-
- command_list_num = num;
/* get the command name (first word on the line) */
+ /* we have to set current_command because Response::Error()
+ expects it to be set */
Tokenizer tokenizer(line);
- argv[0] = tokenizer.NextWord(error);
- if (argv[0] == nullptr) {
- current_command = "";
+
+ const char *const cmd_name = tokenizer.NextWord(error);
+ if (cmd_name == nullptr) {
if (tokenizer.IsEnd())
- command_error(client, ACK_ERROR_UNKNOWN,
- "No command given");
+ r.FormatError(ACK_ERROR_UNKNOWN, "No command given");
else
- command_error(client, ACK_ERROR_UNKNOWN,
- "%s", error.GetMessage());
-
- current_command = nullptr;
+ r.Error(ACK_ERROR_UNKNOWN, error.GetMessage());
/* this client does not speak the MPD protocol; kick
the connection */
return CommandResult::FINISH;
}
- unsigned argc = 1;
+ char *argv[COMMAND_ARGV_MAX];
+ Request args(argv, 0);
/* now parse the arguments (quoted or unquoted) */
- while (argc < COMMAND_ARGV_MAX &&
- (argv[argc] =
- tokenizer.NextParam(error)) != nullptr)
- ++argc;
-
- /* some error checks; we have to set current_command because
- command_error() expects it to be set */
+ while (true) {
+ if (args.size == COMMAND_ARGV_MAX) {
+ r.Error(ACK_ERROR_ARG, "Too many arguments");
+ return CommandResult::ERROR;
+ }
- current_command = argv[0];
+ char *a = tokenizer.NextParam(error);
+ if (a == nullptr) {
+ if (tokenizer.IsEnd())
+ break;
- if (argc >= COMMAND_ARGV_MAX) {
- command_error(client, ACK_ERROR_ARG, "Too many arguments");
- current_command = nullptr;
- return CommandResult::ERROR;
- }
+ r.Error(ACK_ERROR_UNKNOWN, error.GetMessage());
+ return CommandResult::ERROR;
+ }
- if (!tokenizer.IsEnd()) {
- command_error(client, ACK_ERROR_ARG, "%s", error.GetMessage());
- current_command = nullptr;
- return CommandResult::ERROR;
+ argv[args.size++] = a;
}
/* look up and invoke the command handler */
- cmd = command_checked_lookup(client, client.GetPermission(),
- argc, argv);
- if (cmd)
- ret = cmd->handler(client, argc, argv);
+ const struct command *cmd =
+ command_checked_lookup(r, client.GetPermission(),
+ cmd_name, args);
- current_command = nullptr;
- command_list_num = 0;
+ CommandResult ret = cmd
+ ? cmd->handler(client, args, r)
+ : CommandResult::ERROR;
return ret;
}
diff --git a/src/command/AllCommands.hxx b/src/command/AllCommands.hxx
index b7834a8de..e3405b034 100644
--- a/src/command/AllCommands.hxx
+++ b/src/command/AllCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,9 +24,11 @@
class Client;
-void command_init(void);
+void
+command_init();
-void command_finish(void);
+void
+command_finish();
CommandResult
command_process(Client &client, unsigned num, char *line);
diff --git a/src/command/CommandError.cxx b/src/command/CommandError.cxx
index 89085fc68..9f06431b4 100644
--- a/src/command/CommandError.cxx
+++ b/src/command/CommandError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,8 @@
#include "config.h"
#include "CommandError.hxx"
#include "db/DatabaseError.hxx"
-#include "protocol/Result.hxx"
+#include "LocateUri.hxx"
+#include "client/Response.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -29,57 +30,55 @@
#include <errno.h>
CommandResult
-print_playlist_result(Client &client, PlaylistResult result)
+print_playlist_result(Response &r, PlaylistResult result)
{
switch (result) {
case PlaylistResult::SUCCESS:
return CommandResult::OK;
case PlaylistResult::ERRNO:
- command_error(client, ACK_ERROR_SYSTEM, "%s",
- strerror(errno));
+ r.Error(ACK_ERROR_SYSTEM, strerror(errno));
return CommandResult::ERROR;
case PlaylistResult::DENIED:
- command_error(client, ACK_ERROR_PERMISSION, "Access denied");
+ r.Error(ACK_ERROR_PERMISSION, "Access denied");
return CommandResult::ERROR;
case PlaylistResult::NO_SUCH_SONG:
- command_error(client, ACK_ERROR_NO_EXIST, "No such song");
+ r.Error(ACK_ERROR_NO_EXIST, "No such song");
return CommandResult::ERROR;
case PlaylistResult::NO_SUCH_LIST:
- command_error(client, ACK_ERROR_NO_EXIST, "No such playlist");
+ r.Error(ACK_ERROR_NO_EXIST, "No such playlist");
return CommandResult::ERROR;
case PlaylistResult::LIST_EXISTS:
- command_error(client, ACK_ERROR_EXIST,
- "Playlist already exists");
+ r.Error(ACK_ERROR_EXIST, "Playlist already exists");
return CommandResult::ERROR;
case PlaylistResult::BAD_NAME:
- command_error(client, ACK_ERROR_ARG,
- "playlist name is invalid: "
- "playlist names may not contain slashes,"
- " newlines or carriage returns");
+ r.Error(ACK_ERROR_ARG,
+ "playlist name is invalid: "
+ "playlist names may not contain slashes,"
+ " newlines or carriage returns");
return CommandResult::ERROR;
case PlaylistResult::BAD_RANGE:
- command_error(client, ACK_ERROR_ARG, "Bad song index");
+ r.Error(ACK_ERROR_ARG, "Bad song index");
return CommandResult::ERROR;
case PlaylistResult::NOT_PLAYING:
- command_error(client, ACK_ERROR_PLAYER_SYNC, "Not playing");
+ r.Error(ACK_ERROR_PLAYER_SYNC, "Not playing");
return CommandResult::ERROR;
case PlaylistResult::TOO_LARGE:
- command_error(client, ACK_ERROR_PLAYLIST_MAX,
- "playlist is at the max size");
+ r.Error(ACK_ERROR_PLAYLIST_MAX,
+ "playlist is at the max size");
return CommandResult::ERROR;
case PlaylistResult::DISABLED:
- command_error(client, ACK_ERROR_UNKNOWN,
- "stored playlist support is disabled");
+ r.Error(ACK_ERROR_UNKNOWN,
+ "stored playlist support is disabled");
return CommandResult::ERROR;
}
@@ -88,42 +87,42 @@ print_playlist_result(Client &client, PlaylistResult result)
}
CommandResult
-print_error(Client &client, const Error &error)
+print_error(Response &r, const Error &error)
{
assert(error.IsDefined());
LogError(error);
if (error.IsDomain(playlist_domain)) {
- return print_playlist_result(client,
+ return print_playlist_result(r,
PlaylistResult(error.GetCode()));
} else if (error.IsDomain(ack_domain)) {
- command_error(client, (ack)error.GetCode(),
- "%s", error.GetMessage());
+ r.Error((ack)error.GetCode(), error.GetMessage());
return CommandResult::ERROR;
#ifdef ENABLE_DATABASE
} else if (error.IsDomain(db_domain)) {
switch ((enum db_error)error.GetCode()) {
case DB_DISABLED:
- command_error(client, ACK_ERROR_NO_EXIST, "%s",
- error.GetMessage());
+ r.Error(ACK_ERROR_NO_EXIST, error.GetMessage());
return CommandResult::ERROR;
case DB_NOT_FOUND:
- command_error(client, ACK_ERROR_NO_EXIST, "Not found");
+ r.Error(ACK_ERROR_NO_EXIST, "Not found");
return CommandResult::ERROR;
case DB_CONFLICT:
- command_error(client, ACK_ERROR_ARG, "Conflict");
+ r.Error(ACK_ERROR_ARG, "Conflict");
return CommandResult::ERROR;
}
#endif
+ } else if (error.IsDomain(locate_uri_domain)) {
+ r.Error(ACK_ERROR_ARG, error.GetMessage());
+ return CommandResult::ERROR;
} else if (error.IsDomain(errno_domain)) {
- command_error(client, ACK_ERROR_SYSTEM, "%s",
- strerror(error.GetCode()));
+ r.Error(ACK_ERROR_SYSTEM, strerror(error.GetCode()));
return CommandResult::ERROR;
}
- command_error(client, ACK_ERROR_UNKNOWN, "error");
+ r.Error(ACK_ERROR_UNKNOWN, "error");
return CommandResult::ERROR;
}
diff --git a/src/command/CommandError.hxx b/src/command/CommandError.hxx
index b48baa5bf..e33386078 100644
--- a/src/command/CommandError.hxx
+++ b/src/command/CommandError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,16 +23,16 @@
#include "CommandResult.hxx"
#include "PlaylistError.hxx"
-class Client;
+class Response;
class Error;
CommandResult
-print_playlist_result(Client &client, PlaylistResult result);
+print_playlist_result(Response &r, PlaylistResult result);
/**
* Send the #Error to the client.
*/
CommandResult
-print_error(Client &client, const Error &error);
+print_error(Response &r, const Error &error);
#endif
diff --git a/src/command/CommandListBuilder.cxx b/src/command/CommandListBuilder.cxx
index 477c246ff..4abb3ad16 100644
--- a/src/command/CommandListBuilder.cxx
+++ b/src/command/CommandListBuilder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,6 @@ void
CommandListBuilder::Reset()
{
list.clear();
- size = 0;
mode = Mode::DISABLED;
}
diff --git a/src/command/CommandListBuilder.hxx b/src/command/CommandListBuilder.hxx
index 0747c4697..9908121d6 100644
--- a/src/command/CommandListBuilder.hxx
+++ b/src/command/CommandListBuilder.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@ class CommandListBuilder {
public:
CommandListBuilder()
- :mode(Mode::DISABLED), size(0) {}
+ :mode(Mode::DISABLED) {}
/**
* Is a command list currently being built?
@@ -89,6 +89,7 @@ public:
assert(mode == Mode::DISABLED);
mode = (Mode)ok;
+ size = 0;
}
/**
diff --git a/src/command/CommandResult.hxx b/src/command/CommandResult.hxx
index a2e968fb6..13641ec39 100644
--- a/src/command/CommandResult.hxx
+++ b/src/command/CommandResult.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx
index a3ea8d0ae..bfcf3aa54 100644
--- a/src/command/DatabaseCommands.cxx
+++ b/src/command/DatabaseCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "DatabaseCommands.hxx"
+#include "Request.hxx"
#include "db/DatabaseGlue.hxx"
#include "db/DatabaseQueue.hxx"
#include "db/DatabasePlaylist.hxx"
@@ -27,83 +28,89 @@
#include "db/Selection.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "tag/Tag.hxx"
#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
+#include "util/StringAPI.hxx"
#include "SongFilter.hxx"
-#include "protocol/Result.hxx"
#include "BulkEdit.hxx"
#include <string.h>
CommandResult
-handle_listfiles_db(Client &client, const char *uri)
+handle_listfiles_db(Client &client, Response &r, const char *uri)
{
const DatabaseSelection selection(uri, false);
Error error;
- if (!db_selection_print(client, selection, false, true, error))
- return print_error(client, error);
+ if (!db_selection_print(r, client.partition,
+ selection, false, true, error))
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_lsinfo2(Client &client, unsigned argc, char *argv[])
+handle_lsinfo2(Client &client, const char *uri, Response &r)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
const DatabaseSelection selection(uri, false);
Error error;
- if (!db_selection_print(client, selection, true, false, error))
- return print_error(client, error);
+ if (!db_selection_print(r, client.partition,
+ selection, true, false, error))
+ return print_error(r, error);
return CommandResult::OK;
}
static CommandResult
-handle_match(Client &client, unsigned argc, char *argv[], bool fold_case)
+handle_match(Client &client, Request args, Response &r, bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
+ RangeArg window;
+ if (args.size >= 2 && StringIsEqual(args[args.size - 2], "window")) {
+ if (!args.Parse(args.size - 1, window, r))
+ return CommandResult::ERROR;
+
+ args.pop_back();
+ args.pop_back();
+ } else
+ window.SetAll();
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
const DatabaseSelection selection("", true, &filter);
Error error;
- return db_selection_print(client, selection, true, false, error)
+ return db_selection_print(r, client.partition,
+ selection, true, false,
+ window.start, window.end, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_find(Client &client, unsigned argc, char *argv[])
+handle_find(Client &client, Request args, Response &r)
{
- return handle_match(client, argc, argv, false);
+ return handle_match(client, args, r, false);
}
CommandResult
-handle_search(Client &client, unsigned argc, char *argv[])
+handle_search(Client &client, Request args, Response &r)
{
- return handle_match(client, argc, argv, true);
+ return handle_match(client, args, r, true);
}
static CommandResult
-handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case)
+handle_match_add(Client &client, Request args, Response &r, bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
@@ -113,55 +120,52 @@ handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case)
Error error;
return AddFromDatabase(client.partition, selection, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_findadd(Client &client, unsigned argc, char *argv[])
+handle_findadd(Client &client, Request args, Response &r)
{
- return handle_match_add(client, argc, argv, false);
+ return handle_match_add(client, args, r, false);
}
CommandResult
-handle_searchadd(Client &client, unsigned argc, char *argv[])
+handle_searchadd(Client &client, Request args, Response &r)
{
- return handle_match_add(client, argc, argv, true);
+ return handle_match_add(client, args, r, true);
}
CommandResult
-handle_searchaddpl(Client &client, unsigned argc, char *argv[])
+handle_searchaddpl(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
const char *playlist = args.shift();
SongFilter filter;
if (!filter.Parse(args, true)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
Error error;
const Database *db = client.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
return search_add_to_playlist(*db, *client.GetStorage(),
"", playlist, &filter, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_count(Client &client, unsigned argc, char *argv[])
+handle_count(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
TagType group = TAG_NUM_OF_ITEM_TYPES;
- if (args.size >= 2 && strcmp(args[args.size - 2], "group") == 0) {
+ if (args.size >= 2 && StringIsEqual(args[args.size - 2], "group")) {
const char *s = args[args.size - 1];
group = tag_name_parse_i(s);
if (group == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", s);
return CommandResult::ERROR;
}
@@ -172,52 +176,50 @@ handle_count(Client &client, unsigned argc, char *argv[])
SongFilter filter;
if (!args.IsEmpty() && !filter.Parse(args, false)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
Error error;
- return PrintSongCount(client, "", &filter, group, error)
+ return PrintSongCount(r, client.partition, "", &filter, group, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_listall(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listall(Client &client, Request args, Response &r)
{
- const char *directory = "";
-
- if (argc == 2)
- directory = argv[1];
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
Error error;
- return db_selection_print(client, DatabaseSelection(directory, true),
+ return db_selection_print(r, client.partition,
+ DatabaseSelection(uri, true),
false, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_list(Client &client, unsigned argc, char *argv[])
+handle_list(Client &client, Request args, Response &r)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
const char *tag_name = args.shift();
unsigned tagType = locate_parse_type(tag_name);
if (tagType >= TAG_NUM_OF_ITEM_TYPES &&
tagType != LOCATE_TAG_FILE_TYPE) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
SongFilter *filter = nullptr;
- uint32_t group_mask = 0;
+ tag_mask_t group_mask = 0;
if (args.size == 1) {
/* for compatibility with < 0.12.0 */
if (tagType != TAG_ALBUM) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"should be \"%s\" for 3 arguments",
tag_item_names[TAG_ALBUM]);
return CommandResult::ERROR;
@@ -227,16 +229,16 @@ handle_list(Client &client, unsigned argc, char *argv[])
}
while (args.size >= 2 &&
- strcmp(args[args.size - 2], "group") == 0) {
+ StringIsEqual(args[args.size - 2], "group")) {
const char *s = args[args.size - 1];
TagType gt = tag_name_parse_i(s);
if (gt == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", s);
return CommandResult::ERROR;
}
- group_mask |= 1u << unsigned(gt);
+ group_mask |= tag_mask_t(1) << unsigned(gt);
args.pop_back();
args.pop_back();
@@ -246,24 +248,24 @@ handle_list(Client &client, unsigned argc, char *argv[])
filter = new SongFilter();
if (!filter->Parse(args, false)) {
delete filter;
- command_error(client, ACK_ERROR_ARG,
- "not able to parse args");
+ r.Error(ACK_ERROR_ARG, "not able to parse args");
return CommandResult::ERROR;
}
}
if (tagType < TAG_NUM_OF_ITEM_TYPES &&
- group_mask & (1u << tagType)) {
+ group_mask & (tag_mask_t(1) << tagType)) {
delete filter;
- command_error(client, ACK_ERROR_ARG, "Conflicting group");
+ r.Error(ACK_ERROR_ARG, "Conflicting group");
return CommandResult::ERROR;
}
Error error;
CommandResult ret =
- PrintUniqueTags(client, tagType, group_mask, filter, error)
+ PrintUniqueTags(r, client.partition,
+ tagType, group_mask, filter, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
delete filter;
@@ -271,16 +273,15 @@ handle_list(Client &client, unsigned argc, char *argv[])
}
CommandResult
-handle_listallinfo(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listallinfo(Client &client, Request args, Response &r)
{
- const char *directory = "";
-
- if (argc == 2)
- directory = argv[1];
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
Error error;
- return db_selection_print(client, DatabaseSelection(directory, true),
+ return db_selection_print(r, client.partition,
+ DatabaseSelection(uri, true),
true, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
diff --git a/src/command/DatabaseCommands.hxx b/src/command/DatabaseCommands.hxx
index 7abf89e0c..660e147db 100644
--- a/src/command/DatabaseCommands.hxx
+++ b/src/command/DatabaseCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,38 +23,40 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_listfiles_db(Client &client, const char *uri);
+handle_listfiles_db(Client &client, Response &r, const char *uri);
CommandResult
-handle_lsinfo2(Client &client, unsigned argc, char *argv[]);
+handle_lsinfo2(Client &client, const char *uri, Response &response);
CommandResult
-handle_find(Client &client, unsigned argc, char *argv[]);
+handle_find(Client &client, Request request, Response &response);
CommandResult
-handle_findadd(Client &client, unsigned argc, char *argv[]);
+handle_findadd(Client &client, Request request, Response &response);
CommandResult
-handle_search(Client &client, unsigned argc, char *argv[]);
+handle_search(Client &client, Request request, Response &response);
CommandResult
-handle_searchadd(Client &client, unsigned argc, char *argv[]);
+handle_searchadd(Client &client, Request request, Response &response);
CommandResult
-handle_searchaddpl(Client &client, unsigned argc, char *argv[]);
+handle_searchaddpl(Client &client, Request request, Response &response);
CommandResult
-handle_count(Client &client, unsigned argc, char *argv[]);
+handle_count(Client &client, Request request, Response &response);
CommandResult
-handle_listall(Client &client, unsigned argc, char *argv[]);
+handle_listall(Client &client, Request request, Response &response);
CommandResult
-handle_list(Client &client, unsigned argc, char *argv[]);
+handle_list(Client &client, Request request, Response &response);
CommandResult
-handle_listallinfo(Client &client, unsigned argc, char *argv[]);
+handle_listallinfo(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/FileCommands.cxx b/src/command/FileCommands.cxx
index 1b6a11cf5..486c00d89 100644
--- a/src/command/FileCommands.cxx
+++ b/src/command/FileCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,10 +21,12 @@
#include "config.h"
#include "FileCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "protocol/Ack.hxx"
-#include "protocol/Result.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
+#include "util/ConstBuffer.hxx"
#include "util/CharUtil.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
@@ -35,10 +37,10 @@
#include "TagFile.hxx"
#include "storage/StorageInterface.hxx"
#include "fs/AllocatedPath.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "fs/DirectoryReader.hxx"
+#include "LocateUri.hxx"
#include "TimePrint.hxx"
-#include "ls.hxx"
#include <assert.h>
#include <sys/stat.h>
@@ -46,7 +48,7 @@
gcc_pure
static bool
-SkipNameFS(const char *name_fs)
+SkipNameFS(PathTraitsFS::const_pointer name_fs)
{
return name_fs[0] == '.' &&
(name_fs[1] == 0 ||
@@ -55,9 +57,9 @@ SkipNameFS(const char *name_fs)
gcc_pure
static bool
-skip_path(const char *name_fs)
+skip_path(Path name_fs)
{
- return strchr(name_fs, '\n') != nullptr;
+ return name_fs.HasNewline();
}
#if defined(WIN32) && GCC_CHECK_VERSION(4,6)
@@ -68,28 +70,19 @@ skip_path(const char *name_fs)
#endif
CommandResult
-handle_listfiles_local(Client &client, const char *path_utf8)
+handle_listfiles_local(Response &r,
+ const char *path_utf8, Path path_fs)
{
- const auto path_fs = AllocatedPath::FromUTF8(path_utf8);
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
DirectoryReader reader(path_fs);
if (reader.HasFailed()) {
+ Error error;
error.FormatErrno("Failed to open '%s'", path_utf8);
- return print_error(client, error);
+ return print_error(r, error);
}
while (reader.ReadEntry()) {
const Path name_fs = reader.GetEntry();
- if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs.c_str()))
+ if (SkipNameFS(name_fs.c_str()) || skip_path(name_fs))
continue;
std::string name_utf8 = name_fs.ToUTF8();
@@ -98,20 +91,21 @@ handle_listfiles_local(Client &client, const char *path_utf8)
const AllocatedPath full_fs =
AllocatedPath::Build(path_fs, name_fs);
- struct stat st;
- if (!StatFile(full_fs, st, false))
+ FileInfo fi;
+ if (!GetFileInfo(full_fs, fi, false))
continue;
- if (S_ISREG(st.st_mode)) {
- client_printf(client, "file: %s\n"
- "size: %" PRIu64 "\n",
- name_utf8.c_str(),
- uint64_t(st.st_size));
- } else if (S_ISDIR(st.st_mode))
- client_printf(client, "directory: %s\n",
- name_utf8.c_str());
+ if (fi.IsRegular())
+ r.Format("file: %s\n"
+ "size: %" PRIu64 "\n",
+ name_utf8.c_str(),
+ fi.GetSize());
+ else if (fi.IsDirectory())
+ r.Format("directory: %s\n", name_utf8.c_str());
+ else
+ continue;
- time_print(client, "Last-Modified", st.st_mtime);
+ time_print(r, "Last-Modified", fi.GetModificationTime());
}
return CommandResult::OK;
@@ -154,10 +148,10 @@ IsValidValue(const char *p)
static void
print_pair(const char *key, const char *value, void *ctx)
{
- Client &client = *(Client *)ctx;
+ auto &r = *(Response *)ctx;
if (IsValidName(key) && IsValidValue(value))
- client_printf(client, "%s: %s\n", key, value);
+ r.Format("%s: %s\n", key, value);
}
static constexpr tag_handler print_comment_handler = {
@@ -167,93 +161,90 @@ static constexpr tag_handler print_comment_handler = {
};
static CommandResult
-read_stream_comments(Client &client, const char *uri)
+read_stream_comments(Response &r, const char *uri)
{
- if (!uri_supported_scheme(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported URI scheme");
+ if (!tag_stream_scan(uri, print_comment_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
- if (!tag_stream_scan(uri, print_comment_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "Failed to load file");
+ return CommandResult::OK;
+
+}
+
+static CommandResult
+read_file_comments(Response &r, const Path path_fs)
+{
+ if (!tag_file_scan(path_fs, print_comment_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "Failed to load file");
return CommandResult::ERROR;
}
+ tag_ape_scan2(path_fs, &print_comment_handler, &r);
+ tag_id3_scan(path_fs, &print_comment_handler, &r);
+
return CommandResult::OK;
}
static CommandResult
-read_file_comments(Client &client, const Path path_fs)
+read_db_comments(Client &client, Response &r, const char *uri)
{
- if (!tag_file_scan(path_fs, print_comment_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "Failed to load file");
+#ifdef ENABLE_DATABASE
+ const Storage *storage = client.GetStorage();
+ if (storage == nullptr) {
+#else
+ (void)client;
+ (void)uri;
+#endif
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
+#ifdef ENABLE_DATABASE
}
- tag_ape_scan2(path_fs, &print_comment_handler, &client);
- tag_id3_scan(path_fs, &print_comment_handler, &client);
+ {
+ AllocatedPath path_fs = storage->MapFS(uri);
+ if (!path_fs.IsNull())
+ return read_file_comments(r, path_fs);
+ }
- return CommandResult::OK;
+ {
+ const std::string uri2 = storage->MapUTF8(uri);
+ if (uri_has_scheme(uri2.c_str()))
+ return read_stream_comments(r, uri2.c_str());
+ }
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
+#endif
}
CommandResult
-handle_read_comments(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_read_comments(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
- const char *const uri = argv[1];
+ const char *const uri = args.front();
- if (memcmp(uri, "file:///", 8) == 0) {
- /* read comments from arbitrary local file */
- const char *path_utf8 = uri + 7;
- AllocatedPath path_fs = AllocatedPath::FromUTF8(path_utf8);
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
- return read_file_comments(client, path_fs);
- } else if (uri_has_scheme(uri)) {
- return read_stream_comments(client, uri);
- } else if (!PathTraitsUTF8::IsAbsolute(uri)) {
-#ifdef ENABLE_DATABASE
- const Storage *storage = client.GetStorage();
- if (storage == nullptr) {
-#endif
- command_error(client, ACK_ERROR_NO_EXIST,
- "No database");
- return CommandResult::ERROR;
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
#ifdef ENABLE_DATABASE
- }
-
- {
- AllocatedPath path_fs = storage->MapFS(uri);
- if (!path_fs.IsNull())
- return read_file_comments(client, path_fs);
- }
-
- {
- const std::string uri2 = storage->MapUTF8(uri);
- if (uri_has_scheme(uri2.c_str()))
- return read_stream_comments(client,
- uri2.c_str());
- }
-
- command_error(client, ACK_ERROR_NO_EXIST, "No such file");
- return CommandResult::ERROR;
+ nullptr,
#endif
- } else {
- command_error(client, ACK_ERROR_NO_EXIST, "No such file");
- return CommandResult::ERROR;
+ error);
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ return read_stream_comments(r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::RELATIVE:
+ return read_db_comments(client, r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::PATH:
+ return read_file_comments(r, located_uri.path);
}
+
+ gcc_unreachable();
}
diff --git a/src/command/FileCommands.hxx b/src/command/FileCommands.hxx
index 62835a82c..9c6631df5 100644
--- a/src/command/FileCommands.hxx
+++ b/src/command/FileCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,11 +23,15 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
+class Path;
CommandResult
-handle_listfiles_local(Client &client, const char *path_utf8);
+handle_listfiles_local(Response &response,
+ const char *path_utf8, Path path_fs);
CommandResult
-handle_read_comments(Client &client, unsigned argc, char *argv[]);
+handle_read_comments(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/MessageCommands.cxx b/src/command/MessageCommands.cxx
index a86bdf30c..28f97a52f 100644
--- a/src/command/MessageCommands.cxx
+++ b/src/command/MessageCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,11 +19,13 @@
#include "config.h"
#include "MessageCommands.hxx"
+#include "Request.hxx"
#include "client/Client.hxx"
#include "client/ClientList.hxx"
+#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
-#include "protocol/Result.hxx"
+#include "util/ConstBuffer.hxx"
#include <set>
#include <string>
@@ -31,27 +33,25 @@
#include <assert.h>
CommandResult
-handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_subscribe(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
+ const char *const channel_name = args[0];
- switch (client.Subscribe(argv[1])) {
+ switch (client.Subscribe(channel_name)) {
case Client::SubscribeResult::OK:
return CommandResult::OK;
case Client::SubscribeResult::INVALID:
- command_error(client, ACK_ERROR_ARG,
- "invalid channel name");
+ r.Error(ACK_ERROR_ARG, "invalid channel name");
return CommandResult::ERROR;
case Client::SubscribeResult::ALREADY:
- command_error(client, ACK_ERROR_EXIST,
- "already subscribed to this channel");
+ r.Error(ACK_ERROR_EXIST, "already subscribed to this channel");
return CommandResult::ERROR;
case Client::SubscribeResult::FULL:
- command_error(client, ACK_ERROR_EXIST,
- "subscription list is full");
+ r.Error(ACK_ERROR_EXIST, "subscription list is full");
return CommandResult::ERROR;
}
@@ -61,24 +61,23 @@ handle_subscribe(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_unsubscribe(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_unsubscribe(Client &client, Request args, Response &r)
{
- assert(argc == 2);
+ assert(args.size == 1);
+ const char *const channel_name = args[0];
- if (client.Unsubscribe(argv[1]))
+ if (client.Unsubscribe(channel_name))
return CommandResult::OK;
else {
- command_error(client, ACK_ERROR_NO_EXIST,
- "not subscribed to this channel");
+ r.Error(ACK_ERROR_NO_EXIST, "not subscribed to this channel");
return CommandResult::ERROR;
}
}
CommandResult
-handle_channels(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_channels(Client &client, gcc_unused Request args, Response &r)
{
- assert(argc == 1);
+ assert(args.IsEmpty());
std::set<std::string> channels;
for (const auto &c : *client.partition.instance.client_list)
@@ -86,22 +85,22 @@ handle_channels(Client &client,
c.subscriptions.end());
for (const auto &channel : channels)
- client_printf(client, "channel: %s\n", channel.c_str());
+ r.Format("channel: %s\n", channel.c_str());
return CommandResult::OK;
}
CommandResult
handle_read_messages(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+ gcc_unused Request args, Response &r)
{
- assert(argc == 1);
+ assert(args.IsEmpty());
while (!client.messages.empty()) {
const ClientMessage &msg = client.messages.front();
- client_printf(client, "channel: %s\nmessage: %s\n",
- msg.GetChannel(), msg.GetMessage());
+ r.Format("channel: %s\nmessage: %s\n",
+ msg.GetChannel(), msg.GetMessage());
client.messages.pop_front();
}
@@ -109,19 +108,20 @@ handle_read_messages(Client &client,
}
CommandResult
-handle_send_message(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_send_message(Client &client, Request args, Response &r)
{
- assert(argc == 3);
+ assert(args.size == 2);
- if (!client_message_valid_channel_name(argv[1])) {
- command_error(client, ACK_ERROR_ARG,
- "invalid channel name");
+ const char *const channel_name = args[0];
+ const char *const message_text = args[1];
+
+ if (!client_message_valid_channel_name(channel_name)) {
+ r.Error(ACK_ERROR_ARG, "invalid channel name");
return CommandResult::ERROR;
}
bool sent = false;
- const ClientMessage msg(argv[1], argv[2]);
+ const ClientMessage msg(channel_name, message_text);
for (auto &c : *client.partition.instance.client_list)
if (c.PushMessage(msg))
sent = true;
@@ -129,8 +129,8 @@ handle_send_message(Client &client,
if (sent)
return CommandResult::OK;
else {
- command_error(client, ACK_ERROR_NO_EXIST,
- "nobody is subscribed to this channel");
+ r.Error(ACK_ERROR_NO_EXIST,
+ "nobody is subscribed to this channel");
return CommandResult::ERROR;
}
}
diff --git a/src/command/MessageCommands.hxx b/src/command/MessageCommands.hxx
index ac8afe2fb..986c7cf6a 100644
--- a/src/command/MessageCommands.hxx
+++ b/src/command/MessageCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,20 +23,22 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_subscribe(Client &client, unsigned argc, char *argv[]);
+handle_subscribe(Client &client, Request request, Response &response);
CommandResult
-handle_unsubscribe(Client &client, unsigned argc, char *argv[]);
+handle_unsubscribe(Client &client, Request request, Response &response);
CommandResult
-handle_channels(Client &client, unsigned argc, char *argv[]);
+handle_channels(Client &client, Request request, Response &response);
CommandResult
-handle_read_messages(Client &client, unsigned argc, char *argv[]);
+handle_read_messages(Client &client, Request request, Response &response);
CommandResult
-handle_send_message(Client &client, unsigned argc, char *argv[]);
+handle_send_message(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/NeighborCommands.cxx b/src/command/NeighborCommands.cxx
index 22e8adf9e..254f7a346 100644
--- a/src/command/NeighborCommands.cxx
+++ b/src/command/NeighborCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,12 +19,14 @@
#include "config.h"
#include "NeighborCommands.hxx"
+#include "Request.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Instance.hxx"
#include "Partition.hxx"
-#include "protocol/Result.hxx"
#include "neighbor/Glue.hxx"
#include "neighbor/Info.hxx"
+#include "util/ConstBuffer.hxx"
#include <set>
#include <string>
@@ -38,22 +40,19 @@ neighbor_commands_available(const Instance &instance)
}
CommandResult
-handle_listneighbors(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listneighbors(Client &client, gcc_unused Request args, Response &r)
{
const NeighborGlue *const neighbors =
client.partition.instance.neighbors;
if (neighbors == nullptr) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "No neighbor plugin configured");
+ r.Error(ACK_ERROR_UNKNOWN, "No neighbor plugin configured");
return CommandResult::ERROR;
}
for (const auto &i : neighbors->GetList())
- client_printf(client,
- "neighbor: %s\n"
- "name: %s\n",
- i.uri.c_str(),
- i.display_name.c_str());
+ r.Format("neighbor: %s\n"
+ "name: %s\n",
+ i.uri.c_str(),
+ i.display_name.c_str());
return CommandResult::OK;
}
diff --git a/src/command/NeighborCommands.hxx b/src/command/NeighborCommands.hxx
index 7fb309aeb..efe05c5ae 100644
--- a/src/command/NeighborCommands.hxx
+++ b/src/command/NeighborCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,12 +25,14 @@
struct Instance;
class Client;
+class Request;
+class Response;
gcc_pure
bool
neighbor_commands_available(const Instance &instance);
CommandResult
-handle_listneighbors(Client &client, unsigned argc, char *argv[]);
+handle_listneighbors(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/OtherCommands.cxx b/src/command/OtherCommands.cxx
index a924f77b5..b4a23fe4b 100644
--- a/src/command/OtherCommands.cxx
+++ b/src/command/OtherCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,11 +19,13 @@
#include "config.h"
#include "OtherCommands.hxx"
+#include "Request.hxx"
#include "FileCommands.hxx"
#include "StorageCommands.hxx"
#include "CommandError.hxx"
#include "db/Uri.hxx"
#include "storage/StorageInterface.hxx"
+#include "LocateUri.hxx"
#include "DetachedSong.hxx"
#include "SongPrint.hxx"
#include "TagPrint.hxx"
@@ -31,18 +33,19 @@
#include "tag/TagHandler.hxx"
#include "TimePrint.hxx"
#include "decoder/DecoderPrint.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
#include "ls.hxx"
#include "mixer/Volume.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
#include "fs/AllocatedPath.hxx"
#include "Stats.hxx"
#include "Permission.hxx"
#include "PlaylistFile.hxx"
#include "db/PlaylistVector.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "Idle.hxx"
@@ -57,52 +60,51 @@
#include <string.h>
static void
-print_spl_list(Client &client, const PlaylistVector &list)
+print_spl_list(Response &r, const PlaylistVector &list)
{
for (const auto &i : list) {
- client_printf(client, "playlist: %s\n", i.name.c_str());
+ r.Format("playlist: %s\n", i.name.c_str());
if (i.mtime > 0)
- time_print(client, "Last-Modified", i.mtime);
+ time_print(r, "Last-Modified", i.mtime);
}
}
CommandResult
-handle_urlhandlers(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_urlhandlers(Client &client, gcc_unused Request args, Response &r)
{
if (client.IsLocal())
- client_puts(client, "handler: file://\n");
- print_supported_uri_schemes(client);
+ r.Format("handler: file://\n");
+ print_supported_uri_schemes(r);
return CommandResult::OK;
}
CommandResult
-handle_decoders(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_decoders(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
- decoder_list_print(client);
+ decoder_list_print(r);
return CommandResult::OK;
}
CommandResult
-handle_tagtypes(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_tagtypes(gcc_unused Client &client, gcc_unused Request request,
+ Response &r)
{
- tag_print_types(client);
+ tag_print_types(r);
return CommandResult::OK;
}
CommandResult
-handle_kill(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_kill(gcc_unused Client &client, gcc_unused Request request,
+ gcc_unused Response &r)
{
return CommandResult::KILL;
}
CommandResult
-handle_close(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_close(gcc_unused Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
return CommandResult::FINISH;
}
@@ -110,44 +112,60 @@ handle_close(gcc_unused Client &client,
static void
print_tag(TagType type, const char *value, void *ctx)
{
- Client &client = *(Client *)ctx;
+ auto &r = *(Response *)ctx;
- tag_print(client, type, value);
+ tag_print(r, type, value);
}
CommandResult
-handle_listfiles(Client &client, unsigned argc, char *argv[])
+handle_listfiles(Client &client, Request args, Response &r)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
- if (memcmp(uri, "file:///", 8) == 0)
- /* list local directory */
- return handle_listfiles_local(client, uri + 7);
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
#ifdef ENABLE_DATABASE
- if (uri_has_scheme(uri))
- /* use storage plugin to list remote directory */
- return handle_listfiles_storage(client, uri);
+ nullptr,
+#endif
+ error);
- /* must be a path relative to the configured
- music_directory */
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
- if (client.partition.instance.storage != nullptr)
- /* if we have a storage instance, obtain a list of
- files from it */
- return handle_listfiles_storage(client,
- *client.partition.instance.storage,
- uri);
+ case LocatedUri::Type::ABSOLUTE:
+#ifdef ENABLE_DATABASE
+ /* use storage plugin to list remote directory */
+ return handle_listfiles_storage(r, located_uri.canonical_uri);
+#else
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+#endif
- /* fall back to entries from database if we have no storage */
- return handle_listfiles_db(client, uri);
+ case LocatedUri::Type::RELATIVE:
+#ifdef ENABLE_DATABASE
+ if (client.partition.instance.storage != nullptr)
+ /* if we have a storage instance, obtain a list of
+ files from it */
+ return handle_listfiles_storage(r,
+ *client.partition.instance.storage,
+ uri);
+
+ /* fall back to entries from database if we have no storage */
+ return handle_listfiles_db(client, r, uri);
#else
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
- return CommandResult::ERROR;
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
#endif
+
+ case LocatedUri::Type::PATH:
+ /* list local directory */
+ return handle_listfiles_local(r, located_uri.canonical_uri,
+ located_uri.path);
+ }
+
+ gcc_unreachable();
}
static constexpr tag_handler print_tag_handler = {
@@ -156,69 +174,35 @@ static constexpr tag_handler print_tag_handler = {
nullptr,
};
-CommandResult
-handle_lsinfo(Client &client, unsigned argc, char *argv[])
+static CommandResult
+handle_lsinfo_absolute(Response &r, const char *uri)
{
- const char *const uri = argc == 2
- ? argv[1]
- /* default is root directory */
- : "";
-
- if (memcmp(uri, "file:///", 8) == 0) {
- /* print information about an arbitrary local file */
- const char *path_utf8 = uri + 7;
- const auto path_fs = AllocatedPath::FromUTF8(path_utf8);
-
- if (path_fs.IsNull()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported file name");
- return CommandResult::ERROR;
- }
-
- Error error;
- if (!client.AllowFile(path_fs, error))
- return print_error(client, error);
-
- DetachedSong song(path_utf8);
- if (!song.Update()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such file");
- return CommandResult::ERROR;
- }
-
- song_print_info(client, song);
- return CommandResult::OK;
+ if (!tag_stream_scan(uri, print_tag_handler, &r)) {
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
}
- if (uri_has_scheme(uri)) {
- if (!uri_supported_scheme(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "unsupported URI scheme");
- return CommandResult::ERROR;
- }
-
- if (!tag_stream_scan(uri, print_tag_handler, &client)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such file");
- return CommandResult::ERROR;
- }
-
- return CommandResult::OK;
- }
+ return CommandResult::OK;
+}
+static CommandResult
+handle_lsinfo_relative(Client &client, Response &r, const char *uri)
+{
#ifdef ENABLE_DATABASE
- CommandResult result = handle_lsinfo2(client, argc, argv);
+ CommandResult result = handle_lsinfo2(client, uri, r);
if (result != CommandResult::OK)
return result;
+#else
+ (void)client;
#endif
if (isRootDirectory(uri)) {
Error error;
const auto &list = ListPlaylistFiles(error);
- print_spl_list(client, list);
+ print_spl_list(r, list);
} else {
#ifndef ENABLE_DATABASE
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
#endif
}
@@ -226,38 +210,84 @@ handle_lsinfo(Client &client, unsigned argc, char *argv[])
return CommandResult::OK;
}
+static CommandResult
+handle_lsinfo_path(Client &client, Response &r,
+ const char *path_utf8, Path path_fs)
+{
+ DetachedSong song(path_utf8);
+ if (!song.LoadFile(path_fs)) {
+ r.Error(ACK_ERROR_NO_EXIST, "No such file");
+ return CommandResult::ERROR;
+ }
+
+ song_print_info(r, client.partition, song);
+ return CommandResult::OK;
+}
+
+CommandResult
+handle_lsinfo(Client &client, Request args, Response &r)
+{
+ /* default is root directory */
+ const auto uri = args.GetOptional(0, "");
+
+ Error error;
+ const auto located_uri = LocateUri(uri, &client,
+#ifdef ENABLE_DATABASE
+ nullptr,
+#endif
+ error);
+
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ return handle_lsinfo_absolute(r, located_uri.canonical_uri);
+
+ case LocatedUri::Type::RELATIVE:
+ return handle_lsinfo_relative(client, r,
+ located_uri.canonical_uri);
+
+ case LocatedUri::Type::PATH:
+ /* print information about an arbitrary local file */
+ return handle_lsinfo_path(client, r, located_uri.canonical_uri,
+ located_uri.path);
+ }
+
+ gcc_unreachable();
+}
+
#ifdef ENABLE_DATABASE
static CommandResult
-handle_update(Client &client, UpdateService &update,
+handle_update(Response &r, UpdateService &update,
const char *uri_utf8, bool discard)
{
unsigned ret = update.Enqueue(uri_utf8, discard);
if (ret > 0) {
- client_printf(client, "updating_db: %i\n", ret);
+ r.Format("updating_db: %i\n", ret);
return CommandResult::OK;
} else {
- command_error(client, ACK_ERROR_UPDATE_ALREADY,
- "already updating");
+ r.Error(ACK_ERROR_UPDATE_ALREADY, "already updating");
return CommandResult::ERROR;
}
}
static CommandResult
-handle_update(Client &client, Database &db,
+handle_update(Response &r, Database &db,
const char *uri_utf8, bool discard)
{
Error error;
unsigned id = db.Update(uri_utf8, discard, error);
if (id > 0) {
- client_printf(client, "updating_db: %i\n", id);
+ r.Format("updating_db: %i\n", id);
return CommandResult::OK;
} else if (error.IsDefined()) {
- return print_error(client, error);
+ return print_error(r, error);
} else {
/* Database::Update() has returned 0 without setting
the Error: the method is not implemented */
- command_error(client, ACK_ERROR_NO_EXIST, "Not implemented");
+ r.Error(ACK_ERROR_NO_EXIST, "Not implemented");
return CommandResult::ERROR;
}
}
@@ -265,72 +295,62 @@ handle_update(Client &client, Database &db,
#endif
static CommandResult
-handle_update(Client &client, unsigned argc, char *argv[], bool discard)
+handle_update(Client &client, Request args, Response &r, bool discard)
{
#ifdef ENABLE_DATABASE
const char *path = "";
- assert(argc <= 2);
- if (argc == 2) {
- path = argv[1];
+ assert(args.size <= 1);
+ if (!args.IsEmpty()) {
+ path = args.front();
- if (*path == 0 || strcmp(path, "/") == 0)
+ if (*path == 0 || StringIsEqual(path, "/"))
/* backwards compatibility with MPD 0.15 */
path = "";
else if (!uri_safe_local(path)) {
- command_error(client, ACK_ERROR_ARG,
- "Malformed path");
+ r.Error(ACK_ERROR_ARG, "Malformed path");
return CommandResult::ERROR;
}
}
UpdateService *update = client.partition.instance.update;
if (update != nullptr)
- return handle_update(client, *update, path, discard);
+ return handle_update(r, *update, path, discard);
Database *db = client.partition.instance.database;
if (db != nullptr)
- return handle_update(client, *db, path, discard);
+ return handle_update(r, *db, path, discard);
#else
- (void)argc;
- (void)argv;
+ (void)client;
+ (void)args;
(void)discard;
#endif
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CommandResult
-handle_update(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_update(Client &client, Request args, gcc_unused Response &r)
{
- return handle_update(client, argc, argv, false);
+ return handle_update(client, args, r, false);
}
CommandResult
-handle_rescan(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rescan(Client &client, Request args, Response &r)
{
- return handle_update(client, argc, argv, true);
+ return handle_update(client, args, r, true);
}
CommandResult
-handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_setvol(Client &client, Request args, Response &r)
{
unsigned level;
- bool success;
-
- if (!check_unsigned(client, &level, argv[1]))
+ if (!args.Parse(0, level, r, 100))
return CommandResult::ERROR;
- if (level > 100) {
- command_error(client, ACK_ERROR_ARG, "Invalid volume value");
- return CommandResult::ERROR;
- }
-
- success = volume_level_change(client.partition.outputs, level);
- if (!success) {
- command_error(client, ACK_ERROR_SYSTEM,
- "problems setting volume");
+ if (!volume_level_change(client.partition.outputs, level)) {
+ r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
return CommandResult::ERROR;
}
@@ -338,20 +358,15 @@ handle_setvol(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_volume(Client &client, Request args, Response &r)
{
int relative;
- if (!check_int(client, &relative, argv[1]))
+ if (!args.Parse(0, relative, r, -100, 100))
return CommandResult::ERROR;
- if (relative < -100 || relative > 100) {
- command_error(client, ACK_ERROR_ARG, "Invalid volume value");
- return CommandResult::ERROR;
- }
-
const int old_volume = volume_level_get(client.partition.outputs);
if (old_volume < 0) {
- command_error(client, ACK_ERROR_SYSTEM, "No mixer");
+ r.Error(ACK_ERROR_SYSTEM, "No mixer");
return CommandResult::ERROR;
}
@@ -363,8 +378,7 @@ handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
if (new_volume != old_volume &&
!volume_level_change(client.partition.outputs, new_volume)) {
- command_error(client, ACK_ERROR_SYSTEM,
- "problems setting volume");
+ r.Error(ACK_ERROR_SYSTEM, "problems setting volume");
return CommandResult::ERROR;
}
@@ -372,27 +386,25 @@ handle_volume(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_stats(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_stats(Client &client, gcc_unused Request args, Response &r)
{
- stats_print(client);
+ stats_print(r, client.partition);
return CommandResult::OK;
}
CommandResult
-handle_ping(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_ping(gcc_unused Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
return CommandResult::OK;
}
CommandResult
-handle_password(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_password(Client &client, Request args, Response &r)
{
unsigned permission = 0;
-
- if (getPermissionFromPassword(argv[1], &permission) < 0) {
- command_error(client, ACK_ERROR_PASSWORD, "incorrect password");
+ if (getPermissionFromPassword(args.front(), &permission) < 0) {
+ r.Error(ACK_ERROR_PASSWORD, "incorrect password");
return CommandResult::ERROR;
}
@@ -402,12 +414,11 @@ handle_password(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_config(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_config(Client &client, gcc_unused Request args, Response &r)
{
if (!client.IsLocal()) {
- command_error(client, ACK_ERROR_PERMISSION,
- "Command only permitted to local clients");
+ r.Error(ACK_ERROR_PERMISSION,
+ "Command only permitted to local clients");
return CommandResult::ERROR;
}
@@ -415,7 +426,7 @@ handle_config(Client &client,
const Storage *storage = client.GetStorage();
if (storage != nullptr) {
const auto path = storage->MapUTF8("");
- client_printf(client, "music_directory: %s\n", path.c_str());
+ r.Format("music_directory: %s\n", path.c_str());
}
#endif
@@ -423,17 +434,14 @@ handle_config(Client &client,
}
CommandResult
-handle_idle(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_idle(Client &client, Request args, Response &r)
{
unsigned flags = 0;
-
- for (unsigned i = 1; i < argc; ++i) {
- unsigned event = idle_parse_name(argv[i]);
+ for (const char *i : args) {
+ unsigned event = idle_parse_name(i);
if (event == 0) {
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized idle event: %s",
- argv[i]);
+ r.FormatError(ACK_ERROR_ARG,
+ "Unrecognized idle event: %s", i);
return CommandResult::ERROR;
}
diff --git a/src/command/OtherCommands.hxx b/src/command/OtherCommands.hxx
index 7cfa35dfb..2a918df97 100644
--- a/src/command/OtherCommands.hxx
+++ b/src/command/OtherCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,53 +23,55 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_urlhandlers(Client &client, unsigned argc, char *argv[]);
+handle_urlhandlers(Client &client, Request request, Response &response);
CommandResult
-handle_decoders(Client &client, unsigned argc, char *argv[]);
+handle_decoders(Client &client, Request request, Response &response);
CommandResult
-handle_tagtypes(Client &client, unsigned argc, char *argv[]);
+handle_tagtypes(Client &client, Request request, Response &response);
CommandResult
-handle_kill(Client &client, unsigned argc, char *argv[]);
+handle_kill(Client &client, Request request, Response &response);
CommandResult
-handle_close(Client &client, unsigned argc, char *argv[]);
+handle_close(Client &client, Request request, Response &response);
CommandResult
-handle_listfiles(Client &client, unsigned argc, char *argv[]);
+handle_listfiles(Client &client, Request request, Response &response);
CommandResult
-handle_lsinfo(Client &client, unsigned argc, char *argv[]);
+handle_lsinfo(Client &client, Request request, Response &response);
CommandResult
-handle_update(Client &client, unsigned argc, char *argv[]);
+handle_update(Client &client, Request request, Response &response);
CommandResult
-handle_rescan(Client &client, unsigned argc, char *argv[]);
+handle_rescan(Client &client, Request request, Response &response);
CommandResult
-handle_setvol(Client &client, unsigned argc, char *argv[]);
+handle_setvol(Client &client, Request request, Response &response);
CommandResult
-handle_volume(Client &client, unsigned argc, char *argv[]);
+handle_volume(Client &client, Request request, Response &response);
CommandResult
-handle_stats(Client &client, unsigned argc, char *argv[]);
+handle_stats(Client &client, Request request, Response &response);
CommandResult
-handle_ping(Client &client, unsigned argc, char *argv[]);
+handle_ping(Client &client, Request request, Response &response);
CommandResult
-handle_password(Client &client, unsigned argc, char *argv[]);
+handle_password(Client &client, Request request, Response &response);
CommandResult
-handle_config(Client &client, unsigned argc, char *argv[]);
+handle_config(Client &client, Request request, Response &response);
CommandResult
-handle_idle(Client &client, unsigned argc, char *argv[]);
+handle_idle(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx
index c69a0dd65..7bbe5f905 100644
--- a/src/command/OutputCommands.cxx
+++ b/src/command/OutputCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,23 +19,24 @@
#include "config.h"
#include "OutputCommands.hxx"
+#include "Request.hxx"
#include "output/OutputPrint.hxx"
#include "output/OutputCommand.hxx"
-#include "protocol/Result.hxx"
-#include "protocol/ArgParser.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
+#include "util/ConstBuffer.hxx"
CommandResult
-handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_enableoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_enable_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -43,15 +44,15 @@ handle_enableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_disableoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_disable_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -59,15 +60,15 @@ handle_disableoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_toggleoutput(Client &client, Request args, Response &r)
{
+ assert(args.size == 1);
unsigned device;
- if (!check_unsigned(client, &device, argv[1]))
+ if (!args.Parse(0, device, r))
return CommandResult::ERROR;
if (!audio_output_toggle_index(client.partition.outputs, device)) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "No such audio output");
+ r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
return CommandResult::ERROR;
}
@@ -75,10 +76,10 @@ handle_toggleoutput(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_devices(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_devices(Client &client, gcc_unused Request args, Response &r)
{
- printAudioDevices(client, client.partition.outputs);
+ assert(args.IsEmpty());
+ printAudioDevices(r, client.partition.outputs);
return CommandResult::OK;
}
diff --git a/src/command/OutputCommands.hxx b/src/command/OutputCommands.hxx
index 8d6be0511..3dd81bc23 100644
--- a/src/command/OutputCommands.hxx
+++ b/src/command/OutputCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,17 +23,19 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_enableoutput(Client &client, unsigned argc, char *argv[]);
+handle_enableoutput(Client &client, Request request, Response &response);
CommandResult
-handle_disableoutput(Client &client, unsigned argc, char *argv[]);
+handle_disableoutput(Client &client, Request request, Response &response);
CommandResult
-handle_toggleoutput(Client &client, unsigned argc, char *argv[]);
+handle_toggleoutput(Client &client, Request request, Response &response);
CommandResult
-handle_devices(Client &client, unsigned argc, char *argv[]);
+handle_devices(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/PlayerCommands.cxx b/src/command/PlayerCommands.cxx
index cd7f42289..11cde2e98 100644
--- a/src/command/PlayerCommands.cxx
+++ b/src/command/PlayerCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,17 +19,18 @@
#include "config.h"
#include "PlayerCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "mixer/Volume.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
-#include "protocol/Result.hxx"
-#include "protocol/ArgParser.hxx"
#include "AudioFormat.hxx"
#include "ReplayGainConfig.hxx"
+#include "util/ConstBuffer.hxx"
#ifdef ENABLE_DATABASE
#include "db/update/Service.hxx"
@@ -56,51 +57,47 @@
#define COMMAND_STATUS_UPDATING_DB "updating_db"
CommandResult
-handle_play(Client &client, unsigned argc, char *argv[])
+handle_play(Client &client, Request args, Response &r)
{
int song = -1;
-
- if (argc == 2 && !check_int(client, &song, argv[1]))
+ if (!args.ParseOptional(0, song, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.PlayPosition(song);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_playid(Client &client, unsigned argc, char *argv[])
+handle_playid(Client &client, Request args, Response &r)
{
int id = -1;
-
- if (argc == 2 && !check_int(client, &id, argv[1]))
+ if (!args.ParseOptional(0, id, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.PlayId(id);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_stop(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_stop(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
client.partition.Stop();
return CommandResult::OK;
}
CommandResult
-handle_currentsong(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_currentsong(Client &client, gcc_unused Request args, Response &r)
{
- playlist_print_current(client, client.playlist);
+ playlist_print_current(r, client.partition, client.playlist);
return CommandResult::OK;
}
CommandResult
-handle_pause(Client &client,
- unsigned argc, char *argv[])
+handle_pause(Client &client, Request args, Response &r)
{
- if (argc == 2) {
+ if (!args.IsEmpty()) {
bool pause_flag;
- if (!check_bool(client, &pause_flag, argv[1]))
+ if (!args.Parse(0, pause_flag, r))
return CommandResult::ERROR;
client.player_control.SetPause(pause_flag);
@@ -111,8 +108,7 @@ handle_pause(Client &client,
}
CommandResult
-handle_status(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_status(Client &client, gcc_unused Request args, Response &r)
{
const char *state = nullptr;
int song;
@@ -132,63 +128,61 @@ handle_status(Client &client,
}
const playlist &playlist = client.playlist;
- client_printf(client,
- "volume: %i\n"
- COMMAND_STATUS_REPEAT ": %i\n"
- COMMAND_STATUS_RANDOM ": %i\n"
- COMMAND_STATUS_SINGLE ": %i\n"
- COMMAND_STATUS_CONSUME ": %i\n"
- COMMAND_STATUS_PLAYLIST ": %li\n"
- COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
- COMMAND_STATUS_MIXRAMPDB ": %f\n"
- COMMAND_STATUS_STATE ": %s\n",
- volume_level_get(client.partition.outputs),
- playlist.GetRepeat(),
- playlist.GetRandom(),
- playlist.GetSingle(),
- playlist.GetConsume(),
- (unsigned long)playlist.GetVersion(),
- playlist.GetLength(),
- client.player_control.GetMixRampDb(),
- state);
+ r.Format("volume: %i\n"
+ COMMAND_STATUS_REPEAT ": %i\n"
+ COMMAND_STATUS_RANDOM ": %i\n"
+ COMMAND_STATUS_SINGLE ": %i\n"
+ COMMAND_STATUS_CONSUME ": %i\n"
+ COMMAND_STATUS_PLAYLIST ": %li\n"
+ COMMAND_STATUS_PLAYLIST_LENGTH ": %i\n"
+ COMMAND_STATUS_MIXRAMPDB ": %f\n"
+ COMMAND_STATUS_STATE ": %s\n",
+ volume_level_get(client.partition.outputs),
+ playlist.GetRepeat(),
+ playlist.GetRandom(),
+ playlist.GetSingle(),
+ playlist.GetConsume(),
+ (unsigned long)playlist.GetVersion(),
+ playlist.GetLength(),
+ client.player_control.GetMixRampDb(),
+ state);
if (client.player_control.GetCrossFade() > 0)
- client_printf(client,
- COMMAND_STATUS_CROSSFADE ": %i\n",
- int(client.player_control.GetCrossFade() + 0.5));
+ r.Format(COMMAND_STATUS_CROSSFADE ": %i\n",
+ int(client.player_control.GetCrossFade() + 0.5));
if (client.player_control.GetMixRampDelay() > 0)
- client_printf(client,
- COMMAND_STATUS_MIXRAMPDELAY ": %f\n",
- client.player_control.GetMixRampDelay());
+ r.Format(COMMAND_STATUS_MIXRAMPDELAY ": %f\n",
+ client.player_control.GetMixRampDelay());
song = playlist.GetCurrentPosition();
if (song >= 0) {
- client_printf(client,
- COMMAND_STATUS_SONG ": %i\n"
- COMMAND_STATUS_SONGID ": %u\n",
- song, playlist.PositionToId(song));
+ r.Format(COMMAND_STATUS_SONG ": %i\n"
+ COMMAND_STATUS_SONGID ": %u\n",
+ song, playlist.PositionToId(song));
}
if (player_status.state != PlayerState::STOP) {
- client_printf(client,
- COMMAND_STATUS_TIME ": %i:%i\n"
- "elapsed: %1.3f\n"
- COMMAND_STATUS_BITRATE ": %u\n",
- player_status.elapsed_time.RoundS(),
- player_status.total_time.IsNegative()
- ? 0u
- : unsigned(player_status.total_time.RoundS()),
- player_status.elapsed_time.ToDoubleS(),
- player_status.bit_rate);
+ r.Format(COMMAND_STATUS_TIME ": %i:%i\n"
+ "elapsed: %1.3f\n"
+ COMMAND_STATUS_BITRATE ": %u\n",
+ player_status.elapsed_time.RoundS(),
+ player_status.total_time.IsNegative()
+ ? 0u
+ : unsigned(player_status.total_time.RoundS()),
+ player_status.elapsed_time.ToDoubleS(),
+ player_status.bit_rate);
+
+ if (!player_status.total_time.IsNegative())
+ r.Format("duration: %1.3f\n",
+ player_status.total_time.ToDoubleS());
if (player_status.audio_format.IsDefined()) {
struct audio_format_string af_string;
- client_printf(client,
- COMMAND_STATUS_AUDIO ": %s\n",
- audio_format_to_string(player_status.audio_format,
- &af_string));
+ r.Format(COMMAND_STATUS_AUDIO ": %s\n",
+ audio_format_to_string(player_status.audio_format,
+ &af_string));
}
}
@@ -198,32 +192,27 @@ handle_status(Client &client,
? update_service->GetId()
: 0;
if (updateJobId != 0) {
- client_printf(client,
- COMMAND_STATUS_UPDATING_DB ": %i\n",
- updateJobId);
+ r.Format(COMMAND_STATUS_UPDATING_DB ": %i\n",
+ updateJobId);
}
#endif
Error error = client.player_control.LockGetError();
if (error.IsDefined())
- client_printf(client,
- COMMAND_STATUS_ERROR ": %s\n",
- error.GetMessage());
+ r.Format(COMMAND_STATUS_ERROR ": %s\n",
+ error.GetMessage());
song = playlist.GetNextPosition();
- if (song >= 0) {
- client_printf(client,
- COMMAND_STATUS_NEXTSONG ": %i\n"
- COMMAND_STATUS_NEXTSONGID ": %u\n",
- song, playlist.PositionToId(song));
- }
+ if (song >= 0)
+ r.Format(COMMAND_STATUS_NEXTSONG ": %i\n"
+ COMMAND_STATUS_NEXTSONGID ": %u\n",
+ song, playlist.PositionToId(song));
return CommandResult::OK;
}
CommandResult
-handle_next(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_next(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
playlist &playlist = client.playlist;
@@ -239,18 +228,18 @@ handle_next(Client &client,
}
CommandResult
-handle_previous(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_previous(Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
client.partition.PlayPrevious();
return CommandResult::OK;
}
CommandResult
-handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_repeat(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetRepeat(status);
@@ -258,10 +247,10 @@ handle_repeat(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_single(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_single(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetSingle(status);
@@ -269,10 +258,10 @@ handle_single(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_consume(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_consume(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetConsume(status);
@@ -280,10 +269,10 @@ handle_consume(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_random(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_random(Client &client, Request args, Response &r)
{
bool status;
- if (!check_bool(client, &status, argv[1]))
+ if (!args.Parse(0, status, r))
return CommandResult::ERROR;
client.partition.SetRandom(status);
@@ -292,102 +281,94 @@ handle_random(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_clearerror(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_clearerror(Client &client, gcc_unused Request args,
+ gcc_unused Response &r)
{
client.player_control.ClearError();
return CommandResult::OK;
}
CommandResult
-handle_seek(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seek(Client &client, Request args, Response &r)
{
unsigned song;
SongTime seek_time;
-
- if (!check_unsigned(client, &song, argv[1]))
- return CommandResult::ERROR;
- if (!ParseCommandArg(client, seek_time, argv[2]))
+ if (!args.Parse(0, song, r) || !args.Parse(1, seek_time, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekSongPosition(song, seek_time);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_seekid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seekid(Client &client, Request args, Response &r)
{
unsigned id;
SongTime seek_time;
-
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
- if (!ParseCommandArg(client, seek_time, argv[2]))
+ if (!args.Parse(1, seek_time, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekSongId(id, seek_time);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_seekcur(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_seekcur(Client &client, Request args, Response &r)
{
- const char *p = argv[1];
+ const char *p = args.front();
bool relative = *p == '+' || *p == '-';
SignedSongTime seek_time;
- if (!ParseCommandArg(client, seek_time, p))
+ if (!ParseCommandArg(r, seek_time, p))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SeekCurrent(seek_time, relative);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_crossfade(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_crossfade(Client &client, Request args, Response &r)
{
unsigned xfade_time;
-
- if (!check_unsigned(client, &xfade_time, argv[1]))
+ if (!args.Parse(0, xfade_time, r))
return CommandResult::ERROR;
- client.player_control.SetCrossFade(xfade_time);
+ client.player_control.SetCrossFade(xfade_time);
return CommandResult::OK;
}
CommandResult
-handle_mixrampdb(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mixrampdb(Client &client, Request args, Response &r)
{
float db;
-
- if (!check_float(client, &db, argv[1]))
+ if (!args.Parse(0, db, r))
return CommandResult::ERROR;
- client.player_control.SetMixRampDb(db);
+ client.player_control.SetMixRampDb(db);
return CommandResult::OK;
}
CommandResult
-handle_mixrampdelay(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mixrampdelay(Client &client, Request args, Response &r)
{
float delay_secs;
-
- if (!check_float(client, &delay_secs, argv[1]))
+ if (!args.Parse(0, delay_secs, r))
return CommandResult::ERROR;
+
client.player_control.SetMixRampDelay(delay_secs);
return CommandResult::OK;
}
CommandResult
-handle_replay_gain_mode(Client &client,
- gcc_unused unsigned argc, char *argv[])
+handle_replay_gain_mode(Client &client, Request args, Response &r)
{
- if (!replay_gain_set_mode_string(argv[1])) {
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized replay gain mode");
+ if (!replay_gain_set_mode_string(args.front())) {
+ r.Error(ACK_ERROR_ARG, "Unrecognized replay gain mode");
return CommandResult::ERROR;
}
@@ -396,10 +377,9 @@ handle_replay_gain_mode(Client &client,
}
CommandResult
-handle_replay_gain_status(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_replay_gain_status(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
- client_printf(client, "replay_gain_mode: %s\n",
- replay_gain_get_mode_string());
+ r.Format("replay_gain_mode: %s\n", replay_gain_get_mode_string());
return CommandResult::OK;
}
diff --git a/src/command/PlayerCommands.hxx b/src/command/PlayerCommands.hxx
index da7083f1e..76ce51ef5 100644
--- a/src/command/PlayerCommands.hxx
+++ b/src/command/PlayerCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,68 +23,70 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_play(Client &client, unsigned argc, char *argv[]);
+handle_play(Client &client, Request request, Response &response);
CommandResult
-handle_playid(Client &client, unsigned argc, char *argv[]);
+handle_playid(Client &client, Request request, Response &response);
CommandResult
-handle_stop(Client &client, unsigned argc, char *argv[]);
+handle_stop(Client &client, Request request, Response &response);
CommandResult
-handle_currentsong(Client &client, unsigned argc, char *argv[]);
+handle_currentsong(Client &client, Request request, Response &response);
CommandResult
-handle_pause(Client &client, unsigned argc, char *argv[]);
+handle_pause(Client &client, Request request, Response &response);
CommandResult
-handle_status(Client &client, unsigned argc, char *argv[]);
+handle_status(Client &client, Request request, Response &response);
CommandResult
-handle_next(Client &client, unsigned argc, char *argv[]);
+handle_next(Client &client, Request request, Response &response);
CommandResult
-handle_previous(Client &client, unsigned argc, char *avg[]);
+handle_previous(Client &client, Request request, Response &response);
CommandResult
-handle_repeat(Client &client, unsigned argc, char *argv[]);
+handle_repeat(Client &client, Request request, Response &response);
CommandResult
-handle_single(Client &client, unsigned argc, char *argv[]);
+handle_single(Client &client, Request request, Response &response);
CommandResult
-handle_consume(Client &client, unsigned argc, char *argv[]);
+handle_consume(Client &client, Request request, Response &response);
CommandResult
-handle_random(Client &client, unsigned argc, char *argv[]);
+handle_random(Client &client, Request request, Response &response);
CommandResult
-handle_clearerror(Client &client, unsigned argc, char *argv[]);
+handle_clearerror(Client &client, Request request, Response &response);
CommandResult
-handle_seek(Client &client, unsigned argc, char *argv[]);
+handle_seek(Client &client, Request request, Response &response);
CommandResult
-handle_seekid(Client &client, unsigned argc, char *argv[]);
+handle_seekid(Client &client, Request request, Response &response);
CommandResult
-handle_seekcur(Client &client, unsigned argc, char *argv[]);
+handle_seekcur(Client &client, Request request, Response &response);
CommandResult
-handle_crossfade(Client &client, unsigned argc, char *argv[]);
+handle_crossfade(Client &client, Request request, Response &response);
CommandResult
-handle_mixrampdb(Client &client, unsigned argc, char *argv[]);
+handle_mixrampdb(Client &client, Request request, Response &response);
CommandResult
-handle_mixrampdelay(Client &client, unsigned argc, char *argv[]);
+handle_mixrampdelay(Client &client, Request request, Response &response);
CommandResult
-handle_replay_gain_mode(Client &client, unsigned argc, char *argv[]);
+handle_replay_gain_mode(Client &client, Request request, Response &response);
CommandResult
-handle_replay_gain_status(Client &client, unsigned argc, char *argv[]);
+handle_replay_gain_status(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx
index c2b18064c..625e82055 100644
--- a/src/command/PlaylistCommands.cxx
+++ b/src/command/PlaylistCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "PlaylistCommands.hxx"
+#include "Request.hxx"
#include "db/DatabasePlaylist.hxx"
#include "CommandError.hxx"
#include "PlaylistPrint.hxx"
@@ -32,143 +33,157 @@
#include "queue/Playlist.hxx"
#include "TimePrint.hxx"
#include "client/Client.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
+#include "client/Response.hxx"
#include "ls.hxx"
+#include "Mapper.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
+
+bool
+playlist_commands_available()
+{
+ return !map_spl_path().IsNull();
+}
static void
-print_spl_list(Client &client, const PlaylistVector &list)
+print_spl_list(Response &r, const PlaylistVector &list)
{
for (const auto &i : list) {
- client_printf(client, "playlist: %s\n", i.name.c_str());
+ r.Format("playlist: %s\n", i.name.c_str());
if (i.mtime > 0)
- time_print(client, "Last-Modified", i.mtime);
+ time_print(r, "Last-Modified", i.mtime);
}
}
CommandResult
-handle_save(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_save(Client &client, Request args, Response &r)
{
- PlaylistResult result = spl_save_playlist(argv[1], client.playlist);
- return print_playlist_result(client, result);
+ Error error;
+ return spl_save_playlist(args.front(), client.playlist, error)
+ ? CommandResult::OK
+ : print_error(r, error);
}
CommandResult
-handle_load(Client &client, unsigned argc, char *argv[])
+handle_load(Client &client, Request args, Response &r)
{
- unsigned start_index, end_index;
-
- if (argc < 3) {
- start_index = 0;
- end_index = unsigned(-1);
- } else if (!check_range(client, &start_index, &end_index, argv[2]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(1, range, r))
return CommandResult::ERROR;
const ScopeBulkEdit bulk_edit(client.partition);
Error error;
const SongLoader loader(client);
- if (!playlist_open_into_queue(argv[1],
- start_index, end_index,
+ if (!playlist_open_into_queue(args.front(),
+ range.start, range.end,
client.playlist,
client.player_control, loader, error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_listplaylist(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_listplaylist(Client &client, Request args, Response &r)
{
- if (playlist_file_print(client, argv[1], false))
+ const char *const name = args.front();
+
+ if (playlist_file_print(r, client.partition, SongLoader(client),
+ name, false))
return CommandResult::OK;
Error error;
- return spl_print(client, argv[1], false, error)
+ return spl_print(r, client.partition, name, false, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_listplaylistinfo(Client &client,
- gcc_unused unsigned argc, char *argv[])
+handle_listplaylistinfo(Client &client, Request args, Response &r)
{
- if (playlist_file_print(client, argv[1], true))
+ const char *const name = args.front();
+
+ if (playlist_file_print(r, client.partition, SongLoader(client),
+ name, true))
return CommandResult::OK;
Error error;
- return spl_print(client, argv[1], true, error)
+ return spl_print(r, client.partition, name, true, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_rm(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rm(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const name = args.front();
+
Error error;
- return spl_delete(argv[1], error)
+ return spl_delete(name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_rename(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rename(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const old_name = args[0];
+ const char *const new_name = args[1];
+
Error error;
- return spl_rename(argv[1], argv[2], error)
+ return spl_rename(old_name, new_name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistdelete(Client &client,
- gcc_unused unsigned argc, char *argv[]) {
- char *playlist = argv[1];
+handle_playlistdelete(gcc_unused Client &client, Request args, Response &r)
+{
+ const char *const name = args[0];
unsigned from;
-
- if (!check_unsigned(client, &from, argv[2]))
+ if (!args.Parse(1, from, r))
return CommandResult::ERROR;
Error error;
- return spl_remove_index(playlist, from, error)
+ return spl_remove_index(name, from, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistmove(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistmove(gcc_unused Client &client, Request args, Response &r)
{
- char *playlist = argv[1];
+ const char *const name = args.front();
unsigned from, to;
-
- if (!check_unsigned(client, &from, argv[2]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &to, argv[3]))
+ if (!args.Parse(1, from, r) || !args.Parse(2, to, r))
return CommandResult::ERROR;
Error error;
- return spl_move_index(playlist, from, to, error)
+ return spl_move_index(name, from, to, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistclear(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistclear(gcc_unused Client &client, Request args, Response &r)
{
+ const char *const name = args.front();
+
Error error;
- return spl_clear(argv[1], error)
+ return spl_clear(name, error)
? CommandResult::OK
- : print_error(client, error);
+ : print_error(r, error);
}
CommandResult
-handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_playlistadd(Client &client, Request args, Response &r)
{
- char *playlist = argv[1];
- char *uri = argv[2];
+ const char *const playlist = args[0];
+ const char *const uri = args[1];
bool success;
Error error;
@@ -179,7 +194,7 @@ handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
#ifdef ENABLE_DATABASE
const Database *db = client.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
success = search_add_to_playlist(*db, *client.GetStorage(),
uri, playlist, nullptr,
@@ -190,23 +205,22 @@ handle_playlistadd(Client &client, gcc_unused unsigned argc, char *argv[])
}
if (!success && !error.IsDefined()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "directory or file not found");
+ r.Error(ACK_ERROR_NO_EXIST, "directory or file not found");
return CommandResult::ERROR;
}
- return success ? CommandResult::OK : print_error(client, error);
+ return success ? CommandResult::OK : print_error(r, error);
}
CommandResult
-handle_listplaylists(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listplaylists(gcc_unused Client &client, gcc_unused Request args,
+ Response &r)
{
Error error;
const auto list = ListPlaylistFiles(error);
if (list.empty() && error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- print_spl_list(client, list);
+ print_spl_list(r, list);
return CommandResult::OK;
}
diff --git a/src/command/PlaylistCommands.hxx b/src/command/PlaylistCommands.hxx
index fba4e1318..9f263df62 100644
--- a/src/command/PlaylistCommands.hxx
+++ b/src/command/PlaylistCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,40 +21,47 @@
#define MPD_PLAYLIST_COMMANDS_HXX
#include "CommandResult.hxx"
+#include "Compiler.h"
class Client;
+class Request;
+class Response;
+
+gcc_const
+bool
+playlist_commands_available();
CommandResult
-handle_save(Client &client, unsigned argc, char *argv[]);
+handle_save(Client &client, Request request, Response &response);
CommandResult
-handle_load(Client &client, unsigned argc, char *argv[]);
+handle_load(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylist(Client &client, unsigned argc, char *argv[]);
+handle_listplaylist(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylistinfo(Client &client, unsigned argc, char *argv[]);
+handle_listplaylistinfo(Client &client, Request request, Response &response);
CommandResult
-handle_rm(Client &client, unsigned argc, char *argv[]);
+handle_rm(Client &client, Request request, Response &response);
CommandResult
-handle_rename(Client &client, unsigned argc, char *argv[]);
+handle_rename(Client &client, Request request, Response &response);
CommandResult
-handle_playlistdelete(Client &client, unsigned argc, char *argv[]);
+handle_playlistdelete(Client &client, Request request, Response &response);
CommandResult
-handle_playlistmove(Client &client, unsigned argc, char *argv[]);
+handle_playlistmove(Client &client, Request request, Response &response);
CommandResult
-handle_playlistclear(Client &client, unsigned argc, char *argv[]);
+handle_playlistclear(Client &client, Request request, Response &response);
CommandResult
-handle_playlistadd(Client &client, unsigned argc, char *argv[]);
+handle_playlistadd(Client &client, Request request, Response &response);
CommandResult
-handle_listplaylists(Client &client, unsigned argc, char *argv[]);
+handle_listplaylists(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx
index d0b789eb1..7751aa26d 100644
--- a/src/command/QueueCommands.cxx
+++ b/src/command/QueueCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,19 +19,20 @@
#include "config.h"
#include "QueueCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "db/DatabaseQueue.hxx"
#include "db/Selection.hxx"
#include "SongFilter.hxx"
#include "SongLoader.hxx"
+#include "DetachedSong.hxx"
+#include "LocateUri.hxx"
#include "queue/Playlist.hxx"
#include "PlaylistPrint.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "BulkEdit.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
-#include "ls.hxx"
#include "util/ConstBuffer.hxx"
#include "util/UriUtil.hxx"
#include "util/NumberParser.hxx"
@@ -42,26 +43,48 @@
#include <string.h>
-static const char *
-translate_uri(Client &client, const char *uri)
+static CommandResult
+AddUri(Client &client, const LocatedUri &uri, Response &r)
{
- if (memcmp(uri, "file:///", 8) == 0)
- /* drop the "file://", leave only an absolute path
- (starting with a slash) */
- return uri + 7;
-
- if (PathTraitsUTF8::IsAbsolute(uri)) {
- command_error(client, ACK_ERROR_NO_EXIST, "Malformed URI");
- return nullptr;
- }
+ Error error;
+ DetachedSong *song = SongLoader(client).LoadSong(uri, error);
+ if (song == nullptr)
+ return print_error(r, error);
+
+ auto &partition = client.partition;
+ unsigned id = partition.playlist.AppendSong(partition.pc,
+ std::move(*song), error);
+ delete song;
+ if (id == 0)
+ return print_error(r, error);
+
+ return CommandResult::OK;
+}
+
+static CommandResult
+AddDatabaseSelection(Client &client, const char *uri, Response &r)
+{
+#ifdef ENABLE_DATABASE
+ const ScopeBulkEdit bulk_edit(client.partition);
+
+ const DatabaseSelection selection(uri, true);
+ Error error;
+ return AddFromDatabase(client.partition, selection, error)
+ ? CommandResult::OK
+ : print_error(r, error);
+#else
+ (void)client;
+ (void)uri;
- return uri;
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
+ return CommandResult::ERROR;
+#endif
}
CommandResult
-handle_add(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_add(Client &client, Request args, Response &r)
{
- const char *uri = argv[1];
+ const char *uri = args.front();
if (memcmp(uri, "/", 2) == 0)
/* this URI is malformed, but some clients are buggy
and use "add /" to add the whole database, which
@@ -70,61 +93,54 @@ handle_add(Client &client, gcc_unused unsigned argc, char *argv[])
here */
uri = "";
- uri = translate_uri(client, uri);
- if (uri == nullptr)
- return CommandResult::ERROR;
-
- if (uri_has_scheme(uri) || PathTraitsUTF8::IsAbsolute(uri)) {
- const SongLoader loader(client);
- Error error;
- unsigned id = client.partition.AppendURI(loader, uri, error);
- if (id == 0)
- return print_error(client, error);
-
- return CommandResult::OK;
- }
-
-#ifdef ENABLE_DATABASE
- const ScopeBulkEdit bulk_edit(client.partition);
-
- const DatabaseSelection selection(uri, true);
Error error;
- return AddFromDatabase(client.partition, selection, error)
- ? CommandResult::OK
- : print_error(client, error);
-#else
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
- return CommandResult::ERROR;
+ const auto located_uri = LocateUri(uri, &client,
+#ifdef ENABLE_DATABASE
+ nullptr,
#endif
+ error);
+ switch (located_uri.type) {
+ case LocatedUri::Type::UNKNOWN:
+ return print_error(r, error);
+
+ case LocatedUri::Type::ABSOLUTE:
+ case LocatedUri::Type::PATH:
+ return AddUri(client, located_uri, r);
+
+ case LocatedUri::Type::RELATIVE:
+ return AddDatabaseSelection(client, located_uri.canonical_uri,
+ r);
+ }
+
+ gcc_unreachable();
}
CommandResult
-handle_addid(Client &client, unsigned argc, char *argv[])
+handle_addid(Client &client, Request args, Response &r)
{
- const char *const uri = translate_uri(client, argv[1]);
- if (uri == nullptr)
- return CommandResult::ERROR;
+ const char *const uri = args.front();
const SongLoader loader(client);
Error error;
unsigned added_id = client.partition.AppendURI(loader, uri, error);
if (added_id == 0)
- return print_error(client, error);
+ return print_error(r, error);
- if (argc == 3) {
+ if (args.size == 2) {
unsigned to;
- if (!check_unsigned(client, &to, argv[2]))
+ if (!args.Parse(1, to, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.MoveId(added_id, to);
if (result != PlaylistResult::SUCCESS) {
CommandResult ret =
- print_playlist_result(client, result);
+ print_playlist_result(r, result);
client.partition.DeleteId(added_id);
return ret;
}
}
- client_printf(client, "Id: %u\n", added_id);
+ r.Format("Id: %u\n", added_id);
return CommandResult::OK;
}
@@ -160,15 +176,15 @@ parse_time_range(const char *p, SongTime &start_r, SongTime &end_r)
}
CommandResult
-handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_rangeid(Client &client, Request args, Response &r)
{
unsigned id;
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
SongTime start, end;
- if (!parse_time_range(argv[2], start, end)) {
- command_error(client, ACK_ERROR_ARG, "Bad range");
+ if (!parse_time_range(args[1], start, end)) {
+ r.Error(ACK_ERROR_ARG, "Bad range");
return CommandResult::ERROR;
}
@@ -176,118 +192,110 @@ handle_rangeid(Client &client, gcc_unused unsigned argc, char *argv[])
if (!client.partition.playlist.SetSongIdRange(client.partition.pc,
id, start, end,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_delete(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_delete(Client &client, Request args, Response &r)
{
- unsigned start, end;
-
- if (!check_range(client, &start, &end, argv[1]))
+ RangeArg range;
+ if (!args.Parse(0, range, r))
return CommandResult::ERROR;
- PlaylistResult result = client.partition.DeleteRange(start, end);
- return print_playlist_result(client, result);
+ auto result = client.partition.DeleteRange(range.start, range.end);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_deleteid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_deleteid(Client &client, Request args, Response &r)
{
unsigned id;
-
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.DeleteId(id);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_playlist(Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_playlist(Client &client, gcc_unused Request args, Response &r)
{
- playlist_print_uris(client, client.playlist);
+ playlist_print_uris(r, client.partition, client.playlist);
return CommandResult::OK;
}
CommandResult
-handle_shuffle(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_shuffle(gcc_unused Client &client, Request args, Response &r)
{
- unsigned start = 0, end = client.playlist.queue.GetLength();
- if (argc == 2 && !check_range(client, &start, &end, argv[1]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(0, range, r))
return CommandResult::ERROR;
- client.partition.Shuffle(start, end);
+ client.partition.Shuffle(range.start, range.end);
return CommandResult::OK;
}
CommandResult
-handle_clear(gcc_unused Client &client,
- gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_clear(Client &client, gcc_unused Request args, gcc_unused Response &r)
{
client.partition.ClearQueue();
return CommandResult::OK;
}
CommandResult
-handle_plchanges(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_plchanges(Client &client, Request args, Response &r)
{
uint32_t version;
-
- if (!check_uint32(client, &version, argv[1]))
+ if (!ParseCommandArg32(r, version, args.front()))
return CommandResult::ERROR;
- playlist_print_changes_info(client, client.playlist, version);
+ playlist_print_changes_info(r, client.partition,
+ client.playlist, version);
return CommandResult::OK;
}
CommandResult
-handle_plchangesposid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_plchangesposid(Client &client, Request args, Response &r)
{
uint32_t version;
-
- if (!check_uint32(client, &version, argv[1]))
+ if (!ParseCommandArg32(r, version, args.front()))
return CommandResult::ERROR;
- playlist_print_changes_position(client, client.playlist, version);
+ playlist_print_changes_position(r, client.playlist, version);
return CommandResult::OK;
}
CommandResult
-handle_playlistinfo(Client &client, unsigned argc, char *argv[])
+handle_playlistinfo(Client &client, Request args, Response &r)
{
- unsigned start = 0, end = std::numeric_limits<unsigned>::max();
- bool ret;
-
- if (argc == 2 && !check_range(client, &start, &end, argv[1]))
+ RangeArg range = RangeArg::All();
+ if (!args.ParseOptional(0, range, r))
return CommandResult::ERROR;
- ret = playlist_print_info(client, client.playlist, start, end);
- if (!ret)
- return print_playlist_result(client,
+ if (!playlist_print_info(r, client.partition, client.playlist,
+ range.start, range.end))
+ return print_playlist_result(r,
PlaylistResult::BAD_RANGE);
return CommandResult::OK;
}
CommandResult
-handle_playlistid(Client &client, unsigned argc, char *argv[])
+handle_playlistid(Client &client, Request args, Response &r)
{
- if (argc >= 2) {
+ if (!args.IsEmpty()) {
unsigned id;
- if (!check_unsigned(client, &id, argv[1]))
+ if (!args.Parse(0, id, r))
return CommandResult::ERROR;
- bool ret = playlist_print_id(client, client.playlist, id);
+ bool ret = playlist_print_id(r, client.partition,
+ client.playlist, id);
if (!ret)
- return print_playlist_result(client,
- PlaylistResult::NO_SUCH_SONG);
+ return print_playlist_result(r, PlaylistResult::NO_SUCH_SONG);
} else {
- playlist_print_info(client, client.playlist,
+ playlist_print_info(r, client.partition, client.playlist,
0, std::numeric_limits<unsigned>::max());
}
@@ -295,147 +303,120 @@ handle_playlistid(Client &client, unsigned argc, char *argv[])
}
static CommandResult
-handle_playlist_match(Client &client, unsigned argc, char *argv[],
+handle_playlist_match(Client &client, Request args, Response &r,
bool fold_case)
{
- ConstBuffer<const char *> args(argv + 1, argc - 1);
-
SongFilter filter;
if (!filter.Parse(args, fold_case)) {
- command_error(client, ACK_ERROR_ARG, "incorrect arguments");
+ r.Error(ACK_ERROR_ARG, "incorrect arguments");
return CommandResult::ERROR;
}
- playlist_print_find(client, client.playlist, filter);
+ playlist_print_find(r, client.partition, client.playlist, filter);
return CommandResult::OK;
}
CommandResult
-handle_playlistfind(Client &client, unsigned argc, char *argv[])
+handle_playlistfind(Client &client, Request args, Response &r)
{
- return handle_playlist_match(client, argc, argv, false);
+ return handle_playlist_match(client, args, r, false);
}
CommandResult
-handle_playlistsearch(Client &client, unsigned argc, char *argv[])
+handle_playlistsearch(Client &client, Request args, Response &r)
{
- return handle_playlist_match(client, argc, argv, true);
+ return handle_playlist_match(client, args, r, true);
}
CommandResult
-handle_prio(Client &client, unsigned argc, char *argv[])
+handle_prio(Client &client, Request args, Response &r)
{
unsigned priority;
-
- if (!check_unsigned(client, &priority, argv[1]))
+ if (!args.ParseShift(0, priority, r, 0xff))
return CommandResult::ERROR;
- if (priority > 0xff) {
- command_error(client, ACK_ERROR_ARG,
- "Priority out of range: %s", argv[1]);
- return CommandResult::ERROR;
- }
-
- for (unsigned i = 2; i < argc; ++i) {
- unsigned start_position, end_position;
- if (!check_range(client, &start_position, &end_position,
- argv[i]))
+ for (const char *i : args) {
+ RangeArg range;
+ if (!ParseCommandArg(r, range, i))
return CommandResult::ERROR;
PlaylistResult result =
- client.partition.SetPriorityRange(start_position,
- end_position,
- priority);
+ client.partition.SetPriorityRange(range.start,
+ range.end,
+ priority);
if (result != PlaylistResult::SUCCESS)
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
return CommandResult::OK;
}
CommandResult
-handle_prioid(Client &client, unsigned argc, char *argv[])
+handle_prioid(Client &client, Request args, Response &r)
{
unsigned priority;
-
- if (!check_unsigned(client, &priority, argv[1]))
+ if (!args.ParseShift(0, priority, r, 0xff))
return CommandResult::ERROR;
- if (priority > 0xff) {
- command_error(client, ACK_ERROR_ARG,
- "Priority out of range: %s", argv[1]);
- return CommandResult::ERROR;
- }
-
- for (unsigned i = 2; i < argc; ++i) {
+ for (const char *i : args) {
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[i]))
+ if (!ParseCommandArg(r, song_id, i))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SetPriorityId(song_id, priority);
if (result != PlaylistResult::SUCCESS)
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
return CommandResult::OK;
}
CommandResult
-handle_move(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_move(Client &client, Request args, Response &r)
{
- unsigned start, end;
+ RangeArg range;
int to;
- if (!check_range(client, &start, &end, argv[1]))
- return CommandResult::ERROR;
- if (!check_int(client, &to, argv[2]))
+ if (!args.Parse(0, range, r) || !args.Parse(1, to, r))
return CommandResult::ERROR;
PlaylistResult result =
- client.partition.MoveRange(start, end, to);
- return print_playlist_result(client, result);
+ client.partition.MoveRange(range.start, range.end, to);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_moveid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_moveid(Client &client, Request args, Response &r)
{
unsigned id;
int to;
-
- if (!check_unsigned(client, &id, argv[1]))
- return CommandResult::ERROR;
- if (!check_int(client, &to, argv[2]))
+ if (!args.Parse(0, id, r) || !args.Parse(1, to, r))
return CommandResult::ERROR;
+
PlaylistResult result = client.partition.MoveId(id, to);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_swap(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_swap(Client &client, Request args, Response &r)
{
unsigned song1, song2;
-
- if (!check_unsigned(client, &song1, argv[1]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &song2, argv[2]))
+ if (!args.Parse(0, song1, r) || !args.Parse(1, song2, r))
return CommandResult::ERROR;
PlaylistResult result =
client.partition.SwapPositions(song1, song2);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
CommandResult
-handle_swapid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_swapid(Client &client, Request args, Response &r)
{
unsigned id1, id2;
-
- if (!check_unsigned(client, &id1, argv[1]))
- return CommandResult::ERROR;
- if (!check_unsigned(client, &id2, argv[2]))
+ if (!args.Parse(0, id1, r) || !args.Parse(1, id2, r))
return CommandResult::ERROR;
PlaylistResult result = client.partition.SwapIds(id1, id2);
- return print_playlist_result(client, result);
+ return print_playlist_result(r, result);
}
diff --git a/src/command/QueueCommands.hxx b/src/command/QueueCommands.hxx
index f98f7bad2..49499d8ea 100644
--- a/src/command/QueueCommands.hxx
+++ b/src/command/QueueCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,65 +23,67 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_add(Client &client, unsigned argc, char *argv[]);
+handle_add(Client &client, Request request, Response &response);
CommandResult
-handle_addid(Client &client, unsigned argc, char *argv[]);
+handle_addid(Client &client, Request request, Response &response);
CommandResult
-handle_rangeid(Client &client, unsigned argc, char *argv[]);
+handle_rangeid(Client &client, Request request, Response &response);
CommandResult
-handle_delete(Client &client, unsigned argc, char *argv[]);
+handle_delete(Client &client, Request request, Response &response);
CommandResult
-handle_deleteid(Client &client, unsigned argc, char *argv[]);
+handle_deleteid(Client &client, Request request, Response &response);
CommandResult
-handle_playlist(Client &client, unsigned argc, char *argv[]);
+handle_playlist(Client &client, Request request, Response &response);
CommandResult
-handle_shuffle(Client &client, unsigned argc, char *argv[]);
+handle_shuffle(Client &client, Request request, Response &response);
CommandResult
-handle_clear(Client &client, unsigned argc, char *argv[]);
+handle_clear(Client &client, Request request, Response &response);
CommandResult
-handle_plchanges(Client &client, unsigned argc, char *argv[]);
+handle_plchanges(Client &client, Request request, Response &response);
CommandResult
-handle_plchangesposid(Client &client, unsigned argc, char *argv[]);
+handle_plchangesposid(Client &client, Request request, Response &response);
CommandResult
-handle_playlistinfo(Client &client, unsigned argc, char *argv[]);
+handle_playlistinfo(Client &client, Request request, Response &response);
CommandResult
-handle_playlistid(Client &client, unsigned argc, char *argv[]);
+handle_playlistid(Client &client, Request request, Response &response);
CommandResult
-handle_playlistfind(Client &client, unsigned argc, char *argv[]);
+handle_playlistfind(Client &client, Request request, Response &response);
CommandResult
-handle_playlistsearch(Client &client, unsigned argc, char *argv[]);
+handle_playlistsearch(Client &client, Request request, Response &response);
CommandResult
-handle_prio(Client &client, unsigned argc, char *argv[]);
+handle_prio(Client &client, Request request, Response &response);
CommandResult
-handle_prioid(Client &client, unsigned argc, char *argv[]);
+handle_prioid(Client &client, Request request, Response &response);
CommandResult
-handle_move(Client &client, unsigned argc, char *argv[]);
+handle_move(Client &client, Request request, Response &response);
CommandResult
-handle_moveid(Client &client, unsigned argc, char *argv[]);
+handle_moveid(Client &client, Request request, Response &response);
CommandResult
-handle_swap(Client &client, unsigned argc, char *argv[]);
+handle_swap(Client &client, Request request, Response &response);
CommandResult
-handle_swapid(Client &client, unsigned argc, char *argv[]);
+handle_swapid(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/Request.hxx b/src/command/Request.hxx
new file mode 100644
index 000000000..1616b7045
--- /dev/null
+++ b/src/command/Request.hxx
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_REQUEST_HXX
+#define MPD_REQUEST_HXX
+
+#include "check.h"
+#include "protocol/ArgParser.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <utility>
+
+#include <assert.h>
+
+class Response;
+
+class Request : public ConstBuffer<const char *> {
+ typedef ConstBuffer<const char *> Base;
+
+public:
+ constexpr Request(const char *const*argv, size_type n)
+ :Base(argv, n) {}
+
+ constexpr const char *GetOptional(unsigned idx,
+ const char *default_value=nullptr) const {
+ return idx < size
+ ? data[idx]
+ : default_value;
+ }
+
+ template<typename T, typename... Args>
+ bool Parse(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ assert(idx < size);
+
+ return ParseCommandArg(r, value_r, data[idx],
+ std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ bool ParseOptional(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ return idx >= size ||
+ Parse(idx, value_r, r,
+ std::forward<Args>(args)...);
+ }
+
+ template<typename T, typename... Args>
+ bool ParseShift(unsigned idx, T &value_r, Response &r,
+ Args&&... args) {
+ bool success = Parse(idx, value_r, r,
+ std::forward<Args>(args)...);
+ shift();
+ return success;
+ }
+};
+
+#endif
diff --git a/src/command/StickerCommands.cxx b/src/command/StickerCommands.cxx
index 37506d51b..d5d7ab1f8 100644
--- a/src/command/StickerCommands.cxx
+++ b/src/command/StickerCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "StickerCommands.hxx"
+#include "Request.hxx"
#include "SongPrint.hxx"
#include "db/Interface.hxx"
#include "db/DatabaseGlue.hxx"
@@ -26,16 +27,17 @@
#include "sticker/StickerPrint.hxx"
#include "sticker/StickerDatabase.hxx"
#include "CommandError.hxx"
-#include "protocol/Result.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "util/Error.hxx"
-
-#include <string.h>
+#include "util/ConstBuffer.hxx"
+#include "util/StringAPI.hxx"
struct sticker_song_find_data {
- Client &client;
+ Response &r;
+ Partition &partition;
const char *name;
};
@@ -46,125 +48,161 @@ sticker_song_find_print_cb(const LightSong &song, const char *value,
struct sticker_song_find_data *data =
(struct sticker_song_find_data *)user_data;
- song_print_uri(data->client, song);
- sticker_print_value(data->client, data->name, value);
+ song_print_uri(data->r, data->partition, song);
+ sticker_print_value(data->r, data->name, value);
}
static CommandResult
-handle_sticker_song(Client &client, unsigned argc, char *argv[])
+handle_sticker_song(Response &r, Partition &partition, Request args)
{
Error error;
- const Database *db = client.GetDatabase(error);
+ const Database *db = partition.GetDatabase(error);
if (db == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
+
+ const char *const cmd = args.front();
/* get song song_id key */
- if (argc == 5 && strcmp(argv[1], "get") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ if (args.size == 4 && StringIsEqual(cmd, "get")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- const auto value = sticker_song_get_value(*song, argv[4]);
+ const auto value = sticker_song_get_value(*song, args[3],
+ error);
db->ReturnSong(song);
if (value.empty()) {
- command_error(client, ACK_ERROR_NO_EXIST,
- "no such sticker");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_NO_EXIST, "no such sticker");
return CommandResult::ERROR;
}
- sticker_print_value(client, argv[4], value.c_str());
+ sticker_print_value(r, args[3], value.c_str());
return CommandResult::OK;
/* list song song_id */
- } else if (argc == 4 && strcmp(argv[1], "list") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if (args.size == 3 && StringIsEqual(cmd, "list")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- sticker *sticker = sticker_song_get(*song);
+ Sticker *sticker = sticker_song_get(*song, error);
db->ReturnSong(song);
if (sticker) {
- sticker_print(client, *sticker);
+ sticker_print(r, *sticker);
sticker_free(sticker);
- }
+ } else if (error.IsDefined())
+ return print_error(r, error);
return CommandResult::OK;
/* set song song_id id key */
- } else if (argc == 6 && strcmp(argv[1], "set") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if (args.size == 5 && StringIsEqual(cmd, "set")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- bool ret = sticker_song_set_value(*song, argv[4], argv[5]);
+ bool ret = sticker_song_set_value(*song, args[3], args[4],
+ error);
db->ReturnSong(song);
if (!ret) {
- command_error(client, ACK_ERROR_SYSTEM,
- "failed to set sticker value");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM,
+ "failed to set sticker value");
return CommandResult::ERROR;
}
return CommandResult::OK;
/* delete song song_id [key] */
- } else if ((argc == 4 || argc == 5) &&
- strcmp(argv[1], "delete") == 0) {
- const LightSong *song = db->GetSong(argv[3], error);
+ } else if ((args.size == 3 || args.size == 4) &&
+ StringIsEqual(cmd, "delete")) {
+ const LightSong *song = db->GetSong(args[2], error);
if (song == nullptr)
- return print_error(client, error);
+ return print_error(r, error);
- bool ret = argc == 4
- ? sticker_song_delete(*song)
- : sticker_song_delete_value(*song, argv[4]);
+ bool ret = args.size == 3
+ ? sticker_song_delete(*song, error)
+ : sticker_song_delete_value(*song, args[3], error);
db->ReturnSong(song);
if (!ret) {
- command_error(client, ACK_ERROR_SYSTEM,
- "no such sticker");
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM, "no such sticker");
return CommandResult::ERROR;
}
return CommandResult::OK;
/* find song dir key */
- } else if (argc == 5 && strcmp(argv[1], "find") == 0) {
+ } else if ((args.size == 4 || args.size == 6) &&
+ StringIsEqual(cmd, "find")) {
/* "sticker find song a/directory name" */
- const char *const base_uri = argv[3];
+ const char *const base_uri = args[2];
+
+ StickerOperator op = StickerOperator::EXISTS;
+ const char *value = nullptr;
+
+ if (args.size == 6) {
+ /* match the value */
+
+ const char *op_s = args[4];
+ value = args[5];
+
+ if (StringIsEqual(op_s, "="))
+ op = StickerOperator::EQUALS;
+ else if (StringIsEqual(op_s, "<"))
+ op = StickerOperator::LESS_THAN;
+ else if (StringIsEqual(op_s, ">"))
+ op = StickerOperator::GREATER_THAN;
+ else {
+ r.Error(ACK_ERROR_ARG, "bad operator");
+ return CommandResult::ERROR;
+ }
+ }
- bool success;
struct sticker_song_find_data data = {
- client,
- argv[4],
+ r,
+ partition,
+ args[3],
};
- success = sticker_song_find(*db, base_uri, data.name,
- sticker_song_find_print_cb, &data);
- if (!success) {
- command_error(client, ACK_ERROR_SYSTEM,
- "failed to set search sticker database");
+ if (!sticker_song_find(*db, base_uri, data.name,
+ op, value,
+ sticker_song_find_print_cb, &data,
+ error)) {
+ if (error.IsDefined())
+ return print_error(r, error);
+
+ r.Error(ACK_ERROR_SYSTEM,
+ "failed to set search sticker database");
return CommandResult::ERROR;
}
return CommandResult::OK;
} else {
- command_error(client, ACK_ERROR_ARG, "bad request");
+ r.Error(ACK_ERROR_ARG, "bad request");
return CommandResult::ERROR;
}
}
CommandResult
-handle_sticker(Client &client, unsigned argc, char *argv[])
+handle_sticker(Client &client, Request args, Response &r)
{
- assert(argc >= 4);
+ assert(args.size >= 3);
if (!sticker_enabled()) {
- command_error(client, ACK_ERROR_UNKNOWN,
- "sticker database is disabled");
+ r.Error(ACK_ERROR_UNKNOWN, "sticker database is disabled");
return CommandResult::ERROR;
}
- if (strcmp(argv[2], "song") == 0)
- return handle_sticker_song(client, argc, argv);
+ if (StringIsEqual(args[1], "song"))
+ return handle_sticker_song(r, client.partition, args);
else {
- command_error(client, ACK_ERROR_ARG,
- "unknown sticker domain");
+ r.Error(ACK_ERROR_ARG, "unknown sticker domain");
return CommandResult::ERROR;
}
}
diff --git a/src/command/StickerCommands.hxx b/src/command/StickerCommands.hxx
index cf46cd034..5bb9cc426 100644
--- a/src/command/StickerCommands.hxx
+++ b/src/command/StickerCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,8 +23,10 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_sticker(Client &client, unsigned argc, char *argv[]);
+handle_sticker(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/StorageCommands.cxx b/src/command/StorageCommands.cxx
index ee51c573e..3c11eb0d7 100644
--- a/src/command/StorageCommands.cxx
+++ b/src/command/StorageCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,12 +21,14 @@
#include "config.h"
#include "StorageCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
-#include "protocol/Result.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
+#include "util/ConstBuffer.hxx"
#include "fs/Traits.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
#include "Partition.hxx"
#include "Instance.hxx"
#include "storage/Registry.hxx"
@@ -55,7 +57,7 @@ skip_path(const char *name_utf8)
#endif
static bool
-handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
+handle_listfiles_storage(Response &r, StorageDirectoryReader &reader,
Error &error)
{
const char *name_utf8;
@@ -63,29 +65,29 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
if (skip_path(name_utf8))
continue;
- FileInfo info;
+ StorageFileInfo info;
if (!reader.GetInfo(false, info, error))
continue;
switch (info.type) {
- case FileInfo::Type::OTHER:
+ case StorageFileInfo::Type::OTHER:
/* ignore */
continue;
- case FileInfo::Type::REGULAR:
- client_printf(client, "file: %s\n"
- "size: %" PRIu64 "\n",
- name_utf8,
- info.size);
+ case StorageFileInfo::Type::REGULAR:
+ r.Format("file: %s\n"
+ "size: %" PRIu64 "\n",
+ name_utf8,
+ info.size);
break;
- case FileInfo::Type::DIRECTORY:
- client_printf(client, "directory: %s\n", name_utf8);
+ case StorageFileInfo::Type::DIRECTORY:
+ r.Format("directory: %s\n", name_utf8);
break;
}
if (info.mtime != 0)
- time_print(client, "Last-Modified", info.mtime);
+ time_print(r, "Last-Modified", info.mtime);
}
return true;
@@ -96,58 +98,57 @@ handle_listfiles_storage(Client &client, StorageDirectoryReader &reader,
#endif
static bool
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri,
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri,
Error &error)
{
auto reader = storage.OpenDirectory(uri, error);
if (reader == nullptr)
return false;
- bool success = handle_listfiles_storage(client, *reader, error);
+ bool success = handle_listfiles_storage(r, *reader, error);
delete reader;
return success;
}
CommandResult
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri)
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri)
{
Error error;
- if (!handle_listfiles_storage(client, storage, uri, error))
- return print_error(client, error);
+ if (!handle_listfiles_storage(r, storage, uri, error))
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_listfiles_storage(Client &client, const char *uri)
+handle_listfiles_storage(Response &r, const char *uri)
{
Error error;
Storage *storage = CreateStorageURI(io_thread_get(), uri, error);
if (storage == nullptr) {
if (error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized storage URI");
+ r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR;
}
- bool success = handle_listfiles_storage(client, *storage, "", error);
+ bool success = handle_listfiles_storage(r, *storage, "", error);
delete storage;
if (!success)
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
static void
-print_storage_uri(Client &client, const Storage &storage)
+print_storage_uri(Client &client, Response &r, const Storage &storage)
{
std::string uri = storage.MapUTF8("");
if (uri.empty())
return;
- if (PathTraitsFS::IsAbsolute(uri.c_str())) {
+ if (PathTraitsUTF8::IsAbsolute(uri.c_str())) {
/* storage points to local directory */
if (!client.IsLocal())
@@ -163,24 +164,24 @@ print_storage_uri(Client &client, const Storage &storage)
uri = std::move(allocated);
}
- client_printf(client, "storage: %s\n", uri.c_str());
+ r.Format("storage: %s\n", uri.c_str());
}
CommandResult
-handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *argv[])
+handle_listmounts(Client &client, gcc_unused Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const auto visitor = [&client](const char *mount_uri,
- const Storage &storage){
- client_printf(client, "mount: %s\n", mount_uri);
- print_storage_uri(client, storage);
+ const auto visitor = [&client, &r](const char *mount_uri,
+ const Storage &storage){
+ r.Format("mount: %s\n", mount_uri);
+ print_storage_uri(client, r, storage);
};
composite.VisitMounts(visitor);
@@ -189,21 +190,21 @@ handle_listmounts(Client &client, gcc_unused unsigned argc, gcc_unused char *arg
}
CommandResult
-handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_mount(Client &client, Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const char *const local_uri = argv[1];
- const char *const remote_uri = argv[2];
+ const char *const local_uri = args[0];
+ const char *const remote_uri = args[1];
if (*local_uri == 0) {
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -213,7 +214,7 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
UpdateQueue::Erase() really gets called for every
unmount, and no Directory disappears recursively
during database update */
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -222,10 +223,9 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
error);
if (storage == nullptr) {
if (error.IsDefined())
- return print_error(client, error);
+ return print_error(r, error);
- command_error(client, ACK_ERROR_ARG,
- "Unrecognized storage URI");
+ r.Error(ACK_ERROR_ARG, "Unrecognized storage URI");
return CommandResult::ERROR;
}
@@ -239,7 +239,7 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
if (!db.Mount(local_uri, remote_uri, error)) {
composite.Unmount(local_uri);
- return print_error(client, error);
+ return print_error(r, error);
}
// TODO: call Instance::OnDatabaseModified()?
@@ -252,20 +252,20 @@ handle_mount(Client &client, gcc_unused unsigned argc, char *argv[])
}
CommandResult
-handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_unmount(Client &client, Request args, Response &r)
{
Storage *_composite = client.partition.instance.storage;
if (_composite == nullptr) {
- command_error(client, ACK_ERROR_NO_EXIST, "No database");
+ r.Error(ACK_ERROR_NO_EXIST, "No database");
return CommandResult::ERROR;
}
CompositeStorage &composite = *(CompositeStorage *)_composite;
- const char *const local_uri = argv[1];
+ const char *const local_uri = args.front();
if (*local_uri == 0) {
- command_error(client, ACK_ERROR_ARG, "Bad mount point");
+ r.Error(ACK_ERROR_ARG, "Bad mount point");
return CommandResult::ERROR;
}
@@ -287,7 +287,7 @@ handle_unmount(Client &client, gcc_unused unsigned argc, char *argv[])
#endif
if (!composite.Unmount(local_uri)) {
- command_error(client, ACK_ERROR_ARG, "Not a mount point");
+ r.Error(ACK_ERROR_ARG, "Not a mount point");
return CommandResult::ERROR;
}
diff --git a/src/command/StorageCommands.hxx b/src/command/StorageCommands.hxx
index a3636d54a..7d3c552f6 100644
--- a/src/command/StorageCommands.hxx
+++ b/src/command/StorageCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,20 +24,22 @@
class Client;
class Storage;
+class Request;
+class Response;
CommandResult
-handle_listfiles_storage(Client &client, Storage &storage, const char *uri);
+handle_listfiles_storage(Response &r, Storage &storage, const char *uri);
CommandResult
-handle_listfiles_storage(Client &client, const char *uri);
+handle_listfiles_storage(Response &r, const char *uri);
CommandResult
-handle_listmounts(Client &client, unsigned argc, char *argv[]);
+handle_listmounts(Client &client, Request request, Response &response);
CommandResult
-handle_mount(Client &client, unsigned argc, char *argv[]);
+handle_mount(Client &client, Request request, Response &response);
CommandResult
-handle_unmount(Client &client, unsigned argc, char *argv[]);
+handle_unmount(Client &client, Request request, Response &response);
#endif
diff --git a/src/command/TagCommands.cxx b/src/command/TagCommands.cxx
index 2d537671c..2a7076bdc 100644
--- a/src/command/TagCommands.cxx
+++ b/src/command/TagCommands.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,51 +19,51 @@
#include "config.h"
#include "TagCommands.hxx"
+#include "Request.hxx"
#include "CommandError.hxx"
#include "client/Client.hxx"
-#include "protocol/ArgParser.hxx"
-#include "protocol/Result.hxx"
+#include "client/Response.hxx"
#include "tag/Tag.hxx"
#include "Partition.hxx"
+#include "util/ConstBuffer.hxx"
CommandResult
-handle_addtagid(Client &client, gcc_unused unsigned argc, char *argv[])
+handle_addtagid(Client &client, Request args, Response &r)
{
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[1]))
+ if (!args.Parse(0, song_id, r))
return CommandResult::ERROR;
- const char *const tag_name = argv[2];
+ const char *const tag_name = args[1];
const TagType tag_type = tag_name_parse_i(tag_name);
if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
- "Unknown tag type: %s", tag_name);
+ r.FormatError(ACK_ERROR_ARG, "Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
- const char *const value = argv[3];
+ const char *const value = args[2];
Error error;
if (!client.partition.playlist.AddSongIdTag(song_id, tag_type, value,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
CommandResult
-handle_cleartagid(Client &client, unsigned argc, char *argv[])
+handle_cleartagid(Client &client, Request args, Response &r)
{
unsigned song_id;
- if (!check_unsigned(client, &song_id, argv[1]))
+ if (!args.Parse(0, song_id, r))
return CommandResult::ERROR;
TagType tag_type = TAG_NUM_OF_ITEM_TYPES;
- if (argc >= 3) {
- const char *const tag_name = argv[2];
+ if (args.size >= 2) {
+ const char *const tag_name = args[1];
tag_type = tag_name_parse_i(tag_name);
if (tag_type == TAG_NUM_OF_ITEM_TYPES) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Unknown tag type: %s", tag_name);
return CommandResult::ERROR;
}
@@ -72,7 +72,7 @@ handle_cleartagid(Client &client, unsigned argc, char *argv[])
Error error;
if (!client.partition.playlist.ClearSongIdTag(song_id, tag_type,
error))
- return print_error(client, error);
+ return print_error(r, error);
return CommandResult::OK;
}
diff --git a/src/command/TagCommands.hxx b/src/command/TagCommands.hxx
index 748838e68..868d6d783 100644
--- a/src/command/TagCommands.hxx
+++ b/src/command/TagCommands.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,11 +23,13 @@
#include "CommandResult.hxx"
class Client;
+class Request;
+class Response;
CommandResult
-handle_addtagid(Client &client, unsigned argc, char *argv[]);
+handle_addtagid(Client &client, Request request, Response &response);
CommandResult
-handle_cleartagid(Client &client, unsigned argc, char *argv[]);
+handle_cleartagid(Client &client, Request request, Response &response);
#endif
diff --git a/src/config/ConfigData.cxx b/src/config/Block.cxx
index 70e1e55ed..a74903b10 100644
--- a/src/config/ConfigData.cxx
+++ b/src/config/Block.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,18 +18,18 @@
*/
#include "config.h"
-#include "ConfigData.hxx"
+#include "Block.hxx"
#include "ConfigParser.hxx"
#include "ConfigPath.hxx"
-#include "util/Error.hxx"
-#include "fs/AllocatedPath.hxx"
#include "system/FatalError.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "util/Error.hxx"
#include <assert.h>
#include <stdlib.h>
int
-block_param::GetIntValue() const
+BlockParam::GetIntValue() const
{
char *endptr;
long value2 = strtol(value.c_str(), &endptr, 0);
@@ -40,7 +40,7 @@ block_param::GetIntValue() const
}
unsigned
-block_param::GetUnsignedValue() const
+BlockParam::GetUnsignedValue() const
{
char *endptr;
unsigned long value2 = strtoul(value.c_str(), &endptr, 0);
@@ -51,7 +51,7 @@ block_param::GetUnsignedValue() const
}
bool
-block_param::GetBoolValue() const
+BlockParam::GetBoolValue() const
{
bool value2;
if (!get_bool(value.c_str(), &value2))
@@ -62,16 +62,13 @@ block_param::GetBoolValue() const
return value2;
}
-config_param::config_param(const char *_value, int _line)
- :next(nullptr), value(_value), line(_line), used(false) {}
-
-config_param::~config_param()
+ConfigBlock::~ConfigBlock()
{
delete next;
}
-const block_param *
-config_param::GetBlockParam(const char *name) const
+const BlockParam *
+ConfigBlock::GetBlockParam(const char *name) const
{
for (const auto &i : block_params) {
if (i.name == name) {
@@ -80,13 +77,13 @@ config_param::GetBlockParam(const char *name) const
}
}
- return NULL;
+ return nullptr;
}
const char *
-config_param::GetBlockValue(const char *name, const char *default_value) const
+ConfigBlock::GetBlockValue(const char *name, const char *default_value) const
{
- const block_param *bp = GetBlockParam(name);
+ const BlockParam *bp = GetBlockParam(name);
if (bp == nullptr)
return default_value;
@@ -94,7 +91,7 @@ config_param::GetBlockValue(const char *name, const char *default_value) const
}
AllocatedPath
-config_param::GetBlockPath(const char *name, const char *default_value,
+ConfigBlock::GetBlockPath(const char *name, const char *default_value,
Error &error) const
{
assert(!error.IsDefined());
@@ -102,7 +99,7 @@ config_param::GetBlockPath(const char *name, const char *default_value,
int line2 = line;
const char *s;
- const block_param *bp = GetBlockParam(name);
+ const BlockParam *bp = GetBlockParam(name);
if (bp != nullptr) {
line2 = bp->line;
s = bp->value.c_str();
@@ -122,15 +119,15 @@ config_param::GetBlockPath(const char *name, const char *default_value,
}
AllocatedPath
-config_param::GetBlockPath(const char *name, Error &error) const
+ConfigBlock::GetBlockPath(const char *name, Error &error) const
{
return GetBlockPath(name, nullptr, error);
}
int
-config_param::GetBlockValue(const char *name, int default_value) const
+ConfigBlock::GetBlockValue(const char *name, int default_value) const
{
- const block_param *bp = GetBlockParam(name);
+ const BlockParam *bp = GetBlockParam(name);
if (bp == nullptr)
return default_value;
@@ -138,9 +135,9 @@ config_param::GetBlockValue(const char *name, int default_value) const
}
unsigned
-config_param::GetBlockValue(const char *name, unsigned default_value) const
+ConfigBlock::GetBlockValue(const char *name, unsigned default_value) const
{
- const block_param *bp = GetBlockParam(name);
+ const BlockParam *bp = GetBlockParam(name);
if (bp == nullptr)
return default_value;
@@ -149,10 +146,10 @@ config_param::GetBlockValue(const char *name, unsigned default_value) const
gcc_pure
bool
-config_param::GetBlockValue(const char *name, bool default_value) const
+ConfigBlock::GetBlockValue(const char *name, bool default_value) const
{
- const block_param *bp = GetBlockParam(name);
- if (bp == NULL)
+ const BlockParam *bp = GetBlockParam(name);
+ if (bp == nullptr)
return default_value;
return bp->GetBoolValue();
diff --git a/src/config/ConfigData.hxx b/src/config/Block.hxx
index e42d674ba..9e72018ca 100644
--- a/src/config/ConfigData.hxx
+++ b/src/config/Block.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,20 +17,20 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_CONFIG_DATA_HXX
-#define MPD_CONFIG_DATA_HXX
+#ifndef MPD_CONFIG_BLOCK_HXX
+#define MPD_CONFIG_BLOCK_HXX
-#include "ConfigOption.hxx"
+#include "check.h"
+#include "Param.hxx"
#include "Compiler.h"
#include <string>
-#include <array>
#include <vector>
-class AllocatedPath;
class Error;
+class AllocatedPath;
-struct block_param {
+struct BlockParam {
std::string name;
std::string value;
int line;
@@ -42,7 +42,7 @@ struct block_param {
mutable bool used;
gcc_nonnull_all
- block_param(const char *_name, const char *_value, int _line=-1)
+ BlockParam(const char *_name, const char *_value, int _line=-1)
:name(_name), value(_value), line(_line), used(false) {}
gcc_pure
@@ -55,18 +55,16 @@ struct block_param {
bool GetBoolValue() const;
};
-struct config_param {
+struct ConfigBlock {
/**
- * The next config_param with the same name. The destructor
+ * The next #ConfigBlock with the same name. The destructor
* deletes the whole chain.
*/
- struct config_param *next;
-
- std::string value;
+ ConfigBlock *next;
- unsigned int line;
+ int line;
- std::vector<block_param> block_params;
+ std::vector<BlockParam> block_params;
/**
* This flag is false when nobody has queried the value of
@@ -74,17 +72,14 @@ struct config_param {
*/
bool used;
- config_param(int _line=-1)
+ explicit ConfigBlock(int _line=-1)
:next(nullptr), line(_line), used(false) {}
- gcc_nonnull_all
- config_param(const char *_value, int _line=-1);
-
- config_param(const config_param &) = delete;
+ ConfigBlock(const ConfigBlock &) = delete;
- ~config_param();
+ ~ConfigBlock();
- config_param &operator=(const config_param &) = delete;
+ ConfigBlock &operator=(const ConfigBlock &) = delete;
/**
* Determine if this is a "null" instance, i.e. an empty
@@ -92,7 +87,12 @@ struct config_param {
* configuration file.
*/
bool IsNull() const {
- return line == unsigned(-1);
+ return line < 0;
+ }
+
+ gcc_pure
+ bool IsEmpty() const {
+ return block_params.empty();
}
gcc_nonnull_all
@@ -102,14 +102,14 @@ struct config_param {
}
gcc_nonnull_all gcc_pure
- const block_param *GetBlockParam(const char *_name) const;
+ const BlockParam *GetBlockParam(const char *_name) const;
gcc_pure
const char *GetBlockValue(const char *name,
const char *default_value=nullptr) const;
/**
- * Same as config_dup_path(), but looks up the setting in the
+ * Same as config_get_path(), but looks up the setting in the
* specified block.
*/
AllocatedPath GetBlockPath(const char *name, const char *default_value,
@@ -127,8 +127,4 @@ struct config_param {
bool GetBlockValue(const char *name, bool default_value) const;
};
-struct ConfigData {
- std::array<config_param *, std::size_t(CONF_MAX)> params;
-};
-
#endif
diff --git a/src/config/ConfigDefaults.hxx b/src/config/ConfigDefaults.hxx
index c50f28c91..2dca5d469 100644
--- a/src/config/ConfigDefaults.hxx
+++ b/src/config/ConfigDefaults.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigError.cxx b/src/config/ConfigError.cxx
index 70aff7175..b2a773b15 100644
--- a/src/config/ConfigError.cxx
+++ b/src/config/ConfigError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigError.hxx b/src/config/ConfigError.hxx
index cbfa79df3..89543599d 100644
--- a/src/config/ConfigError.hxx
+++ b/src/config/ConfigError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigFile.cxx b/src/config/ConfigFile.cxx
index 1329c4cd4..b6164b8bc 100644
--- a/src/config/ConfigFile.cxx
+++ b/src/config/ConfigFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,28 +19,27 @@
#include "config.h"
#include "ConfigFile.hxx"
-#include "ConfigData.hxx"
+#include "Data.hxx"
+#include "Param.hxx"
+#include "Block.hxx"
#include "ConfigTemplates.hxx"
#include "util/Tokenizer.hxx"
#include "util/StringUtil.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
-#include "fs/Limits.hxx"
#include "fs/Path.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/io/FileReader.hxx"
+#include "fs/io/BufferedReader.hxx"
#include "Log.hxx"
#include <assert.h>
-#include <stdio.h>
-#define MAX_STRING_SIZE MPD_PATH_MAX+80
-
-#define CONF_COMMENT '#'
+static constexpr char CONF_COMMENT = '#';
static constexpr Domain config_file_domain("config_file");
static bool
-config_read_name_value(struct config_param *param, char *input, unsigned line,
+config_read_name_value(ConfigBlock &block, char *input, unsigned line,
Error &error)
{
Tokenizer tokenizer(input);
@@ -67,7 +66,7 @@ config_read_name_value(struct config_param *param, char *input, unsigned line,
return false;
}
- const struct block_param *bp = param->GetBlockParam(name);
+ const BlockParam *bp = block.GetBlockParam(name);
if (bp != nullptr) {
error.Format(config_file_domain,
"\"%s\" is duplicate, first defined on line %i",
@@ -75,27 +74,26 @@ config_read_name_value(struct config_param *param, char *input, unsigned line,
return false;
}
- param->AddBlockParam(name, value, line);
+ block.AddBlockParam(name, value, line);
return true;
}
-static struct config_param *
-config_read_block(FILE *fp, int *count, char *string, Error &error)
+static ConfigBlock *
+config_read_block(BufferedReader &reader, Error &error)
{
- struct config_param *ret = new config_param(*count);
+ auto *ret = new ConfigBlock(reader.GetLineNumber());
while (true) {
- char *line;
-
- line = fgets(string, MAX_STRING_SIZE, fp);
+ char *line = reader.ReadLine();
if (line == nullptr) {
delete ret;
- error.Set(config_file_domain,
- "Expected '}' before end-of-file");
+
+ if (reader.Check(error))
+ error.Set(config_file_domain,
+ "Expected '}' before end-of-file");
return nullptr;
}
- (*count)++;
line = StripLeft(line);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -108,8 +106,8 @@ config_read_block(FILE *fp, int *count, char *string, Error &error)
if (*line != 0 && *line != CONF_COMMENT) {
delete ret;
error.Format(config_file_domain,
- "line %i: Unknown tokens after '}'",
- *count);
+ "line %y: Unknown tokens after '}'",
+ reader.GetLineNumber());
return nullptr;
}
@@ -118,10 +116,11 @@ config_read_block(FILE *fp, int *count, char *string, Error &error)
/* parse name and value */
- if (!config_read_name_value(ret, line, *count, error)) {
+ if (!config_read_name_value(*ret, line, reader.GetLineNumber(),
+ error)) {
assert(*line != 0);
delete ret;
- error.FormatPrefix("line %i: ", *count);
+ error.FormatPrefix("line %u: ", reader.GetLineNumber());
return nullptr;
}
}
@@ -129,6 +128,64 @@ config_read_block(FILE *fp, int *count, char *string, Error &error)
gcc_nonnull_all
static void
+Append(ConfigBlock *&head, ConfigBlock *p)
+{
+ assert(p->next == nullptr);
+
+ auto **i = &head;
+ while (*i != nullptr)
+ i = &(*i)->next;
+
+ *i = p;
+}
+
+static bool
+ReadConfigBlock(ConfigData &config_data, BufferedReader &reader,
+ const char *name, ConfigBlockOption o,
+ Tokenizer &tokenizer,
+ Error &error)
+{
+ const unsigned i = unsigned(o);
+ const ConfigTemplate &option = config_block_templates[i];
+ ConfigBlock *&head = config_data.blocks[i];
+
+ if (head != nullptr && !option.repeatable) {
+ ConfigBlock *block = head;
+ error.Format(config_file_domain,
+ "config parameter \"%s\" is first defined "
+ "on line %d and redefined on line %u\n",
+ name, block->line,
+ reader.GetLineNumber());
+ return false;
+ }
+
+ /* now parse the block or the value */
+
+ if (tokenizer.CurrentChar() != '{') {
+ error.Format(config_file_domain,
+ "line %u: '{' expected",
+ reader.GetLineNumber());
+ return false;
+ }
+
+ char *line = StripLeft(tokenizer.Rest() + 1);
+ if (*line != 0 && *line != CONF_COMMENT) {
+ error.Format(config_file_domain,
+ "line %u: Unknown tokens after '{'",
+ reader.GetLineNumber());
+ return false;
+ }
+
+ auto *param = config_read_block(reader, error);
+ if (param == nullptr)
+ return false;
+
+ Append(head, param);
+ return true;
+}
+
+gcc_nonnull_all
+static void
Append(config_param *&head, config_param *p)
{
assert(p->next == nullptr);
@@ -141,21 +198,62 @@ Append(config_param *&head, config_param *p)
}
static bool
-ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error)
+ReadConfigParam(ConfigData &config_data, BufferedReader &reader,
+ const char *name, ConfigOption o,
+ Tokenizer &tokenizer,
+ Error &error)
{
- assert(fp != nullptr);
+ const unsigned i = unsigned(o);
+ const ConfigTemplate &option = config_param_templates[i];
+ config_param *&head = config_data.params[i];
- char string[MAX_STRING_SIZE + 1];
- int count = 0;
- struct config_param *param;
+ if (head != nullptr && !option.repeatable) {
+ struct config_param *param = head;
+ error.Format(config_file_domain,
+ "config parameter \"%s\" is first defined "
+ "on line %d and redefined on line %u\n",
+ name, param->line,
+ reader.GetLineNumber());
+ return false;
+ }
- while (fgets(string, MAX_STRING_SIZE, fp)) {
- char *line;
- const char *name, *value;
+ /* now parse the block or the value */
- count++;
+ const char *value = tokenizer.NextString(error);
+ if (value == nullptr) {
+ if (tokenizer.IsEnd())
+ error.Format(config_file_domain,
+ "line %u: Value missing",
+ reader.GetLineNumber());
+ else
+ error.FormatPrefix("line %u: ",
+ reader.GetLineNumber());
- line = StripLeft(string);
+ return false;
+ }
+
+ if (!tokenizer.IsEnd() &&
+ tokenizer.CurrentChar() != CONF_COMMENT) {
+ error.Format(config_file_domain,
+ "line %u: Unknown tokens after value",
+ reader.GetLineNumber());
+ return false;
+ }
+
+ auto *param = new config_param(value, reader.GetLineNumber());
+ Append(head, param);
+ return true;
+}
+
+static bool
+ReadConfigFile(ConfigData &config_data, BufferedReader &reader, Error &error)
+{
+ while (true) {
+ char *line = reader.ReadLine();
+ if (line == nullptr)
+ return true;
+
+ line = StripLeft(line);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -163,10 +261,10 @@ ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error)
by either the value or '{' */
Tokenizer tokenizer(line);
- name = tokenizer.NextWord(error);
+ const char *name = tokenizer.NextWord(error);
if (name == nullptr) {
assert(!tokenizer.IsEnd());
- error.FormatPrefix("line %i: ", count);
+ error.FormatPrefix("line %u: ", reader.GetLineNumber());
return false;
}
@@ -174,79 +272,23 @@ ReadConfigFile(ConfigData &config_data, FILE *fp, Error &error)
"repeatable" flag */
const ConfigOption o = ParseConfigOptionName(name);
- if (o == CONF_MAX) {
- error.Format(config_file_domain,
- "unrecognized parameter in config file at "
- "line %i: %s\n", count, name);
- return false;
- }
-
- const unsigned i = unsigned(o);
- const ConfigTemplate &option = config_templates[i];
- config_param *&head = config_data.params[i];
-
- if (head != nullptr && !option.repeatable) {
- param = head;
- error.Format(config_file_domain,
- "config parameter \"%s\" is first defined "
- "on line %i and redefined on line %i\n",
- name, param->line, count);
- return false;
- }
-
- /* now parse the block or the value */
-
- if (option.block) {
- /* it's a block, call config_read_block() */
-
- if (tokenizer.CurrentChar() != '{') {
- error.Format(config_file_domain,
- "line %i: '{' expected", count);
- return false;
- }
-
- line = StripLeft(tokenizer.Rest() + 1);
- if (*line != 0 && *line != CONF_COMMENT) {
- error.Format(config_file_domain,
- "line %i: Unknown tokens after '{'",
- count);
+ ConfigBlockOption bo;
+ if (o != ConfigOption::MAX) {
+ if (!ReadConfigParam(config_data, reader, name, o,
+ tokenizer, error))
return false;
- }
-
- param = config_read_block(fp, &count, string, error);
- if (param == nullptr) {
+ } else if ((bo = ParseConfigBlockOptionName(name)) != ConfigBlockOption::MAX) {
+ if (!ReadConfigBlock(config_data, reader, name, bo,
+ tokenizer, error))
return false;
- }
} else {
- /* a string value */
-
- value = tokenizer.NextString(error);
- if (value == nullptr) {
- if (tokenizer.IsEnd())
- error.Format(config_file_domain,
- "line %i: Value missing",
- count);
- else
- error.FormatPrefix("line %i: ", count);
-
- return false;
- }
-
- if (!tokenizer.IsEnd() &&
- tokenizer.CurrentChar() != CONF_COMMENT) {
- error.Format(config_file_domain,
- "line %i: Unknown tokens after value",
- count);
- return false;
- }
-
- param = new config_param(value, count);
+ error.Format(config_file_domain,
+ "unrecognized parameter in config file at "
+ "line %u: %s\n",
+ reader.GetLineNumber(), name);
+ return false;
}
-
- Append(head, param);
}
-
- return true;
}
bool
@@ -257,13 +299,11 @@ ReadConfigFile(ConfigData &config_data, Path path, Error &error)
FormatDebug(config_file_domain, "loading file %s", path_utf8.c_str());
- FILE *fp = FOpen(path, FOpenMode::ReadText);
- if (fp == nullptr) {
- error.FormatErrno("Failed to open %s", path_utf8.c_str());
+ FileReader file(path, error);
+ if (!file.IsDefined())
return false;
- }
- bool result = ReadConfigFile(config_data, fp, error);
- fclose(fp);
- return result;
+ BufferedReader reader(file);
+ return ReadConfigFile(config_data, reader, error) &&
+ reader.Check(error);
}
diff --git a/src/config/ConfigFile.hxx b/src/config/ConfigFile.hxx
index b87182c6a..30bee0614 100644
--- a/src/config/ConfigFile.hxx
+++ b/src/config/ConfigFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigGlobal.cxx b/src/config/ConfigGlobal.cxx
index 9bc83398c..192baffec 100644
--- a/src/config/ConfigGlobal.cxx
+++ b/src/config/ConfigGlobal.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,9 @@
#include "config.h"
#include "ConfigGlobal.hxx"
#include "ConfigParser.hxx"
-#include "ConfigData.hxx"
+#include "Data.hxx"
+#include "Param.hxx"
+#include "Block.hxx"
#include "ConfigFile.hxx"
#include "ConfigPath.hxx"
#include "ConfigError.hxx"
@@ -36,8 +38,7 @@ static ConfigData config_data;
void config_global_finish(void)
{
- for (auto i : config_data.params)
- delete i;
+ config_data.Clear();
}
void config_global_init(void)
@@ -51,15 +52,15 @@ ReadConfigFile(Path path, Error &error)
}
static void
-Check(const config_param *param)
+Check(const ConfigBlock &block)
{
- if (!param->used)
- /* this whole config_param was not queried at all -
+ if (!block.used)
+ /* this whole block was not queried at all -
the feature might be disabled at compile time?
Silently ignore it here. */
return;
- for (const auto &i : param->block_params) {
+ for (const auto &i : block.block_params) {
if (!i.used)
FormatWarning(config_domain,
"option '%s' on line %i was not recognized",
@@ -69,9 +70,9 @@ Check(const config_param *param)
void config_global_check(void)
{
- for (auto i : config_data.params)
- for (const config_param *p = i; p != nullptr; p = p->next)
- Check(p);
+ for (auto i : config_data.blocks)
+ for (const auto *p = i; p != nullptr; p = p->next)
+ Check(*p);
}
const config_param *
@@ -83,18 +84,27 @@ config_get_param(ConfigOption option)
return param;
}
-const config_param *
-config_find_block(ConfigOption option, const char *key, const char *value)
+const ConfigBlock *
+config_get_block(ConfigBlockOption option)
+{
+ ConfigBlock *block = config_data.blocks[unsigned(option)];
+ if (block != nullptr)
+ block->used = true;
+ return block;
+}
+
+const ConfigBlock *
+config_find_block(ConfigBlockOption option, const char *key, const char *value)
{
- for (const config_param *param = config_get_param(option);
- param != nullptr; param = param->next) {
- const char *value2 = param->GetBlockValue(key);
+ for (const auto *block = config_get_block(option);
+ block != nullptr; block = block->next) {
+ const char *value2 = block->GetBlockValue(key);
if (value2 == nullptr)
FormatFatalError("block without '%s' name in line %d",
- key, param->line);
+ key, block->line);
if (strcmp(value2, value) == 0)
- return param;
+ return block;
}
return nullptr;
diff --git a/src/config/ConfigGlobal.hxx b/src/config/ConfigGlobal.hxx
index 831418d03..b24b9aada 100644
--- a/src/config/ConfigGlobal.hxx
+++ b/src/config/ConfigGlobal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,15 +27,20 @@ class Error;
class Path;
class AllocatedPath;
struct config_param;
+struct ConfigBlock;
-void config_global_init(void);
-void config_global_finish(void);
+void
+config_global_init();
+
+void
+config_global_finish();
/**
* Call this function after all configuration has been evaluated. It
* checks for unused parameters, and logs warnings.
*/
-void config_global_check(void);
+void
+config_global_check();
bool
ReadConfigFile(Path path, Error &error);
@@ -44,6 +49,10 @@ gcc_pure
const config_param *
config_get_param(enum ConfigOption option);
+gcc_pure
+const ConfigBlock *
+config_get_block(enum ConfigBlockOption option);
+
/**
* Find a block with a matching attribute.
*
@@ -52,8 +61,8 @@ config_get_param(enum ConfigOption option);
* @param value the expected attribute value
*/
gcc_pure
-const config_param *
-config_find_block(ConfigOption option, const char *key, const char *value);
+const ConfigBlock *
+config_find_block(ConfigBlockOption option, const char *key, const char *value);
/* Note on gcc_pure: Some of the functions declared pure are not
really pure in strict sense. They have side effect such that they
@@ -64,7 +73,7 @@ config_find_block(ConfigOption option, const char *key, const char *value);
gcc_pure
const char *
-config_get_string(enum ConfigOption option, const char *default_value);
+config_get_string(enum ConfigOption option, const char *default_value=nullptr);
/**
* Returns an optional configuration variable which contains an
diff --git a/src/config/ConfigOption.hxx b/src/config/ConfigOption.hxx
index 8eb4c7eaf..5acd6fd49 100644
--- a/src/config/ConfigOption.hxx
+++ b/src/config/ConfigOption.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,71 +22,93 @@
#include "Compiler.h"
-enum ConfigOption {
- CONF_MUSIC_DIR,
- CONF_PLAYLIST_DIR,
- CONF_FOLLOW_INSIDE_SYMLINKS,
- CONF_FOLLOW_OUTSIDE_SYMLINKS,
- CONF_DB_FILE,
- CONF_STICKER_FILE,
- CONF_LOG_FILE,
- CONF_PID_FILE,
- CONF_STATE_FILE,
- CONF_STATE_FILE_INTERVAL,
- CONF_RESTORE_PAUSED,
- CONF_USER,
- CONF_GROUP,
- CONF_BIND_TO_ADDRESS,
- CONF_PORT,
- CONF_LOG_LEVEL,
- CONF_ZEROCONF_NAME,
- CONF_ZEROCONF_ENABLED,
- CONF_PASSWORD,
- CONF_DEFAULT_PERMS,
- CONF_AUDIO_OUTPUT,
- CONF_AUDIO_OUTPUT_FORMAT,
- CONF_MIXER_TYPE,
- CONF_REPLAYGAIN,
- CONF_REPLAYGAIN_PREAMP,
- CONF_REPLAYGAIN_MISSING_PREAMP,
- CONF_REPLAYGAIN_LIMIT,
- CONF_VOLUME_NORMALIZATION,
- CONF_SAMPLERATE_CONVERTER,
- CONF_AUDIO_BUFFER_SIZE,
- CONF_BUFFER_BEFORE_PLAY,
- CONF_HTTP_PROXY_HOST,
- CONF_HTTP_PROXY_PORT,
- CONF_HTTP_PROXY_USER,
- CONF_HTTP_PROXY_PASSWORD,
- CONF_CONN_TIMEOUT,
- CONF_MAX_CONN,
- CONF_MAX_PLAYLIST_LENGTH,
- CONF_MAX_COMMAND_LIST_SIZE,
- CONF_MAX_OUTPUT_BUFFER_SIZE,
- CONF_FS_CHARSET,
- CONF_ID3V1_ENCODING,
- CONF_METADATA_TO_USE,
- CONF_SAVE_ABSOLUTE_PATHS,
- CONF_DECODER,
- CONF_INPUT,
- CONF_GAPLESS_MP3_PLAYBACK,
- CONF_PLAYLIST_PLUGIN,
- CONF_AUTO_UPDATE,
- CONF_AUTO_UPDATE_DEPTH,
- CONF_DESPOTIFY_USER,
- CONF_DESPOTIFY_PASSWORD,
- CONF_DESPOTIFY_HIGH_BITRATE,
- CONF_AUDIO_FILTER,
- CONF_DATABASE,
- CONF_NEIGHBORS,
- CONF_MAX
+#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
+/* "INPUT" is declared by winuser.h */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+enum class ConfigOption {
+ MUSIC_DIR,
+ PLAYLIST_DIR,
+ FOLLOW_INSIDE_SYMLINKS,
+ FOLLOW_OUTSIDE_SYMLINKS,
+ DB_FILE,
+ STICKER_FILE,
+ LOG_FILE,
+ PID_FILE,
+ STATE_FILE,
+ STATE_FILE_INTERVAL,
+ RESTORE_PAUSED,
+ USER,
+ GROUP,
+ BIND_TO_ADDRESS,
+ PORT,
+ LOG_LEVEL,
+ ZEROCONF_NAME,
+ ZEROCONF_ENABLED,
+ PASSWORD,
+ DEFAULT_PERMS,
+ AUDIO_OUTPUT_FORMAT,
+ MIXER_TYPE,
+ REPLAYGAIN,
+ REPLAYGAIN_PREAMP,
+ REPLAYGAIN_MISSING_PREAMP,
+ REPLAYGAIN_LIMIT,
+ VOLUME_NORMALIZATION,
+ SAMPLERATE_CONVERTER,
+ AUDIO_BUFFER_SIZE,
+ BUFFER_BEFORE_PLAY,
+ HTTP_PROXY_HOST,
+ HTTP_PROXY_PORT,
+ HTTP_PROXY_USER,
+ HTTP_PROXY_PASSWORD,
+ CONN_TIMEOUT,
+ MAX_CONN,
+ MAX_PLAYLIST_LENGTH,
+ MAX_COMMAND_LIST_SIZE,
+ MAX_OUTPUT_BUFFER_SIZE,
+ FS_CHARSET,
+ ID3V1_ENCODING,
+ METADATA_TO_USE,
+ SAVE_ABSOLUTE_PATHS,
+ GAPLESS_MP3_PLAYBACK,
+ AUTO_UPDATE,
+ AUTO_UPDATE_DEPTH,
+ DESPOTIFY_USER,
+ DESPOTIFY_PASSWORD,
+ DESPOTIFY_HIGH_BITRATE,
+ MAX
};
+enum class ConfigBlockOption {
+ AUDIO_OUTPUT,
+ DECODER,
+ INPUT,
+ PLAYLIST_PLUGIN,
+ RESAMPLER,
+ AUDIO_FILTER,
+ DATABASE,
+ NEIGHBORS,
+ MAX
+};
+
+#if defined(WIN32) && CLANG_OR_GCC_VERSION(4,7)
+#pragma GCC diagnostic pop
+#endif
+
/**
- * @return #CONF_MAX if not found
+ * @return #ConfigOption::MAX if not found
*/
gcc_pure
enum ConfigOption
ParseConfigOptionName(const char *name);
+/**
+ * @return #ConfigOption::MAX if not found
+ */
+gcc_pure
+enum ConfigBlockOption
+ParseConfigBlockOptionName(const char *name);
+
#endif
diff --git a/src/config/ConfigParser.cxx b/src/config/ConfigParser.cxx
index 3535c9a13..40afe1edd 100644
--- a/src/config/ConfigParser.cxx
+++ b/src/config/ConfigParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,8 +23,8 @@
bool
get_bool(const char *value, bool *value_r)
{
- static const char *t[] = { "yes", "true", "1", nullptr };
- static const char *f[] = { "no", "false", "0", nullptr };
+ static const char *const t[] = { "yes", "true", "1", nullptr };
+ static const char *const f[] = { "no", "false", "0", nullptr };
if (string_array_contains(t, value)) {
*value_r = true;
diff --git a/src/config/ConfigParser.hxx b/src/config/ConfigParser.hxx
index 06151b0bd..c696801f5 100644
--- a/src/config/ConfigParser.hxx
+++ b/src/config/ConfigParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigPath.cxx b/src/config/ConfigPath.cxx
index a3b3f83a5..c1e57b3ba 100644
--- a/src/config/ConfigPath.cxx
+++ b/src/config/ConfigPath.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -70,7 +70,7 @@ GetHome(Error &error)
static AllocatedPath
GetConfiguredHome(Error &error)
{
- const char *user = config_get_string(CONF_USER, nullptr);
+ const char *user = config_get_string(ConfigOption::USER);
return user != nullptr
? GetHome(user, error)
: GetHome(error);
diff --git a/src/config/ConfigPath.hxx b/src/config/ConfigPath.hxx
index a5518a497..afd3e0435 100644
--- a/src/config/ConfigPath.hxx
+++ b/src/config/ConfigPath.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/config/ConfigTemplates.cxx b/src/config/ConfigTemplates.cxx
index 58ee56425..cd353dc19 100644
--- a/src/config/ConfigTemplates.cxx
+++ b/src/config/ConfigTemplates.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,80 +19,110 @@
#include "ConfigTemplates.hxx"
#include "ConfigOption.hxx"
+#include "util/Macros.hxx"
#include <string.h>
-const ConfigTemplate config_templates[] = {
- { "music_directory", false, false },
- { "playlist_directory", false, false },
- { "follow_inside_symlinks", false, false },
- { "follow_outside_symlinks", false, false },
- { "db_file", false, false },
- { "sticker_file", false, false },
- { "log_file", false, false },
- { "pid_file", false, false },
- { "state_file", false, false },
- { "state_file_interval", false, false },
- { "restore_paused", false, false },
- { "user", false, false },
- { "group", false, false },
- { "bind_to_address", true, false },
- { "port", false, false },
- { "log_level", false, false },
- { "zeroconf_name", false, false },
- { "zeroconf_enabled", false, false },
- { "password", true, false },
- { "default_permissions", false, false },
- { "audio_output", true, true },
- { "audio_output_format", false, false },
- { "mixer_type", false, false },
- { "replaygain", false, false },
- { "replaygain_preamp", false, false },
- { "replaygain_missing_preamp", false, false },
- { "replaygain_limit", false, false },
- { "volume_normalization", false, false },
- { "samplerate_converter", false, false },
- { "audio_buffer_size", false, false },
- { "buffer_before_play", false, false },
- { "http_proxy_host", false, false },
- { "http_proxy_port", false, false },
- { "http_proxy_user", false, false },
- { "http_proxy_password", false, false },
- { "connection_timeout", false, false },
- { "max_connections", false, false },
- { "max_playlist_length", false, false },
- { "max_command_list_size", false, false },
- { "max_output_buffer_size", false, false },
- { "filesystem_charset", false, false },
- { "id3v1_encoding", false, false },
- { "metadata_to_use", false, false },
- { "save_absolute_paths_in_playlists", false, false },
- { "decoder", true, true },
- { "input", true, true },
- { "gapless_mp3_playback", false, false },
- { "playlist_plugin", true, true },
- { "auto_update", false, false },
- { "auto_update_depth", false, false },
- { "despotify_user", false, false },
- { "despotify_password", false, false},
- { "despotify_high_bitrate", false, false },
- { "filter", true, true },
- { "database", false, true },
- { "neighbors", true, true },
+const ConfigTemplate config_param_templates[] = {
+ { "music_directory" },
+ { "playlist_directory" },
+ { "follow_inside_symlinks" },
+ { "follow_outside_symlinks" },
+ { "db_file" },
+ { "sticker_file" },
+ { "log_file" },
+ { "pid_file" },
+ { "state_file" },
+ { "state_file_interval" },
+ { "restore_paused" },
+ { "user" },
+ { "group" },
+ { "bind_to_address", true },
+ { "port" },
+ { "log_level" },
+ { "zeroconf_name" },
+ { "zeroconf_enabled" },
+ { "password", true },
+ { "default_permissions" },
+ { "audio_output_format" },
+ { "mixer_type" },
+ { "replaygain" },
+ { "replaygain_preamp" },
+ { "replaygain_missing_preamp" },
+ { "replaygain_limit" },
+ { "volume_normalization" },
+ { "samplerate_converter" },
+ { "audio_buffer_size" },
+ { "buffer_before_play" },
+ { "http_proxy_host", false, true },
+ { "http_proxy_port", false, true },
+ { "http_proxy_user", false, true },
+ { "http_proxy_password", false, true },
+ { "connection_timeout" },
+ { "max_connections" },
+ { "max_playlist_length" },
+ { "max_command_list_size" },
+ { "max_output_buffer_size" },
+ { "filesystem_charset" },
+ { "id3v1_encoding", false, true },
+ { "metadata_to_use" },
+ { "save_absolute_paths_in_playlists" },
+ { "gapless_mp3_playback" },
+ { "auto_update" },
+ { "auto_update_depth" },
+ { "despotify_user", false, true },
+ { "despotify_password", false, true },
+ { "despotify_high_bitrate", false, true },
};
-static constexpr unsigned n_config_templates =
- sizeof(config_templates) / sizeof(config_templates[0]);
+static constexpr unsigned n_config_param_templates =
+ ARRAY_SIZE(config_param_templates);
-static_assert(n_config_templates == unsigned(CONF_MAX),
- "Wrong number of config_templates");
+static_assert(n_config_param_templates == unsigned(ConfigOption::MAX),
+ "Wrong number of config_param_templates");
+
+const ConfigTemplate config_block_templates[] = {
+ { "audio_output", true },
+ { "decoder", true },
+ { "input", true },
+ { "playlist_plugin", true },
+ { "resampler" },
+ { "filter", true },
+ { "database" },
+ { "neighbors", true },
+};
+
+static constexpr unsigned n_config_block_templates =
+ ARRAY_SIZE(config_block_templates);
+
+static_assert(n_config_block_templates == unsigned(ConfigBlockOption::MAX),
+ "Wrong number of config_block_templates");
+
+gcc_pure
+static inline unsigned
+ParseConfigTemplateName(const ConfigTemplate templates[], unsigned count,
+ const char *name)
+{
+ unsigned i = 0;
+ for (; i < count; ++i)
+ if (strcmp(templates[i].name, name) == 0)
+ break;
+
+ return i;
+}
ConfigOption
ParseConfigOptionName(const char *name)
{
- for (unsigned i = 0; i < n_config_templates; ++i)
- if (strcmp(config_templates[i].name, name) == 0)
- return ConfigOption(i);
+ return ConfigOption(ParseConfigTemplateName(config_param_templates,
+ n_config_param_templates,
+ name));
+}
- return CONF_MAX;
+ConfigBlockOption
+ParseConfigBlockOptionName(const char *name)
+{
+ return ConfigBlockOption(ParseConfigTemplateName(config_block_templates,
+ n_config_block_templates,
+ name));
}
diff --git a/src/config/ConfigTemplates.hxx b/src/config/ConfigTemplates.hxx
index 90d098dc0..3a18ebdc8 100644
--- a/src/config/ConfigTemplates.hxx
+++ b/src/config/ConfigTemplates.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,9 +23,18 @@
struct ConfigTemplate {
const char *const name;
const bool repeatable;
- const bool block;
+
+ // TODO: print warning when a deprecated option is used
+ const bool deprecated;
+
+ constexpr ConfigTemplate(const char *_name,
+ bool _repeatable=false,
+ bool _deprecated=false)
+ :name(_name), repeatable(_repeatable),
+ deprecated(_deprecated) {}
};
-extern const ConfigTemplate config_templates[];
+extern const ConfigTemplate config_param_templates[];
+extern const ConfigTemplate config_block_templates[];
#endif
diff --git a/src/config/Data.cxx b/src/config/Data.cxx
new file mode 100644
index 000000000..52521e31a
--- /dev/null
+++ b/src/config/Data.cxx
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Data.hxx"
+#include "Param.hxx"
+#include "Block.hxx"
+
+void
+ConfigData::Clear()
+{
+ for (auto &i : params) {
+ delete i;
+ i = nullptr;
+ }
+
+ for (auto &i : blocks) {
+ delete i;
+ i = nullptr;
+ }
+}
diff --git a/src/config/Data.hxx b/src/config/Data.hxx
new file mode 100644
index 000000000..6036c49e6
--- /dev/null
+++ b/src/config/Data.hxx
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CONFIG_DATA_HXX
+#define MPD_CONFIG_DATA_HXX
+
+#include "ConfigOption.hxx"
+
+#include <array>
+
+struct config_param;
+struct ConfigBlock;
+
+struct ConfigData {
+ std::array<config_param *, std::size_t(ConfigOption::MAX)> params;
+ std::array<ConfigBlock *, std::size_t(ConfigBlockOption::MAX)> blocks;
+
+ void Clear();
+};
+
+#endif
diff --git a/src/config/Param.cxx b/src/config/Param.cxx
new file mode 100644
index 000000000..bfd9743d2
--- /dev/null
+++ b/src/config/Param.cxx
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Param.hxx"
+
+config_param::config_param(const char *_value, int _line)
+ :next(nullptr), value(_value), line(_line), used(false) {}
+
+config_param::~config_param()
+{
+ delete next;
+}
diff --git a/src/config/Param.hxx b/src/config/Param.hxx
new file mode 100644
index 000000000..e6a039c2a
--- /dev/null
+++ b/src/config/Param.hxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_CONFIG_PARAM_HXX
+#define MPD_CONFIG_PARAM_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#include <string>
+
+struct config_param {
+ /**
+ * The next config_param with the same name. The destructor
+ * deletes the whole chain.
+ */
+ struct config_param *next;
+
+ std::string value;
+
+ int line;
+
+ /**
+ * This flag is false when nobody has queried the value of
+ * this option yet.
+ */
+ bool used;
+
+ explicit config_param(int _line=-1)
+ :next(nullptr), line(_line), used(false) {}
+
+ gcc_nonnull_all
+ config_param(const char *_value, int _line=-1);
+
+ config_param(const config_param &) = delete;
+
+ ~config_param();
+
+ config_param &operator=(const config_param &) = delete;
+
+ /**
+ * Determine if this is a "null" instance, i.e. an empty
+ * object that was synthesized and not loaded from a
+ * configuration file.
+ */
+ bool IsNull() const {
+ return line < 0;
+ }
+};
+
+#endif
diff --git a/src/db/Configured.cxx b/src/db/Configured.cxx
index 625300d75..c71195769 100644
--- a/src/db/Configured.cxx
+++ b/src/db/Configured.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,8 @@
#include "Configured.hxx"
#include "DatabaseGlue.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
+#include "config/Block.hxx"
#include "config/ConfigError.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/StandardDirectory.hxx"
@@ -32,8 +33,8 @@ Database *
CreateConfiguredDatabase(EventLoop &loop, DatabaseListener &listener,
Error &error)
{
- const struct config_param *param = config_get_param(CONF_DATABASE);
- const struct config_param *path = config_get_param(CONF_DB_FILE);
+ const auto *param = config_get_block(ConfigBlockOption::DATABASE);
+ const auto *path = config_get_param(ConfigOption::DB_FILE);
if (param != nullptr && path != nullptr) {
error.Format(config_domain,
@@ -42,10 +43,10 @@ CreateConfiguredDatabase(EventLoop &loop, DatabaseListener &listener,
return nullptr;
}
- struct config_param *allocated = nullptr;
+ ConfigBlock *allocated = nullptr;
if (param == nullptr && path != nullptr) {
- allocated = new config_param("database", path->line);
+ allocated = new ConfigBlock(path->line);
allocated->AddBlockParam("path", path->value.c_str(),
path->line);
param = allocated;
@@ -58,10 +59,14 @@ CreateConfiguredDatabase(EventLoop &loop, DatabaseListener &listener,
if (cache_dir.IsNull())
return nullptr;
- const auto db_file = AllocatedPath::Build(cache_dir, "mpd.db");
+ const auto db_file = AllocatedPath::Build(cache_dir,
+ PATH_LITERAL("mpd.db"));
+ const auto db_file_utf8 = db_file.ToUTF8();
+ if (db_file_utf8.empty())
+ return nullptr;
- allocated = new config_param("database");
- allocated->AddBlockParam("path", db_file.c_str(), -1);
+ allocated = new ConfigBlock();
+ allocated->AddBlockParam("path", db_file_utf8.c_str(), -1);
param = allocated;
}
diff --git a/src/db/Configured.hxx b/src/db/Configured.hxx
index 5d25b701c..aed2c2bf4 100644
--- a/src/db/Configured.hxx
+++ b/src/db/Configured.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Count.cxx b/src/db/Count.cxx
index e5e244a6a..f97f2f288 100644
--- a/src/db/Count.cxx
+++ b/src/db/Count.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,8 @@
#include "Count.hxx"
#include "Selection.hxx"
#include "Interface.hxx"
-#include "client/Client.hxx"
+#include "Partition.hxx"
+#include "client/Response.hxx"
#include "LightSong.hxx"
#include "tag/Tag.hxx"
@@ -40,26 +41,24 @@ class TagCountMap : public std::map<std::string, SearchStats> {
};
static void
-PrintSearchStats(Client &client, const SearchStats &stats)
+PrintSearchStats(Response &r, const SearchStats &stats)
{
unsigned total_duration_s =
std::chrono::duration_cast<std::chrono::seconds>(stats.total_duration).count();
- client_printf(client,
- "songs: %u\n"
- "playtime: %u\n",
- stats.n_songs, total_duration_s);
+ r.Format("songs: %u\n"
+ "playtime: %u\n",
+ stats.n_songs, total_duration_s);
}
static void
-Print(Client &client, TagType group, const TagCountMap &m)
+Print(Response &r, TagType group, const TagCountMap &m)
{
assert(unsigned(group) < TAG_NUM_OF_ITEM_TYPES);
for (const auto &i : m) {
- client_printf(client, "%s: %s\n",
- tag_item_names[group], i.first.c_str());
- PrintSearchStats(client, i.second);
+ r.Format("%s: %s\n", tag_item_names[group], i.first.c_str());
+ PrintSearchStats(r, i.second);
}
}
@@ -109,12 +108,12 @@ GroupCountVisitor(TagCountMap &map, TagType group, const LightSong &song)
}
bool
-PrintSongCount(Client &client, const char *name,
+PrintSongCount(Response &r, const Partition &partition, const char *name,
const SongFilter *filter,
TagType group,
Error &error)
{
- const Database *db = client.GetDatabase(error);
+ const Database *db = partition.GetDatabase(error);
if (db == nullptr)
return false;
@@ -131,7 +130,7 @@ PrintSongCount(Client &client, const char *name,
if (!db->Visit(selection, f, error))
return false;
- PrintSearchStats(client, stats);
+ PrintSearchStats(r, stats);
} else {
/* group by the specified tag: store counts in a
std::map */
@@ -144,7 +143,7 @@ PrintSongCount(Client &client, const char *name,
if (!db->Visit(selection, f, error))
return false;
- Print(client, group, map);
+ Print(r, group, map);
}
return true;
diff --git a/src/db/Count.hxx b/src/db/Count.hxx
index d22a3210d..4fc26aa7a 100644
--- a/src/db/Count.hxx
+++ b/src/db/Count.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,13 +25,14 @@
#include <stdint.h>
enum TagType : uint8_t;
-class Client;
+struct Partition;
+class Response;
class SongFilter;
class Error;
-gcc_nonnull(2)
+gcc_nonnull(3)
bool
-PrintSongCount(Client &client, const char *name,
+PrintSongCount(Response &r, const Partition &partition, const char *name,
const SongFilter *filter,
TagType group,
Error &error);
diff --git a/src/db/DatabaseError.cxx b/src/db/DatabaseError.cxx
index e0cbdd6a3..cf1993de2 100644
--- a/src/db/DatabaseError.cxx
+++ b/src/db/DatabaseError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseError.hxx b/src/db/DatabaseError.hxx
index c71bbdfff..542548c73 100644
--- a/src/db/DatabaseError.hxx
+++ b/src/db/DatabaseError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseGlue.cxx b/src/db/DatabaseGlue.cxx
index ade5c95f3..193b672e9 100644
--- a/src/db/DatabaseGlue.cxx
+++ b/src/db/DatabaseGlue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,17 +22,17 @@
#include "Registry.hxx"
#include "DatabaseError.hxx"
#include "util/Error.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "DatabasePlugin.hxx"
#include <string.h>
Database *
DatabaseGlobalInit(EventLoop &loop, DatabaseListener &listener,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
const char *plugin_name =
- param.GetBlockValue("plugin", "simple");
+ block.GetBlockValue("plugin", "simple");
const DatabasePlugin *plugin = GetDatabasePluginByName(plugin_name);
if (plugin == nullptr) {
@@ -41,5 +41,5 @@ DatabaseGlobalInit(EventLoop &loop, DatabaseListener &listener,
return nullptr;
}
- return plugin->create(loop, listener, param, error);
+ return plugin->create(loop, listener, block, error);
}
diff --git a/src/db/DatabaseGlue.hxx b/src/db/DatabaseGlue.hxx
index 70b50def3..95401d54a 100644
--- a/src/db/DatabaseGlue.hxx
+++ b/src/db/DatabaseGlue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
#include "Compiler.h"
-struct config_param;
+struct ConfigBlock;
class EventLoop;
class DatabaseListener;
class Database;
@@ -31,10 +31,10 @@ class Error;
/**
* Initialize the database library.
*
- * @param param the database configuration block
+ * @param block the database configuration block
*/
Database *
DatabaseGlobalInit(EventLoop &loop, DatabaseListener &listener,
- const config_param &param, Error &error);
+ const ConfigBlock &block, Error &error);
#endif
diff --git a/src/db/DatabaseListener.hxx b/src/db/DatabaseListener.hxx
index 8b410c2f5..5af3bff90 100644
--- a/src/db/DatabaseListener.hxx
+++ b/src/db/DatabaseListener.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseLock.cxx b/src/db/DatabaseLock.cxx
index c0b5e4844..ab4628722 100644
--- a/src/db/DatabaseLock.cxx
+++ b/src/db/DatabaseLock.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseLock.hxx b/src/db/DatabaseLock.hxx
index 9d0b0c152..786c97899 100644
--- a/src/db/DatabaseLock.hxx
+++ b/src/db/DatabaseLock.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabasePlaylist.cxx b/src/db/DatabasePlaylist.cxx
index f1cfdc874..d1e042c6a 100644
--- a/src/db/DatabasePlaylist.cxx
+++ b/src/db/DatabasePlaylist.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabasePlaylist.hxx b/src/db/DatabasePlaylist.hxx
index 9dc3526bb..333a36dc2 100644
--- a/src/db/DatabasePlaylist.hxx
+++ b/src/db/DatabasePlaylist.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabasePlugin.hxx b/src/db/DatabasePlugin.hxx
index 831101786..116aa59d2 100644
--- a/src/db/DatabasePlugin.hxx
+++ b/src/db/DatabasePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#ifndef MPD_DATABASE_PLUGIN_HXX
#define MPD_DATABASE_PLUGIN_HXX
-struct config_param;
+struct ConfigBlock;
class Error;
class EventLoop;
class DatabaseListener;
@@ -47,7 +47,7 @@ struct DatabasePlugin {
* Allocates and configures a database.
*/
Database *(*create)(EventLoop &loop, DatabaseListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
constexpr bool RequireStorage() const {
diff --git a/src/db/DatabasePrint.cxx b/src/db/DatabasePrint.cxx
index 498aedf97..e5e7a84f3 100644
--- a/src/db/DatabasePrint.cxx
+++ b/src/db/DatabasePrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,8 @@
#include "SongPrint.hxx"
#include "TimePrint.hxx"
#include "client/Client.hxx"
+#include "client/Response.hxx"
+#include "Partition.hxx"
#include "tag/Tag.hxx"
#include "LightSong.hxx"
#include "LightDirectory.hxx"
@@ -42,162 +44,190 @@ ApplyBaseFlag(const char *uri, bool base)
}
static void
-PrintDirectoryURI(Client &client, bool base, const LightDirectory &directory)
+PrintDirectoryURI(Response &r, bool base, const LightDirectory &directory)
{
- client_printf(client, "directory: %s\n",
- ApplyBaseFlag(directory.GetPath(), base));
+ r.Format("directory: %s\n",
+ ApplyBaseFlag(directory.GetPath(), base));
}
static bool
-PrintDirectoryBrief(Client &client, bool base, const LightDirectory &directory)
+PrintDirectoryBrief(Response &r, bool base, const LightDirectory &directory)
{
if (!directory.IsRoot())
- PrintDirectoryURI(client, base, directory);
+ PrintDirectoryURI(r, base, directory);
return true;
}
static bool
-PrintDirectoryFull(Client &client, bool base, const LightDirectory &directory)
+PrintDirectoryFull(Response &r, bool base, const LightDirectory &directory)
{
if (!directory.IsRoot()) {
- PrintDirectoryURI(client, base, directory);
+ PrintDirectoryURI(r, base, directory);
if (directory.mtime > 0)
- time_print(client, "Last-Modified", directory.mtime);
+ time_print(r, "Last-Modified", directory.mtime);
}
return true;
}
static void
-print_playlist_in_directory(Client &client, bool base,
+print_playlist_in_directory(Response &r, bool base,
const char *directory,
const char *name_utf8)
{
if (base || directory == nullptr)
- client_printf(client, "playlist: %s\n",
- ApplyBaseFlag(name_utf8, base));
+ r.Format("playlist: %s\n",
+ ApplyBaseFlag(name_utf8, base));
else
- client_printf(client, "playlist: %s/%s\n",
- directory, name_utf8);
+ r.Format("playlist: %s/%s\n",
+ directory, name_utf8);
}
static void
-print_playlist_in_directory(Client &client, bool base,
+print_playlist_in_directory(Response &r, bool base,
const LightDirectory *directory,
const char *name_utf8)
{
if (base || directory == nullptr || directory->IsRoot())
- client_printf(client, "playlist: %s\n", name_utf8);
+ r.Format("playlist: %s\n", name_utf8);
else
- client_printf(client, "playlist: %s/%s\n",
- directory->GetPath(), name_utf8);
+ r.Format("playlist: %s/%s\n",
+ directory->GetPath(), name_utf8);
}
static bool
-PrintSongBrief(Client &client, bool base, const LightSong &song)
+PrintSongBrief(Response &r, Partition &partition,
+ bool base, const LightSong &song)
{
- song_print_uri(client, song, base);
+ song_print_uri(r, partition, song, base);
if (song.tag->has_playlist)
/* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, base,
+ print_playlist_in_directory(r, base,
song.directory, song.uri);
return true;
}
static bool
-PrintSongFull(Client &client, bool base, const LightSong &song)
+PrintSongFull(Response &r, Partition &partition,
+ bool base, const LightSong &song)
{
- song_print_info(client, song, base);
+ song_print_info(r, partition, song, base);
if (song.tag->has_playlist)
/* this song file has an embedded CUE sheet */
- print_playlist_in_directory(client, base,
+ print_playlist_in_directory(r, base,
song.directory, song.uri);
return true;
}
static bool
-PrintPlaylistBrief(Client &client, bool base,
+PrintPlaylistBrief(Response &r, bool base,
const PlaylistInfo &playlist,
const LightDirectory &directory)
{
- print_playlist_in_directory(client, base,
+ print_playlist_in_directory(r, base,
&directory, playlist.name.c_str());
return true;
}
static bool
-PrintPlaylistFull(Client &client, bool base,
+PrintPlaylistFull(Response &r, bool base,
const PlaylistInfo &playlist,
const LightDirectory &directory)
{
- print_playlist_in_directory(client, base,
+ print_playlist_in_directory(r, base,
&directory, playlist.name.c_str());
if (playlist.mtime > 0)
- time_print(client, "Last-Modified", playlist.mtime);
+ time_print(r, "Last-Modified", playlist.mtime);
return true;
}
bool
-db_selection_print(Client &client, const DatabaseSelection &selection,
- bool full, bool base, Error &error)
+db_selection_print(Response &r, Partition &partition,
+ const DatabaseSelection &selection,
+ bool full, bool base,
+ unsigned window_start, unsigned window_end,
+ Error &error)
{
- const Database *db = client.GetDatabase(error);
+ const Database *db = partition.GetDatabase(error);
if (db == nullptr)
return false;
+ unsigned i = 0;
+
using namespace std::placeholders;
const auto d = selection.filter == nullptr
? std::bind(full ? PrintDirectoryFull : PrintDirectoryBrief,
- std::ref(client), base, _1)
+ std::ref(r), base, _1)
: VisitDirectory();
- const auto s = std::bind(full ? PrintSongFull : PrintSongBrief,
- std::ref(client), base, _1);
+ VisitSong s = std::bind(full ? PrintSongFull : PrintSongBrief,
+ std::ref(r), std::ref(partition), base, _1);
const auto p = selection.filter == nullptr
? std::bind(full ? PrintPlaylistFull : PrintPlaylistBrief,
- std::ref(client), base, _1, _2)
+ std::ref(r), base, _1, _2)
: VisitPlaylist();
+ if (window_start > 0 ||
+ window_end < (unsigned)std::numeric_limits<int>::max())
+ s = [s, window_start, window_end, &i](const LightSong &song,
+ Error &error2){
+ const bool in_window = i >= window_start && i < window_end;
+ ++i;
+ return !in_window || s(song, error2);
+ };
+
return db->Visit(selection, d, s, p, error);
}
+bool
+db_selection_print(Response &r, Partition &partition,
+ const DatabaseSelection &selection,
+ bool full, bool base,
+ Error &error)
+{
+ return db_selection_print(r, partition, selection, full, base,
+ 0, std::numeric_limits<int>::max(),
+ error);
+}
+
static bool
-PrintSongURIVisitor(Client &client, const LightSong &song)
+PrintSongURIVisitor(Response &r, Partition &partition, const LightSong &song)
{
- song_print_uri(client, song);
+ song_print_uri(r, partition, song);
return true;
}
static bool
-PrintUniqueTag(Client &client, TagType tag_type,
+PrintUniqueTag(Response &r, TagType tag_type,
const Tag &tag)
{
const char *value = tag.GetValue(tag_type);
assert(value != nullptr);
- client_printf(client, "%s: %s\n", tag_item_names[tag_type], value);
+ r.Format("%s: %s\n", tag_item_names[tag_type], value);
for (const auto &item : tag)
if (item.type != tag_type)
- client_printf(client, "%s: %s\n",
- tag_item_names[item.type], item.value);
+ r.Format("%s: %s\n",
+ tag_item_names[item.type], item.value);
return true;
}
bool
-PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask,
+PrintUniqueTags(Response &r, Partition &partition,
+ unsigned type, tag_mask_t group_mask,
const SongFilter *filter,
Error &error)
{
- const Database *db = client.GetDatabase(error);
+ const Database *db = partition.GetDatabase(error);
if (db == nullptr)
return false;
@@ -206,13 +236,13 @@ PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask,
if (type == LOCATE_TAG_FILE_TYPE) {
using namespace std::placeholders;
const auto f = std::bind(PrintSongURIVisitor,
- std::ref(client), _1);
+ std::ref(r), std::ref(partition), _1);
return db->Visit(selection, f, error);
} else {
assert(type < TAG_NUM_OF_ITEM_TYPES);
using namespace std::placeholders;
- const auto f = std::bind(PrintUniqueTag, std::ref(client),
+ const auto f = std::bind(PrintUniqueTag, std::ref(r),
(TagType)type, _1);
return db->VisitUniqueTags(selection, (TagType)type,
group_mask,
diff --git a/src/db/DatabasePrint.hxx b/src/db/DatabasePrint.hxx
index 2ab5e703d..d48dabaa2 100644
--- a/src/db/DatabasePrint.hxx
+++ b/src/db/DatabasePrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,13 +20,14 @@
#ifndef MPD_DB_PRINT_H
#define MPD_DB_PRINT_H
+#include "tag/Mask.hxx"
#include "Compiler.h"
-#include <stdint.h>
-
class SongFilter;
struct DatabaseSelection;
+struct Partition;
class Client;
+class Response;
class Error;
/**
@@ -34,11 +35,20 @@ class Error;
* @param base print only base name of songs/directories?
*/
bool
-db_selection_print(Client &client, const DatabaseSelection &selection,
+db_selection_print(Response &r, Partition &partition,
+ const DatabaseSelection &selection,
bool full, bool base, Error &error);
bool
-PrintUniqueTags(Client &client, unsigned type, uint32_t group_mask,
+db_selection_print(Response &r, Partition &partition,
+ const DatabaseSelection &selection,
+ bool full, bool base,
+ unsigned window_start, unsigned window_end,
+ Error &error);
+
+bool
+PrintUniqueTags(Response &r, Partition &partition,
+ unsigned type, tag_mask_t group_mask,
const SongFilter *filter,
Error &error);
diff --git a/src/db/DatabaseQueue.cxx b/src/db/DatabaseQueue.cxx
index 490678188..c605e0878 100644
--- a/src/db/DatabaseQueue.cxx
+++ b/src/db/DatabaseQueue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseQueue.hxx b/src/db/DatabaseQueue.hxx
index e653f973c..e9ec7bde2 100644
--- a/src/db/DatabaseQueue.hxx
+++ b/src/db/DatabaseQueue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseSong.cxx b/src/db/DatabaseSong.cxx
index dd27aa8b3..d2475841b 100644
--- a/src/db/DatabaseSong.cxx
+++ b/src/db/DatabaseSong.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/DatabaseSong.hxx b/src/db/DatabaseSong.hxx
index 4daaf4047..c83f9562a 100644
--- a/src/db/DatabaseSong.hxx
+++ b/src/db/DatabaseSong.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Helpers.cxx b/src/db/Helpers.cxx
index add4bb98e..d4c29f405 100644
--- a/src/db/Helpers.cxx
+++ b/src/db/Helpers.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -46,7 +46,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
for (const auto &item : tag) {
switch (item.type) {
case TAG_ARTIST:
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
artists.emplace(item.value);
#else
artists.insert(item.value);
@@ -54,7 +54,7 @@ StatsVisitTag(DatabaseStats &stats, StringSet &artists, StringSet &albums,
break;
case TAG_ALBUM:
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
albums.emplace(item.value);
#else
albums.insert(item.value);
diff --git a/src/db/Helpers.hxx b/src/db/Helpers.hxx
index 651bac0e0..5fcab2d7f 100644
--- a/src/db/Helpers.hxx
+++ b/src/db/Helpers.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Interface.hxx b/src/db/Interface.hxx
index 152928c79..7b43efe24 100644
--- a/src/db/Interface.hxx
+++ b/src/db/Interface.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,10 +22,10 @@
#include "Visitor.hxx"
#include "tag/TagType.h"
+#include "tag/Mask.hxx"
#include "Compiler.h"
#include <time.h>
-#include <stdint.h>
struct DatabasePlugin;
struct DatabaseStats;
@@ -107,7 +107,7 @@ public:
* Visit all unique tag values.
*/
virtual bool VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const = 0;
diff --git a/src/db/LightDirectory.hxx b/src/db/LightDirectory.hxx
index d134151a4..ad5d34590 100644
--- a/src/db/LightDirectory.hxx
+++ b/src/db/LightDirectory.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/LightSong.cxx b/src/db/LightSong.cxx
index 5cdebc133..9202b1b30 100644
--- a/src/db/LightSong.cxx
+++ b/src/db/LightSong.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/LightSong.hxx b/src/db/LightSong.hxx
index bbd449fbe..3c289cce0 100644
--- a/src/db/LightSong.hxx
+++ b/src/db/LightSong.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/PlaylistInfo.hxx b/src/db/PlaylistInfo.hxx
index baa6cc361..f319cbcb6 100644
--- a/src/db/PlaylistInfo.hxx
+++ b/src/db/PlaylistInfo.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/PlaylistVector.cxx b/src/db/PlaylistVector.cxx
index 82a3519d9..1fffbc375 100644
--- a/src/db/PlaylistVector.cxx
+++ b/src/db/PlaylistVector.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/PlaylistVector.hxx b/src/db/PlaylistVector.hxx
index accd4fd42..7cb192dc0 100644
--- a/src/db/PlaylistVector.hxx
+++ b/src/db/PlaylistVector.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Registry.cxx b/src/db/Registry.cxx
index 5681a9b82..dc7807774 100644
--- a/src/db/Registry.cxx
+++ b/src/db/Registry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,10 @@
const DatabasePlugin *const database_plugins[] = {
&simple_db_plugin,
-#ifdef HAVE_LIBMPDCLIENT
+#ifdef ENABLE_LIBMPDCLIENT
&proxy_db_plugin,
#endif
-#ifdef HAVE_LIBUPNP
+#ifdef ENABLE_UPNP
&upnp_db_plugin,
#endif
nullptr
diff --git a/src/db/Registry.hxx b/src/db/Registry.hxx
index 050842e21..9f672f25e 100644
--- a/src/db/Registry.hxx
+++ b/src/db/Registry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Selection.cxx b/src/db/Selection.cxx
index a886916cb..4c941823a 100644
--- a/src/db/Selection.cxx
+++ b/src/db/Selection.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,8 +26,11 @@ DatabaseSelection::DatabaseSelection(const char *_uri, bool _recursive,
{
/* optimization: if the caller didn't specify a base URI, pick
the one from SongFilter */
- if (uri.empty() && filter != nullptr)
- uri = filter->GetBase();
+ if (uri.empty() && filter != nullptr) {
+ auto base = filter->GetBase();
+ if (base != nullptr)
+ uri = base;
+ }
}
bool
diff --git a/src/db/Selection.hxx b/src/db/Selection.hxx
index 9802603fc..7216f5017 100644
--- a/src/db/Selection.hxx
+++ b/src/db/Selection.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Stats.hxx b/src/db/Stats.hxx
index 131a5dc47..c16dcc9c6 100644
--- a/src/db/Stats.hxx
+++ b/src/db/Stats.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/UniqueTags.cxx b/src/db/UniqueTags.cxx
index 589dc936d..a0c85cb85 100644
--- a/src/db/UniqueTags.cxx
+++ b/src/db/UniqueTags.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#include <assert.h>
static bool
-CollectTags(TagSet &set, TagType tag_type, uint32_t group_mask,
+CollectTags(TagSet &set, TagType tag_type, tag_mask_t group_mask,
const LightSong &song)
{
assert(song.tag != nullptr);
@@ -39,7 +39,7 @@ CollectTags(TagSet &set, TagType tag_type, uint32_t group_mask,
bool
VisitUniqueTags(const Database &db, const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error)
{
diff --git a/src/db/UniqueTags.hxx b/src/db/UniqueTags.hxx
index 61004fc56..b241970f9 100644
--- a/src/db/UniqueTags.hxx
+++ b/src/db/UniqueTags.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,7 @@
#include "Visitor.hxx"
#include "tag/TagType.h"
-
-#include <stdint.h>
+#include "tag/Mask.hxx"
class Error;
class Database;
@@ -31,7 +30,7 @@ struct DatabaseSelection;
bool
VisitUniqueTags(const Database &db, const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error);
diff --git a/src/db/Uri.hxx b/src/db/Uri.hxx
index 04960ba80..12acabe4a 100644
--- a/src/db/Uri.hxx
+++ b/src/db/Uri.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/Visitor.hxx b/src/db/Visitor.hxx
index c524f1722..1f6008117 100644
--- a/src/db/Visitor.hxx
+++ b/src/db/Visitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/LazyDatabase.cxx b/src/db/plugins/LazyDatabase.cxx
index bc52395c5..9d57301a9 100644
--- a/src/db/plugins/LazyDatabase.cxx
+++ b/src/db/plugins/LazyDatabase.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -85,7 +85,7 @@ LazyDatabase::Visit(const DatabaseSelection &selection,
bool
LazyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const
{
diff --git a/src/db/plugins/LazyDatabase.hxx b/src/db/plugins/LazyDatabase.hxx
index 38b3fdc2a..6955aefe8 100644
--- a/src/db/plugins/LazyDatabase.hxx
+++ b/src/db/plugins/LazyDatabase.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@ public:
Error &error) const override;
virtual bool VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const override;
diff --git a/src/db/plugins/ProxyDatabasePlugin.cxx b/src/db/plugins/ProxyDatabasePlugin.cxx
index 5fd224bb5..8beb2fb55 100644
--- a/src/db/plugins/ProxyDatabasePlugin.cxx
+++ b/src/db/plugins/ProxyDatabasePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
#include "db/Stats.hxx"
#include "SongFilter.hxx"
#include "Compiler.h"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "tag/TagBuilder.hxx"
#include "tag/Tag.hxx"
#include "util/Error.hxx"
@@ -71,6 +71,7 @@ class ProxyDatabase final : public Database, SocketMonitor, IdleMonitor {
std::string host;
unsigned port;
+ bool keepalive;
struct mpd_connection *connection;
@@ -96,7 +97,7 @@ public:
listener(_listener) {}
static Database *Create(EventLoop &loop, DatabaseListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
virtual bool Open(Error &error) override;
@@ -112,7 +113,7 @@ public:
Error &error) const override;
virtual bool VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const override;
@@ -128,7 +129,7 @@ public:
}
private:
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
bool Connect(Error &error);
bool CheckConnection(Error &error);
@@ -262,18 +263,18 @@ SendConstraints(mpd_connection *connection, const SongFilter::Item &item)
return mpd_search_add_base_constraint(connection,
MPD_OPERATOR_DEFAULT,
- item.GetValue().c_str());
+ item.GetValue());
#endif
case LOCATE_TAG_FILE_TYPE:
return mpd_search_add_uri_constraint(connection,
MPD_OPERATOR_DEFAULT,
- item.GetValue().c_str());
+ item.GetValue());
case LOCATE_TAG_ANY_TYPE:
return mpd_search_add_any_tag_constraint(connection,
MPD_OPERATOR_DEFAULT,
- item.GetValue().c_str());
+ item.GetValue());
default:
tag = Convert(TagType(item.GetTag()));
@@ -283,7 +284,7 @@ SendConstraints(mpd_connection *connection, const SongFilter::Item &item)
return mpd_search_add_tag_constraint(connection,
MPD_OPERATOR_DEFAULT,
tag,
- item.GetValue().c_str());
+ item.GetValue());
}
}
@@ -320,10 +321,10 @@ SendConstraints(mpd_connection *connection, const DatabaseSelection &selection)
Database *
ProxyDatabase::Create(EventLoop &loop, DatabaseListener &listener,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
ProxyDatabase *db = new ProxyDatabase(loop, listener);
- if (!db->Configure(param, error)) {
+ if (!db->Configure(block, error)) {
delete db;
db = nullptr;
}
@@ -332,10 +333,11 @@ ProxyDatabase::Create(EventLoop &loop, DatabaseListener &listener,
}
bool
-ProxyDatabase::Configure(const config_param &param, gcc_unused Error &error)
+ProxyDatabase::Configure(const ConfigBlock &block, gcc_unused Error &error)
{
- host = param.GetBlockValue("host", "");
- port = param.GetBlockValue("port", 0u);
+ host = block.GetBlockValue("host", "");
+ port = block.GetBlockValue("port", 0u);
+ keepalive = block.GetBlockValue("keepalive", false);
return true;
}
@@ -376,6 +378,10 @@ ProxyDatabase::Connect(Error &error)
return false;
}
+#if LIBMPDCLIENT_CHECK_VERSION(2, 10, 0)
+ mpd_connection_set_keepalive(connection, keepalive);
+#endif
+
idle_received = unsigned(-1);
is_idle = false;
@@ -751,7 +757,7 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
bool
ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
TagType tag_type,
- gcc_unused uint32_t group_mask,
+ gcc_unused tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const
{
diff --git a/src/db/plugins/ProxyDatabasePlugin.hxx b/src/db/plugins/ProxyDatabasePlugin.hxx
index 699d374b5..590e5f5d2 100644
--- a/src/db/plugins/ProxyDatabasePlugin.hxx
+++ b/src/db/plugins/ProxyDatabasePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/DatabaseSave.cxx b/src/db/plugins/simple/DatabaseSave.cxx
index c766843b6..d2953b048 100644
--- a/src/db/plugins/simple/DatabaseSave.cxx
+++ b/src/db/plugins/simple/DatabaseSave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#include "fs/io/BufferedOutputStream.hxx"
#include "fs/io/TextFile.hxx"
#include "tag/Tag.hxx"
-#include "tag/TagSettings.h"
+#include "tag/Settings.hxx"
#include "fs/Charset.hxx"
#include "util/StringUtil.hxx"
#include "util/Error.hxx"
@@ -58,7 +58,7 @@ db_save_internal(BufferedOutputStream &os, const Directory &music_root)
os.Format("%s%s\n", DIRECTORY_FS_CHARSET, GetFSCharset());
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
- if (!ignore_tag_items[i])
+ if (IsTagEnabled(i))
os.Format(DB_TAG_PREFIX "%s\n", tag_item_names[i]);
os.Format("%s\n", DIRECTORY_INFO_END);
@@ -142,7 +142,7 @@ db_load_internal(TextFile &file, Directory &music_root, Error &error)
}
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) {
- if (!ignore_tag_items[i] && !tags[i]) {
+ if (IsTagEnabled(i) && !tags[i]) {
error.Set(db_domain,
"Tag list mismatch, "
"discarding database file");
diff --git a/src/db/plugins/simple/DatabaseSave.hxx b/src/db/plugins/simple/DatabaseSave.hxx
index bb7f57115..5a8a60a92 100644
--- a/src/db/plugins/simple/DatabaseSave.hxx
+++ b/src/db/plugins/simple/DatabaseSave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/Directory.cxx b/src/db/plugins/simple/Directory.cxx
index 218652b03..0c2b19efb 100644
--- a/src/db/plugins/simple/Directory.cxx
+++ b/src/db/plugins/simple/Directory.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -31,6 +31,7 @@
#include "lib/icu/Collate.hxx"
#include "fs/Traits.hxx"
#include "util/Alloc.hxx"
+#include "util/DeleteDisposer.hxx"
#include "util/Error.hxx"
#include <assert.h>
@@ -51,7 +52,7 @@ Directory::~Directory()
delete mounted_database;
songs.clear_and_dispose(Song::Disposer());
- children.clear_and_dispose(Disposer());
+ children.clear_and_dispose(DeleteDisposer());
}
void
@@ -61,7 +62,7 @@ Directory::Delete()
assert(parent != nullptr);
parent->children.erase_and_dispose(parent->children.iterator_to(*this),
- Disposer());
+ DeleteDisposer());
}
const char *
@@ -110,7 +111,8 @@ Directory::PruneEmpty()
child->PruneEmpty();
if (child->IsEmpty())
- child = children.erase_and_dispose(child, Disposer());
+ child = children.erase_and_dispose(child,
+ DeleteDisposer());
else
++child;
}
diff --git a/src/db/plugins/simple/Directory.hxx b/src/db/plugins/simple/Directory.hxx
index acef62143..bad4647a0 100644
--- a/src/db/plugins/simple/Directory.hxx
+++ b/src/db/plugins/simple/Directory.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -53,12 +53,6 @@ struct Directory {
typedef boost::intrusive::link_mode<link_mode> LinkMode;
typedef boost::intrusive::list_member_hook<LinkMode> Hook;
- struct Disposer {
- void operator()(Directory *directory) const {
- delete directory;
- }
- };
-
/**
* Pointers to the siblings of this directory within the
* parent directory. It is unused (undefined) in the root
diff --git a/src/db/plugins/simple/DirectorySave.cxx b/src/db/plugins/simple/DirectorySave.cxx
index e1650cbe8..5a7eb6da6 100644
--- a/src/db/plugins/simple/DirectorySave.cxx
+++ b/src/db/plugins/simple/DirectorySave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/DirectorySave.hxx b/src/db/plugins/simple/DirectorySave.hxx
index f464f9946..3948db02b 100644
--- a/src/db/plugins/simple/DirectorySave.hxx
+++ b/src/db/plugins/simple/DirectorySave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/Mount.cxx b/src/db/plugins/simple/Mount.cxx
index 96c7bbb5c..8898a6e9c 100644
--- a/src/db/plugins/simple/Mount.cxx
+++ b/src/db/plugins/simple/Mount.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/Mount.hxx b/src/db/plugins/simple/Mount.hxx
index a4690114c..ece644b8a 100644
--- a/src/db/plugins/simple/Mount.hxx
+++ b/src/db/plugins/simple/Mount.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/PrefixedLightSong.hxx b/src/db/plugins/simple/PrefixedLightSong.hxx
index 3664de001..16da747e3 100644
--- a/src/db/plugins/simple/PrefixedLightSong.hxx
+++ b/src/db/plugins/simple/PrefixedLightSong.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.cxx b/src/db/plugins/simple/SimpleDatabasePlugin.cxx
index d6ad5e91f..1e9817417 100644
--- a/src/db/plugins/simple/SimpleDatabasePlugin.cxx
+++ b/src/db/plugins/simple/SimpleDatabasePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,14 +34,15 @@
#include "fs/io/TextFile.hxx"
#include "fs/io/BufferedOutputStream.hxx"
#include "fs/io/FileOutputStream.hxx"
-#include "config/ConfigData.hxx"
+#include "fs/FileInfo.hxx"
+#include "config/Block.hxx"
#include "fs/FileSystem.hxx"
#include "util/CharUtil.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
#include "fs/io/GzipOutputStream.hxx"
#endif
@@ -52,21 +53,21 @@ static constexpr Domain simple_db_domain("simple_db");
inline SimpleDatabase::SimpleDatabase()
:Database(simple_db_plugin),
path(AllocatedPath::Null()),
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
compress(true),
#endif
cache_path(AllocatedPath::Null()),
prefixed_light_song(nullptr) {}
inline SimpleDatabase::SimpleDatabase(AllocatedPath &&_path,
-#ifndef HAVE_ZLIB
+#ifndef ENABLE_ZLIB
gcc_unused
#endif
bool _compress)
:Database(simple_db_plugin),
path(std::move(_path)),
path_utf8(path.ToUTF8()),
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
compress(_compress),
#endif
cache_path(AllocatedPath::Null()),
@@ -76,10 +77,10 @@ inline SimpleDatabase::SimpleDatabase(AllocatedPath &&_path,
Database *
SimpleDatabase::Create(gcc_unused EventLoop &loop,
gcc_unused DatabaseListener &listener,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
SimpleDatabase *db = new SimpleDatabase();
- if (!db->Configure(param, error)) {
+ if (!db->Configure(block, error)) {
delete db;
db = nullptr;
}
@@ -88,9 +89,9 @@ SimpleDatabase::Create(gcc_unused EventLoop &loop,
}
bool
-SimpleDatabase::Configure(const config_param &param, Error &error)
+SimpleDatabase::Configure(const ConfigBlock &block, Error &error)
{
- path = param.GetBlockPath("path", error);
+ path = block.GetBlockPath("path", error);
if (path.IsNull()) {
if (!error.IsDefined())
error.Set(simple_db_domain,
@@ -100,12 +101,12 @@ SimpleDatabase::Configure(const config_param &param, Error &error)
path_utf8 = path.ToUTF8();
- cache_path = param.GetBlockPath("cache_directory", error);
+ cache_path = block.GetBlockPath("cache_directory", error);
if (path.IsNull() && error.IsDefined())
return false;
-#ifdef HAVE_ZLIB
- compress = param.GetBlockValue("compress", compress);
+#ifdef ENABLE_ZLIB
+ compress = block.GetBlockValue("compress", compress);
#endif
return true;
@@ -117,22 +118,20 @@ SimpleDatabase::Check(Error &error) const
assert(!path.IsNull());
/* Check if the file exists */
- if (!CheckAccess(path)) {
+ if (!PathExists(path)) {
/* If the file doesn't exist, we can't check if we can write
* it, so we are going to try to get the directory path, and
* see if we can write a file in that */
const auto dirPath = path.GetDirectoryName();
/* Check that the parent part of the path is a directory */
- struct stat st;
- if (!StatFile(dirPath, st)) {
- error.FormatErrno("Couldn't stat parent directory of db file "
- "\"%s\"",
- path_utf8.c_str());
+ FileInfo fi;
+ if (!GetFileInfo(dirPath, fi, error)) {
+ error.AddPrefix("On parent directory of db file: ");
return false;
}
- if (!S_ISDIR(st.st_mode)) {
+ if (!fi.IsDirectory()) {
error.Format(simple_db_domain,
"Couldn't create db file \"%s\" because the "
"parent path is not a directory",
@@ -154,14 +153,11 @@ SimpleDatabase::Check(Error &error) const
}
/* Path exists, now check if it's a regular file */
- struct stat st;
- if (!StatFile(path, st)) {
- error.FormatErrno("Couldn't stat db file \"%s\"",
- path_utf8.c_str());
+ FileInfo fi;
+ if (!GetFileInfo(path, fi, error))
return false;
- }
- if (!S_ISREG(st.st_mode)) {
+ if (!fi.IsRegular()) {
error.Format(simple_db_domain,
"db file \"%s\" is not a regular file",
path_utf8.c_str());
@@ -193,9 +189,9 @@ SimpleDatabase::Load(Error &error)
if (!db_load_internal(file, *root, error) || !file.Check(error))
return false;
- struct stat st;
- if (StatFile(path, st))
- mtime = st.st_mtime;
+ FileInfo fi;
+ if (GetFileInfo(path, fi))
+ mtime = fi.GetModificationTime();
return true;
}
@@ -352,7 +348,7 @@ SimpleDatabase::Visit(const DatabaseSelection &selection,
bool
SimpleDatabase::VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const
{
@@ -389,7 +385,7 @@ SimpleDatabase::Save(Error &error)
OutputStream *os = &fos;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
GzipOutputStream *gzip = nullptr;
if (compress) {
gzip = new GzipOutputStream(*os, error);
@@ -407,13 +403,13 @@ SimpleDatabase::Save(Error &error)
db_save_internal(bos, *root);
if (!bos.Flush(error)) {
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
delete gzip;
#endif
return false;
}
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
if (gzip != nullptr) {
bool success = gzip->Flush(error);
delete gzip;
@@ -425,9 +421,9 @@ SimpleDatabase::Save(Error &error)
if (!fos.Commit(error))
return false;
- struct stat st;
- if (StatFile(path, st))
- mtime = st.st_mtime;
+ FileInfo fi;
+ if (GetFileInfo(path, fi))
+ mtime = fi.GetModificationTime();
return true;
}
@@ -487,11 +483,15 @@ SimpleDatabase::Mount(const char *local_uri, const char *storage_uri,
std::string name(storage_uri);
std::replace_if(name.begin(), name.end(), IsUnsafeChar, '_');
-#ifndef HAVE_ZLIB
+ const auto name_fs = AllocatedPath::FromUTF8(name.c_str(), error);
+ if (name_fs.IsNull())
+ return false;
+
+#ifndef ENABLE_ZLIB
constexpr bool compress = false;
#endif
auto db = new SimpleDatabase(AllocatedPath::Build(cache_path,
- name.c_str()),
+ name_fs.c_str()),
compress);
if (!db->Open(error)) {
delete db;
diff --git a/src/db/plugins/simple/SimpleDatabasePlugin.hxx b/src/db/plugins/simple/SimpleDatabasePlugin.hxx
index d82225f8c..7a28099d9 100644
--- a/src/db/plugins/simple/SimpleDatabasePlugin.hxx
+++ b/src/db/plugins/simple/SimpleDatabasePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
#include <cassert>
-struct config_param;
+struct ConfigBlock;
struct Directory;
struct DatabasePlugin;
class EventLoop;
@@ -39,7 +39,7 @@ class SimpleDatabase : public Database {
AllocatedPath path;
std::string path_utf8;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
bool compress;
#endif
@@ -73,7 +73,7 @@ class SimpleDatabase : public Database {
public:
static Database *Create(EventLoop &loop, DatabaseListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
gcc_pure
@@ -121,7 +121,7 @@ public:
Error &error) const override;
virtual bool VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const override;
@@ -134,7 +134,7 @@ public:
}
private:
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
gcc_pure
bool Check(Error &error) const;
diff --git a/src/db/plugins/simple/Song.cxx b/src/db/plugins/simple/Song.cxx
index fbfc2ec19..b2515a2d5 100644
--- a/src/db/plugins/simple/Song.cxx
+++ b/src/db/plugins/simple/Song.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/Song.hxx b/src/db/plugins/simple/Song.hxx
index 9f3a4a3ef..c83bbace0 100644
--- a/src/db/plugins/simple/Song.hxx
+++ b/src/db/plugins/simple/Song.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#ifndef MPD_SONG_HXX
#define MPD_SONG_HXX
+#include "check.h"
#include "Chrono.hxx"
#include "tag/Tag.hxx"
#include "Compiler.h"
@@ -109,7 +110,10 @@ struct Song {
void Free();
bool UpdateFile(Storage &storage);
+
+#ifdef ENABLE_ARCHIVE
bool UpdateFileInArchive(const Storage &storage);
+#endif
/**
* Returns the URI of the song in UTF-8 encoding, including its
diff --git a/src/db/plugins/simple/SongSort.cxx b/src/db/plugins/simple/SongSort.cxx
index 4b7144937..70299a2d4 100644
--- a/src/db/plugins/simple/SongSort.cxx
+++ b/src/db/plugins/simple/SongSort.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/simple/SongSort.hxx b/src/db/plugins/simple/SongSort.hxx
index 2a0c4383b..0a75c9fda 100644
--- a/src/db/plugins/simple/SongSort.hxx
+++ b/src/db/plugins/simple/SongSort.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/ContentDirectoryService.cxx b/src/db/plugins/upnp/ContentDirectoryService.cxx
index 88d4bd644..d98559c7b 100644
--- a/src/db/plugins/upnp/ContentDirectoryService.cxx
+++ b/src/db/plugins/upnp/ContentDirectoryService.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/Directory.cxx b/src/db/plugins/upnp/Directory.cxx
index e94a1a997..e7f92432a 100644
--- a/src/db/plugins/upnp/Directory.cxx
+++ b/src/db/plugins/upnp/Directory.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "tag/TagBuilder.hxx"
#include "tag/TagTable.hxx"
#include "util/NumberParser.hxx"
+#include "util/StringView.hxx"
#include <algorithm>
#include <string>
@@ -36,23 +37,13 @@ UPnPDirContent::~UPnPDirContent()
/* this destructor exists here just so it won't get inlined */
}
-gcc_pure gcc_nonnull_all
-static bool
-CompareStringLiteral(const char *literal, const char *value, size_t length)
-{
- return length == strlen(literal) &&
- memcmp(literal, value, length) == 0;
-}
-
gcc_pure
static UPnPDirObject::ItemClass
-ParseItemClass(const char *name, size_t length)
+ParseItemClass(StringView name)
{
- if (CompareStringLiteral("object.item.audioItem.musicTrack",
- name, length))
+ if (name.EqualsLiteral("object.item.audioItem.musicTrack"))
return UPnPDirObject::ItemClass::MUSIC;
- else if (CompareStringLiteral("object.item.playlistItem",
- name, length))
+ else if (name.EqualsLiteral("object.item.playlistItem"))
return UPnPDirObject::ItemClass::PLAYLIST;
else
return UPnPDirObject::ItemClass::UNKNOWN;
@@ -89,18 +80,18 @@ ParseDuration(const char *duration)
* this. Twonky returns directory names (titles) like 'Artist/Album'.
*/
gcc_pure
-static std::string
-titleToPathElt(std::string &&s)
+static std::string &&
+TitleToPathSegment(std::string &&s)
{
std::replace(s.begin(), s.end(), '/', '_');
- return s;
+ return std::move(s);
}
/**
* An XML parser which builds directory contents from DIDL lite input.
*/
class UPnPDirParser final : public CommonExpatParser {
- UPnPDirContent &m_dir;
+ UPnPDirContent &directory;
enum {
NONE,
@@ -120,22 +111,22 @@ class UPnPDirParser final : public CommonExpatParser {
*/
std::string value;
- UPnPDirObject m_tobj;
+ UPnPDirObject object;
TagBuilder tag;
public:
- UPnPDirParser(UPnPDirContent& dir)
- :m_dir(dir),
+ UPnPDirParser(UPnPDirContent &_directory)
+ :directory(_directory),
state(NONE),
tag_type(TAG_NUM_OF_ITEM_TYPES)
{
- m_tobj.clear();
+ object.Clear();
}
protected:
virtual void StartElement(const XML_Char *name, const XML_Char **attrs)
{
- if (m_tobj.type != UPnPDirObject::Type::UNKNOWN &&
+ if (object.type != UPnPDirObject::Type::UNKNOWN &&
tag_type == TAG_NUM_OF_ITEM_TYPES) {
tag_type = tag_table_lookup(upnp_tags, name);
if (tag_type != TAG_NUM_OF_ITEM_TYPES)
@@ -147,31 +138,31 @@ protected:
switch (name[0]) {
case 'c':
if (!strcmp(name, "container")) {
- m_tobj.clear();
- m_tobj.type = UPnPDirObject::Type::CONTAINER;
+ object.Clear();
+ object.type = UPnPDirObject::Type::CONTAINER;
const char *id = GetAttribute(attrs, "id");
if (id != nullptr)
- m_tobj.m_id = id;
+ object.id = id;
const char *pid = GetAttribute(attrs, "parentID");
if (pid != nullptr)
- m_tobj.m_pid = pid;
+ object.parent_id = pid;
}
break;
case 'i':
if (!strcmp(name, "item")) {
- m_tobj.clear();
- m_tobj.type = UPnPDirObject::Type::ITEM;
+ object.Clear();
+ object.type = UPnPDirObject::Type::ITEM;
const char *id = GetAttribute(attrs, "id");
if (id != nullptr)
- m_tobj.m_id = id;
+ object.id = id;
const char *pid = GetAttribute(attrs, "parentID");
if (pid != nullptr)
- m_tobj.m_pid = pid;
+ object.parent_id = pid;
}
break;
@@ -197,25 +188,15 @@ protected:
}
}
- bool checkobjok() {
- if (m_tobj.m_id.empty() || m_tobj.m_pid.empty() ||
- m_tobj.name.empty() ||
- (m_tobj.type == UPnPDirObject::Type::ITEM &&
- m_tobj.item_class == UPnPDirObject::ItemClass::UNKNOWN))
- return false;
-
- return true;
- }
-
virtual void EndElement(const XML_Char *name)
{
if (tag_type != TAG_NUM_OF_ITEM_TYPES) {
- assert(m_tobj.type != UPnPDirObject::Type::UNKNOWN);
+ assert(object.type != UPnPDirObject::Type::UNKNOWN);
tag.AddItem(tag_type, value.c_str());
if (tag_type == TAG_TITLE)
- m_tobj.name = titleToPathElt(std::move(value));
+ object.name = TitleToPathSegment(std::move(value));
value.clear();
tag_type = TAG_NUM_OF_ITEM_TYPES;
@@ -223,9 +204,9 @@ protected:
}
if ((!strcmp(name, "container") || !strcmp(name, "item")) &&
- checkobjok()) {
- tag.Commit(m_tobj.tag);
- m_dir.objects.emplace_back(std::move(m_tobj));
+ object.Check()) {
+ tag.Commit(object.tag);
+ directory.objects.emplace_back(std::move(object));
}
state = NONE;
@@ -234,7 +215,7 @@ protected:
virtual void CharacterData(const XML_Char *s, int len)
{
if (tag_type != TAG_NUM_OF_ITEM_TYPES) {
- assert(m_tobj.type != UPnPDirObject::Type::UNKNOWN);
+ assert(object.type != UPnPDirObject::Type::UNKNOWN);
value.append(s, len);
return;
@@ -245,11 +226,11 @@ protected:
break;
case RES:
- m_tobj.url.assign(s, len);
+ object.url.assign(s, len);
break;
case CLASS:
- m_tobj.item_class = ParseItemClass(s, len);
+ object.item_class = ParseItemClass(StringView(s, len));
break;
}
}
diff --git a/src/db/plugins/upnp/Directory.hxx b/src/db/plugins/upnp/Directory.hxx
index 433979900..639f2bcbe 100644
--- a/src/db/plugins/upnp/Directory.hxx
+++ b/src/db/plugins/upnp/Directory.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/Object.cxx b/src/db/plugins/upnp/Object.cxx
index 703fb0be4..0b5c4be88 100644
--- a/src/db/plugins/upnp/Object.cxx
+++ b/src/db/plugins/upnp/Object.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/Object.hxx b/src/db/plugins/upnp/Object.hxx
index 16a66c774..aced04b27 100644
--- a/src/db/plugins/upnp/Object.hxx
+++ b/src/db/plugins/upnp/Object.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#define MPD_UPNP_OBJECT_HXX
#include "tag/Tag.hxx"
+#include "Compiler.h"
#include <string>
@@ -50,8 +51,16 @@ public:
PLAYLIST,
};
- std::string m_id; // ObjectId
- std::string m_pid; // Parent ObjectId
+ /**
+ * ObjectId
+ */
+ std::string id;
+
+ /**
+ * Parent's ObjectId
+ */
+ std::string parent_id;
+
std::string url;
/**
@@ -71,15 +80,21 @@ public:
UPnPDirObject &operator=(UPnPDirObject &&) = default;
- void clear()
- {
- m_id.clear();
- m_pid.clear();
+ void Clear() {
+ id.clear();
+ parent_id.clear();
url.clear();
type = Type::UNKNOWN;
item_class = ItemClass::UNKNOWN;
tag.Clear();
}
+
+ gcc_pure
+ bool Check() const {
+ return !id.empty() && !parent_id.empty() && !name.empty() &&
+ (type != UPnPDirObject::Type::ITEM ||
+ item_class != UPnPDirObject::ItemClass::UNKNOWN);
+ }
};
#endif /* _UPNPDIRCONTENT_H_X_INCLUDED_ */
diff --git a/src/db/plugins/upnp/Tags.cxx b/src/db/plugins/upnp/Tags.cxx
index fd65df4d0..89d1b53c5 100644
--- a/src/db/plugins/upnp/Tags.cxx
+++ b/src/db/plugins/upnp/Tags.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/Tags.hxx b/src/db/plugins/upnp/Tags.hxx
index ec6d18478..8f85ce4b0 100644
--- a/src/db/plugins/upnp/Tags.hxx
+++ b/src/db/plugins/upnp/Tags.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
index 9970cdcf3..26844a978 100644
--- a/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
+++ b/src/db/plugins/upnp/UpnpDatabasePlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
#include "db/LightDirectory.hxx"
#include "db/LightSong.hxx"
#include "db/Stats.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "tag/TagBuilder.hxx"
#include "tag/TagTable.hxx"
#include "util/Error.hxx"
@@ -78,7 +78,7 @@ public:
UpnpDatabase():Database(upnp_db_plugin) {}
static Database *Create(EventLoop &loop, DatabaseListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
virtual bool Open(Error &error) override;
@@ -94,7 +94,7 @@ public:
Error &error) const override;
virtual bool VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag_type, uint32_t group_mask,
+ TagType tag_type, tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const override;
@@ -106,7 +106,7 @@ public:
}
protected:
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
private:
bool VisitServer(const ContentDirectoryService &server,
@@ -158,10 +158,10 @@ private:
Database *
UpnpDatabase::Create(gcc_unused EventLoop &loop,
gcc_unused DatabaseListener &listener,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
UpnpDatabase *db = new UpnpDatabase();
- if (!db->Configure(param, error)) {
+ if (!db->Configure(block, error)) {
delete db;
return nullptr;
}
@@ -173,7 +173,7 @@ UpnpDatabase::Create(gcc_unused EventLoop &loop,
}
inline bool
-UpnpDatabase::Configure(const config_param &, Error &)
+UpnpDatabase::Configure(const ConfigBlock &, Error &)
{
return true;
}
@@ -222,7 +222,7 @@ UpnpDatabase::GetSong(const char *uri, Error &error) const
}
ContentDirectoryService server;
- if (!discovery->getServer(vpath.front().c_str(), server, error))
+ if (!discovery->GetServer(vpath.front().c_str(), server, error))
return nullptr;
vpath.pop_front();
@@ -303,7 +303,7 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
} else {
cond += " = ";
}
- dquote(cond, item.GetValue().c_str());
+ dquote(cond, item.GetValue());
}
cond += ')';
}
@@ -339,7 +339,7 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
} else {
cond += " = ";
}
- dquote(cond, item.GetValue().c_str());
+ dquote(cond, item.GetValue());
}
}
@@ -414,7 +414,7 @@ UpnpDatabase::SearchSongs(const ContentDirectoryService &server,
// So we return synthetic and ugly paths based on the object id,
// which we later have to detect.
const std::string path = songPath(server.getFriendlyName(),
- dirent.m_id);
+ dirent.id);
if (!visitSong(std::move(dirent), path.c_str(),
selection, visit_song,
error))
@@ -449,13 +449,13 @@ UpnpDatabase::BuildPath(const ContentDirectoryService &server,
std::string &path,
Error &error) const
{
- const char *pid = idirent.m_id.c_str();
+ const char *pid = idirent.id.c_str();
path.clear();
UPnPDirObject dirent;
while (strcmp(pid, rootid) != 0) {
if (!ReadNode(server, pid, dirent, error))
return false;
- pid = dirent.m_pid.c_str();
+ pid = dirent.parent_id.c_str();
if (path.empty())
path = dirent.name;
@@ -511,7 +511,7 @@ UpnpDatabase::Namei(const ContentDirectoryService &server,
return false;
}
- objid = std::move(child->m_id);
+ objid = std::move(child->id);
}
}
@@ -623,7 +623,7 @@ UpnpDatabase::VisitServer(const ContentDirectoryService &server,
}
std::string path = songPath(server.getFriendlyName(),
- dirent.m_id);
+ dirent.id);
if (!visitSong(std::move(dirent), path.c_str(),
selection,
visit_song, error))
@@ -642,7 +642,7 @@ UpnpDatabase::VisitServer(const ContentDirectoryService &server,
recursion (1-deep) here, which will handle the "add dir"
case. */
if (selection.recursive && selection.filter)
- return SearchSongs(server, tdirent.m_id.c_str(), selection,
+ return SearchSongs(server, tdirent.id.c_str(), selection,
visit_song, error);
const char *const base_uri = selection.uri.empty()
@@ -660,7 +660,7 @@ UpnpDatabase::VisitServer(const ContentDirectoryService &server,
and loop here, but it's not useful as mpd will only return
data to the client when we're done anyway. */
UPnPDirContent dirbuf;
- if (!server.readDir(handle, tdirent.m_id.c_str(), dirbuf,
+ if (!server.readDir(handle, tdirent.id.c_str(), dirbuf,
error))
return false;
@@ -689,7 +689,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
auto vpath = stringToTokens(selection.uri, "/", true);
if (vpath.empty()) {
std::vector<ContentDirectoryService> servers;
- if (!discovery->getDirServices(servers, error))
+ if (!discovery->GetDirectories(servers, error))
return false;
for (const auto &server : servers) {
@@ -714,7 +714,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
vpath.pop_front();
ContentDirectoryService server;
- if (!discovery->getServer(servername.c_str(), server, error))
+ if (!discovery->GetServer(servername.c_str(), server, error))
return false;
return VisitServer(server, vpath, selection,
@@ -723,7 +723,7 @@ UpnpDatabase::Visit(const DatabaseSelection &selection,
bool
UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection,
- TagType tag, gcc_unused uint32_t group_mask,
+ TagType tag, gcc_unused tag_mask_t group_mask,
VisitTag visit_tag,
Error &error) const
{
@@ -733,7 +733,7 @@ UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection,
return true;
std::vector<ContentDirectoryService> servers;
- if (!discovery->getDirServices(servers, error))
+ if (!discovery->GetDirectories(servers, error))
return false;
std::set<std::string> values;
@@ -749,7 +749,7 @@ UpnpDatabase::VisitUniqueTags(const DatabaseSelection &selection,
const char *value = dirent.tag.GetValue(tag);
if (value != nullptr) {
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
values.emplace(value);
#else
values.insert(value);
diff --git a/src/db/plugins/upnp/UpnpDatabasePlugin.hxx b/src/db/plugins/upnp/UpnpDatabasePlugin.hxx
index 0228405cd..f03cde75d 100644
--- a/src/db/plugins/upnp/UpnpDatabasePlugin.hxx
+++ b/src/db/plugins/upnp/UpnpDatabasePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Archive.cxx b/src/db/update/Archive.cxx
index fc8f1fcbf..e818ab279 100644
--- a/src/db/update/Archive.cxx
+++ b/src/db/update/Archive.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -104,7 +104,7 @@ class UpdateArchiveVisitor final : public ArchiveVisitor {
*/
void
UpdateWalk::UpdateArchiveFile(Directory &parent, const char *name,
- const FileInfo &info,
+ const StorageFileInfo &info,
const ArchivePlugin &plugin)
{
db_lock();
@@ -156,7 +156,7 @@ UpdateWalk::UpdateArchiveFile(Directory &parent, const char *name,
bool
UpdateWalk::UpdateArchiveFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
const ArchivePlugin *plugin = archive_plugin_from_suffix(suffix);
if (plugin == nullptr)
diff --git a/src/db/update/Container.cxx b/src/db/update/Container.cxx
index 1c420fa99..93ba5ff20 100644
--- a/src/db/update/Container.cxx
+++ b/src/db/update/Container.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@
Directory *
UpdateWalk::MakeDirectoryIfModified(Directory &parent, const char *name,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
Directory *directory = parent.FindChild(name);
@@ -69,7 +69,7 @@ SupportsContainerSuffix(const DecoderPlugin &plugin, const char *suffix)
bool
UpdateWalk::UpdateContainerFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
const DecoderPlugin *_plugin = decoder_plugins_find([suffix](const DecoderPlugin &plugin){
return SupportsContainerSuffix(plugin, suffix);
@@ -106,8 +106,11 @@ UpdateWalk::UpdateContainerFile(Directory &directory,
// shouldn't be necessary but it's there..
song->mtime = info.mtime;
+ const auto vtrack_fs = AllocatedPath::FromUTF8(vtrack);
+ // TODO: check vtrack_fs.IsNull()
+
const auto child_path_fs = AllocatedPath::Build(pathname,
- vtrack);
+ vtrack_fs);
plugin.ScanFile(child_path_fs,
add_tag_handler, &tag_builder);
diff --git a/src/db/update/Editor.cxx b/src/db/update/Editor.cxx
index 4136ccdad..2ca17f8cb 100644
--- a/src/db/update/Editor.cxx
+++ b/src/db/update/Editor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Editor.hxx b/src/db/update/Editor.hxx
index 58e23ed7a..cefb6c07f 100644
--- a/src/db/update/Editor.hxx
+++ b/src/db/update/Editor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/ExcludeList.cxx b/src/db/update/ExcludeList.cxx
index cf92ac8f7..b09f349ac 100644
--- a/src/db/update/ExcludeList.cxx
+++ b/src/db/update/ExcludeList.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,36 +25,46 @@
#include "config.h"
#include "ExcludeList.hxx"
#include "fs/Path.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/NarrowPath.hxx"
+#include "fs/io/TextFile.hxx"
#include "util/StringUtil.hxx"
-#include "util/Domain.hxx"
+#include "util/Error.hxx"
#include "Log.hxx"
#include <assert.h>
#include <string.h>
#include <errno.h>
-static constexpr Domain exclude_list_domain("exclude_list");
+#ifdef HAVE_CLASS_GLOB
+
+gcc_pure
+static bool
+IsFileNotFound(const Error &error)
+{
+#ifdef WIN32
+ return error.IsDomain(win32_domain) &&
+ error.GetCode() == ERROR_FILE_NOT_FOUND;
+#else
+ return error.IsDomain(errno_domain) && error.GetCode() == ENOENT;
+#endif
+}
+
+#endif
bool
ExcludeList::LoadFile(Path path_fs)
{
-#ifdef HAVE_GLIB
- FILE *file = FOpen(path_fs, FOpenMode::ReadText);
- if (file == nullptr) {
- const int e = errno;
- if (e != ENOENT) {
- const auto path_utf8 = path_fs.ToUTF8();
- FormatErrno(exclude_list_domain,
- "Failed to open %s",
- path_utf8.c_str());
- }
-
+#ifdef HAVE_CLASS_GLOB
+ Error error;
+ TextFile file(path_fs, error);
+ if (file.HasFailed()) {
+ if (!IsFileNotFound(error))
+ LogError(error);
return false;
}
- char line[1024];
- while (fgets(line, sizeof(line), file) != nullptr) {
+ char *line;
+ while ((line = file.ReadLine()) != nullptr) {
char *p = strchr(line, '#');
if (p != nullptr)
*p = 0;
@@ -63,10 +73,8 @@ ExcludeList::LoadFile(Path path_fs)
if (*p != 0)
patterns.emplace_front(p);
}
-
- fclose(file);
#else
- // TODO: implement
+ /* not implemented */
(void)path_fs;
#endif
@@ -80,12 +88,18 @@ ExcludeList::Check(Path name_fs) const
/* XXX include full path name in check */
-#ifdef HAVE_GLIB
+#ifdef HAVE_CLASS_GLOB
+ if (parent != nullptr) {
+ if (parent->Check(name_fs)) {
+ return true;
+ }
+ }
+
for (const auto &i : patterns)
- if (i.Check(name_fs.c_str()))
+ if (i.Check(NarrowPath(name_fs).c_str()))
return true;
#else
- // TODO: implement
+ /* not implemented */
(void)name_fs;
#endif
diff --git a/src/db/update/ExcludeList.hxx b/src/db/update/ExcludeList.hxx
index ef6c4d53e..4952d291a 100644
--- a/src/db/update/ExcludeList.hxx
+++ b/src/db/update/ExcludeList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,51 +27,34 @@
#include "check.h"
#include "Compiler.h"
+#include "fs/Glob.hxx"
+#ifdef HAVE_CLASS_GLOB
#include <forward_list>
-
-#ifdef HAVE_GLIB
-#include <glib.h>
#endif
class Path;
class ExcludeList {
-#ifdef HAVE_GLIB
- class Pattern {
- GPatternSpec *pattern;
-
- public:
- Pattern(const char *_pattern)
- :pattern(g_pattern_spec_new(_pattern)) {}
-
- Pattern(Pattern &&other)
- :pattern(other.pattern) {
- other.pattern = nullptr;
- }
-
- ~Pattern() {
- g_pattern_spec_free(pattern);
- }
+ const ExcludeList *const parent;
- gcc_pure
- bool Check(const char *name_fs) const {
- return g_pattern_match_string(pattern, name_fs);
- }
- };
-
- std::forward_list<Pattern> patterns;
-#else
- // TODO: implement
+#ifdef HAVE_CLASS_GLOB
+ std::forward_list<Glob> patterns;
#endif
public:
+ ExcludeList()
+ :parent(nullptr) {}
+
+ ExcludeList(const ExcludeList &_parent)
+ :parent(&_parent) {}
+
gcc_pure
bool IsEmpty() const {
-#ifdef HAVE_GLIB
- return patterns.empty();
+#ifdef HAVE_CLASS_GLOB
+ return ((parent == nullptr) || parent->IsEmpty()) && patterns.empty();
#else
- // TODO: implement
+ /* not implemented */
return true;
#endif
}
diff --git a/src/db/update/InotifyDomain.cxx b/src/db/update/InotifyDomain.cxx
index 4a3ab2d79..18557a5ce 100644
--- a/src/db/update/InotifyDomain.cxx
+++ b/src/db/update/InotifyDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/InotifyDomain.hxx b/src/db/update/InotifyDomain.hxx
index ad6202361..219ee7e4f 100644
--- a/src/db/update/InotifyDomain.hxx
+++ b/src/db/update/InotifyDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/InotifyQueue.cxx b/src/db/update/InotifyQueue.cxx
index 013200f98..4b5269427 100644
--- a/src/db/update/InotifyQueue.cxx
+++ b/src/db/update/InotifyQueue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/InotifyQueue.hxx b/src/db/update/InotifyQueue.hxx
index a9abc2969..dab7c7e8c 100644
--- a/src/db/update/InotifyQueue.hxx
+++ b/src/db/update/InotifyQueue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/InotifySource.cxx b/src/db/update/InotifySource.cxx
index 233504ad6..b084dd60a 100644
--- a/src/db/update/InotifySource.cxx
+++ b/src/db/update/InotifySource.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include "InotifySource.hxx"
#include "InotifyDomain.hxx"
#include "util/Error.hxx"
-#include "system/fd_util.h"
+#include "system/FileDescriptor.hxx"
#include "system/FatalError.hxx"
#include "Log.hxx"
@@ -72,8 +72,8 @@ InotifySource::OnSocketReady(gcc_unused unsigned flags)
inline
InotifySource::InotifySource(EventLoop &_loop,
mpd_inotify_callback_t _callback, void *_ctx,
- int _fd)
- :SocketMonitor(_fd, _loop),
+ FileDescriptor _fd)
+ :SocketMonitor(_fd.Get(), _loop),
callback(_callback), callback_ctx(_ctx)
{
ScheduleRead();
@@ -85,8 +85,8 @@ InotifySource::Create(EventLoop &loop,
mpd_inotify_callback_t callback, void *callback_ctx,
Error &error)
{
- int fd = inotify_init_cloexec();
- if (fd < 0) {
+ FileDescriptor fd;
+ if (!fd.CreateInotify()) {
error.SetErrno("inotify_init() has failed");
return nullptr;
}
diff --git a/src/db/update/InotifySource.hxx b/src/db/update/InotifySource.hxx
index 2557680a0..34d84c2dd 100644
--- a/src/db/update/InotifySource.hxx
+++ b/src/db/update/InotifySource.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "Compiler.h"
class Error;
+class FileDescriptor;
typedef void (*mpd_inotify_callback_t)(int wd, unsigned mask,
const char *name, void *ctx);
@@ -33,7 +34,8 @@ class InotifySource final : private SocketMonitor {
void *callback_ctx;
InotifySource(EventLoop &_loop,
- mpd_inotify_callback_t callback, void *ctx, int fd);
+ mpd_inotify_callback_t callback, void *ctx,
+ FileDescriptor fd);
public:
~InotifySource() {
@@ -41,10 +43,11 @@ public:
}
/**
- * Creates a new inotify source and registers it in the GLib main
- * loop.
+ * Creates a new inotify source and registers it in the
+ * #EventLoop.
*
- * @param a callback invoked for events received from the kernel
+ * @param callback a callback invoked for events received from
+ * the kernel
*/
static InotifySource *Create(EventLoop &_loop,
mpd_inotify_callback_t callback,
diff --git a/src/db/update/InotifyUpdate.cxx b/src/db/update/InotifyUpdate.cxx
index 26bdddf8d..f699b7f78 100644
--- a/src/db/update/InotifyUpdate.cxx
+++ b/src/db/update/InotifyUpdate.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include "InotifyDomain.hxx"
#include "storage/StorageInterface.hxx"
#include "fs/AllocatedPath.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -179,7 +179,6 @@ recursive_watch_subdirectories(WatchDirectory *directory,
}
while ((ent = readdir(dir))) {
- struct stat st;
int ret;
if (skip_path(ent->d_name))
@@ -187,15 +186,15 @@ recursive_watch_subdirectories(WatchDirectory *directory,
const auto child_path_fs =
AllocatedPath::Build(path_fs, ent->d_name);
- ret = StatFile(child_path_fs, st);
- if (ret < 0) {
- FormatErrno(inotify_domain,
- "Failed to stat %s",
- child_path_fs.c_str());
+
+ FileInfo fi;
+ if (!GetFileInfo(child_path_fs, fi, error)) {
+ LogError(error);
+ error.Clear();
continue;
}
- if (!S_ISDIR(st.st_mode))
+ if (!fi.IsDirectory())
continue;
ret = inotify_source->Add(child_path_fs.c_str(), IN_MASK,
diff --git a/src/db/update/InotifyUpdate.hxx b/src/db/update/InotifyUpdate.hxx
index 0f78db71f..82b6cdf04 100644
--- a/src/db/update/InotifyUpdate.hxx
+++ b/src/db/update/InotifyUpdate.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,6 +32,6 @@ mpd_inotify_init(EventLoop &loop, Storage &storage, UpdateService &update,
unsigned max_depth);
void
-mpd_inotify_finish(void);
+mpd_inotify_finish();
#endif
diff --git a/src/db/update/Queue.cxx b/src/db/update/Queue.cxx
index 6d6d80131..870207fc6 100644
--- a/src/db/update/Queue.cxx
+++ b/src/db/update/Queue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Queue.hxx b/src/db/update/Queue.hxx
index 9064ea481..6c0a5733d 100644
--- a/src/db/update/Queue.hxx
+++ b/src/db/update/Queue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Remove.cxx b/src/db/update/Remove.cxx
index dfada05b2..0f1cbde1c 100644
--- a/src/db/update/Remove.cxx
+++ b/src/db/update/Remove.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Remove.hxx b/src/db/update/Remove.hxx
index ce6d77d47..5ebfb884b 100644
--- a/src/db/update/Remove.hxx
+++ b/src/db/update/Remove.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Service.cxx b/src/db/update/Service.cxx
index e8a1f6b02..e14dbdc6c 100644
--- a/src/db/update/Service.cxx
+++ b/src/db/update/Service.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/Service.hxx b/src/db/update/Service.hxx
index feaeaebc5..7dd198a7f 100644
--- a/src/db/update/Service.hxx
+++ b/src/db/update/Service.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/UpdateDomain.cxx b/src/db/update/UpdateDomain.cxx
index 80ad4fd22..68fcbe81c 100644
--- a/src/db/update/UpdateDomain.cxx
+++ b/src/db/update/UpdateDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/UpdateDomain.hxx b/src/db/update/UpdateDomain.hxx
index a6e994390..8669d24b4 100644
--- a/src/db/update/UpdateDomain.hxx
+++ b/src/db/update/UpdateDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/db/update/UpdateIO.cxx b/src/db/update/UpdateIO.cxx
index 9e43d1289..1a0f318c3 100644
--- a/src/db/update/UpdateIO.cxx
+++ b/src/db/update/UpdateIO.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
#include <unistd.h>
bool
-GetInfo(Storage &storage, const char *uri_utf8, FileInfo &info)
+GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info)
{
Error error;
bool success = storage.GetInfo(uri_utf8, true, info, error);
@@ -43,7 +43,7 @@ GetInfo(Storage &storage, const char *uri_utf8, FileInfo &info)
}
bool
-GetInfo(StorageDirectoryReader &reader, FileInfo &info)
+GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info)
{
Error error;
bool success = reader.GetInfo(true, info, error);
@@ -55,7 +55,7 @@ GetInfo(StorageDirectoryReader &reader, FileInfo &info)
bool
DirectoryExists(Storage &storage, const Directory &directory)
{
- FileInfo info;
+ StorageFileInfo info;
if (!storage.GetInfo(directory.GetPath(), true, info, IgnoreError()))
return false;
@@ -67,7 +67,7 @@ DirectoryExists(Storage &storage, const Directory &directory)
static bool
GetDirectoryChildInfo(Storage &storage, const Directory &directory,
- const char *name_utf8, FileInfo &info, Error &error)
+ const char *name_utf8, StorageFileInfo &info, Error &error)
{
const auto uri_utf8 = PathTraitsUTF8::Build(directory.GetPath(),
name_utf8);
@@ -78,7 +78,7 @@ bool
directory_child_is_regular(Storage &storage, const Directory &directory,
const char *name_utf8)
{
- FileInfo info;
+ StorageFileInfo info;
return GetDirectoryChildInfo(storage, directory, name_utf8, info,
IgnoreError()) &&
info.IsRegular();
diff --git a/src/db/update/UpdateIO.hxx b/src/db/update/UpdateIO.hxx
index 2dbb4ae83..0223cb62c 100644
--- a/src/db/update/UpdateIO.hxx
+++ b/src/db/update/UpdateIO.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include "Compiler.h"
struct Directory;
-struct FileInfo;
+struct StorageFileInfo;
class Storage;
class StorageDirectoryReader;
@@ -33,14 +33,14 @@ class StorageDirectoryReader;
* returning them.
*/
bool
-GetInfo(Storage &storage, const char *uri_utf8, FileInfo &info);
+GetInfo(Storage &storage, const char *uri_utf8, StorageFileInfo &info);
/**
* Wrapper for LocalDirectoryReader::GetInfo() that logs errors
* instead of returning them.
*/
bool
-GetInfo(StorageDirectoryReader &reader, FileInfo &info);
+GetInfo(StorageDirectoryReader &reader, StorageFileInfo &info);
gcc_pure
bool
diff --git a/src/db/update/UpdateSong.cxx b/src/db/update/UpdateSong.cxx
index 005bf8992..e6ed5643a 100644
--- a/src/db/update/UpdateSong.cxx
+++ b/src/db/update/UpdateSong.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@
inline void
UpdateWalk::UpdateSongFile2(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
db_lock();
Song *song = directory.FindSong(name);
@@ -93,7 +93,7 @@ UpdateWalk::UpdateSongFile2(Directory &directory,
bool
UpdateWalk::UpdateSongFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
if (!decoder_plugins_supports_suffix(suffix))
return false;
diff --git a/src/db/update/Walk.cxx b/src/db/update/Walk.cxx
index 9fdb5bbdf..3e5654a3c 100644
--- a/src/db/update/Walk.cxx
+++ b/src/db/update/Walk.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -57,17 +57,17 @@ UpdateWalk::UpdateWalk(EventLoop &_loop, DatabaseListener &_listener,
{
#ifndef WIN32
follow_inside_symlinks =
- config_get_bool(CONF_FOLLOW_INSIDE_SYMLINKS,
+ config_get_bool(ConfigOption::FOLLOW_INSIDE_SYMLINKS,
DEFAULT_FOLLOW_INSIDE_SYMLINKS);
follow_outside_symlinks =
- config_get_bool(CONF_FOLLOW_OUTSIDE_SYMLINKS,
+ config_get_bool(ConfigOption::FOLLOW_OUTSIDE_SYMLINKS,
DEFAULT_FOLLOW_OUTSIDE_SYMLINKS);
#endif
}
static void
-directory_set_stat(Directory &dir, const FileInfo &info)
+directory_set_stat(Directory &dir, const StorageFileInfo &info)
{
dir.inode = info.inode;
dir.device = info.device;
@@ -140,7 +140,7 @@ UpdateWalk::PurgeDeletedFromDirectory(Directory &directory)
static bool
update_directory_stat(Storage &storage, Directory &directory)
{
- FileInfo info;
+ StorageFileInfo info;
if (!GetInfo(storage, directory.GetPath(), info))
return false;
@@ -190,7 +190,7 @@ FindAncestorLoop(Storage &storage, Directory *parent,
inline bool
UpdateWalk::UpdatePlaylistFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info)
+ const StorageFileInfo &info)
{
if (!playlist_suffix_supported(suffix))
return false;
@@ -206,7 +206,7 @@ UpdateWalk::UpdatePlaylistFile(Directory &directory,
inline bool
UpdateWalk::UpdateRegularFile(Directory &directory,
- const char *name, const FileInfo &info)
+ const char *name, const StorageFileInfo &info)
{
const char *suffix = uri_get_suffix(name);
if (suffix == nullptr)
@@ -219,7 +219,8 @@ UpdateWalk::UpdateRegularFile(Directory &directory,
void
UpdateWalk::UpdateDirectoryChild(Directory &directory,
- const char *name, const FileInfo &info)
+ const ExcludeList &exclude_list,
+ const char *name, const StorageFileInfo &info)
{
assert(strchr(name, '/') == nullptr);
@@ -236,7 +237,7 @@ UpdateWalk::UpdateDirectoryChild(Directory &directory,
assert(&directory == subdir->parent);
- if (!UpdateDirectory(*subdir, info))
+ if (!UpdateDirectory(*subdir, exclude_list, info))
editor.LockDeleteDirectory(subdir);
} else {
FormatDebug(update_domain,
@@ -327,7 +328,9 @@ UpdateWalk::SkipSymlink(const Directory *directory,
}
bool
-UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
+UpdateWalk::UpdateDirectory(Directory &directory,
+ const ExcludeList &exclude_list,
+ const StorageFileInfo &info)
{
assert(info.IsDirectory());
@@ -340,17 +343,17 @@ UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
return false;
}
- ExcludeList exclude_list;
+ ExcludeList child_exclude_list(exclude_list);
{
const auto exclude_path_fs =
storage.MapChildFS(directory.GetPath(), ".mpdignore");
if (!exclude_path_fs.IsNull())
- exclude_list.LoadFile(exclude_path_fs);
+ child_exclude_list.LoadFile(exclude_path_fs);
}
- if (!exclude_list.IsEmpty())
- RemoveExcludedFromDirectory(directory, exclude_list);
+ if (!child_exclude_list.IsEmpty())
+ RemoveExcludedFromDirectory(directory, child_exclude_list);
PurgeDeletedFromDirectory(directory);
@@ -361,7 +364,7 @@ UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
{
const auto name_fs = AllocatedPath::FromUTF8(name_utf8);
- if (name_fs.IsNull() || exclude_list.Check(name_fs))
+ if (name_fs.IsNull() || child_exclude_list.Check(name_fs))
continue;
}
@@ -370,13 +373,13 @@ UpdateWalk::UpdateDirectory(Directory &directory, const FileInfo &info)
continue;
}
- FileInfo info2;
+ StorageFileInfo info2;
if (!GetInfo(*reader, info2)) {
modified |= editor.DeleteNameIn(directory, name_utf8);
continue;
}
- UpdateDirectoryChild(directory, name_utf8, info2);
+ UpdateDirectoryChild(directory, child_exclude_list, name_utf8, info2);
}
directory.mtime = info.mtime;
@@ -400,7 +403,7 @@ UpdateWalk::DirectoryMakeChildChecked(Directory &parent,
return directory;
}
- FileInfo info;
+ StorageFileInfo info;
if (!GetInfo(storage, uri_utf8, info) ||
FindAncestorLoop(storage, &parent, info.inode, info.device))
return nullptr;
@@ -462,13 +465,15 @@ UpdateWalk::UpdateUri(Directory &root, const char *uri)
return;
}
- FileInfo info;
+ StorageFileInfo info;
if (!GetInfo(storage, uri, info)) {
modified |= editor.DeleteNameIn(*parent, name);
return;
}
- UpdateDirectoryChild(*parent, name, info);
+ ExcludeList exclude_list;
+
+ UpdateDirectoryChild(*parent, exclude_list, name, info);
}
bool
@@ -480,11 +485,13 @@ UpdateWalk::Walk(Directory &root, const char *path, bool discard)
if (path != nullptr && !isRootDirectory(path)) {
UpdateUri(root, path);
} else {
- FileInfo info;
+ StorageFileInfo info;
if (!GetInfo(storage, "", info))
return false;
- UpdateDirectory(root, info);
+ ExcludeList exclude_list;
+
+ UpdateDirectory(root, exclude_list, info);
}
return modified;
diff --git a/src/db/update/Walk.hxx b/src/db/update/Walk.hxx
index a4c518813..99d54ef51 100644
--- a/src/db/update/Walk.hxx
+++ b/src/db/update/Walk.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#include <sys/stat.h>
struct stat;
-struct FileInfo;
+struct StorageFileInfo;
struct Directory;
struct ArchivePlugin;
class Storage;
@@ -89,15 +89,15 @@ private:
void UpdateSongFile2(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info);
+ const StorageFileInfo &info);
bool UpdateSongFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info);
+ const StorageFileInfo &info);
bool UpdateContainerFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info);
+ const StorageFileInfo &info);
#ifdef ENABLE_ARCHIVE
@@ -105,10 +105,10 @@ private:
bool UpdateArchiveFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info);
+ const StorageFileInfo &info);
void UpdateArchiveFile(Directory &directory, const char *name,
- const FileInfo &info,
+ const StorageFileInfo &info,
const ArchivePlugin &plugin);
@@ -116,22 +116,26 @@ private:
bool UpdateArchiveFile(gcc_unused Directory &directory,
gcc_unused const char *name,
gcc_unused const char *suffix,
- gcc_unused const FileInfo &info) {
+ gcc_unused const StorageFileInfo &info) {
return false;
}
#endif
bool UpdatePlaylistFile(Directory &directory,
const char *name, const char *suffix,
- const FileInfo &info);
+ const StorageFileInfo &info);
bool UpdateRegularFile(Directory &directory,
- const char *name, const FileInfo &info);
+ const char *name, const StorageFileInfo &info);
void UpdateDirectoryChild(Directory &directory,
- const char *name, const FileInfo &info);
+ const ExcludeList &exclude_list,
+ const char *name,
+ const StorageFileInfo &info);
- bool UpdateDirectory(Directory &directory, const FileInfo &info);
+ bool UpdateDirectory(Directory &directory,
+ const ExcludeList &exclude_list,
+ const StorageFileInfo &info);
/**
* Create the specified directory object if it does not exist
@@ -142,7 +146,7 @@ private:
* The caller must lock the database.
*/
Directory *MakeDirectoryIfModified(Directory &parent, const char *name,
- const FileInfo &info);
+ const StorageFileInfo &info);
Directory *DirectoryMakeChildChecked(Directory &parent,
const char *uri_utf8,
diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx
index 941d3a70d..cc08596a2 100644
--- a/src/decoder/DecoderAPI.cxx
+++ b/src/decoder/DecoderAPI.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderAPI.hxx b/src/decoder/DecoderAPI.hxx
index b756331d9..289298ba4 100644
--- a/src/decoder/DecoderAPI.hxx
+++ b/src/decoder/DecoderAPI.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@
#include "tag/Tag.hxx"
#include "AudioFormat.hxx"
#include "MixRampInfo.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "Chrono.hxx"
// IWYU pragma: end_exports
@@ -197,7 +197,6 @@ decoder_data(Decoder &decoder, InputStream &is,
* This function is called by the decoder plugin when it has
* successfully decoded a tag.
*
- * @param decoder the decoder object
* @param is an input stream which is buffering while we are waiting
* for the player
* @param tag the tag to send
@@ -216,9 +215,8 @@ decoder_tag(Decoder &decoder, InputStream &is, Tag &&tag)
/**
* Set replay gain values for the following chunks.
*
- * @param decoder the decoder object
- * @param rgi the replay_gain_info object; may be nullptr to invalidate
- * the previous replay gain values
+ * @param replay_gain_info the replay_gain_info object; may be nullptr
+ * to invalidate the previous replay gain values
*/
void
decoder_replay_gain(Decoder &decoder,
@@ -226,10 +224,6 @@ decoder_replay_gain(Decoder &decoder,
/**
* Store MixRamp tags.
- *
- * @param decoder the decoder object
- * @param mixramp_start the mixramp_start tag; may be nullptr to invalidate
- * @param mixramp_end the mixramp_end tag; may be nullptr to invalidate
*/
void
decoder_mixramp(Decoder &decoder, MixRampInfo &&mix_ramp);
diff --git a/src/decoder/DecoderBuffer.cxx b/src/decoder/DecoderBuffer.cxx
index a8958d6fd..47c18cdd1 100644
--- a/src/decoder/DecoderBuffer.cxx
+++ b/src/decoder/DecoderBuffer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderBuffer.hxx b/src/decoder/DecoderBuffer.hxx
index 9cf47d915..bc7138d5b 100644
--- a/src/decoder/DecoderBuffer.hxx
+++ b/src/decoder/DecoderBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderCommand.hxx b/src/decoder/DecoderCommand.hxx
index a00519644..88eac0181 100644
--- a/src/decoder/DecoderCommand.hxx
+++ b/src/decoder/DecoderCommand.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderControl.cxx b/src/decoder/DecoderControl.cxx
index c30da6214..a4fe570b2 100644
--- a/src/decoder/DecoderControl.cxx
+++ b/src/decoder/DecoderControl.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderControl.hxx b/src/decoder/DecoderControl.hxx
index ed2b8c538..a8e675bba 100644
--- a/src/decoder/DecoderControl.hxx
+++ b/src/decoder/DecoderControl.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderError.cxx b/src/decoder/DecoderError.cxx
index bd3842837..d82a4d58c 100644
--- a/src/decoder/DecoderError.cxx
+++ b/src/decoder/DecoderError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderError.hxx b/src/decoder/DecoderError.hxx
index 83cf98204..58aa6cb83 100644
--- a/src/decoder/DecoderError.hxx
+++ b/src/decoder/DecoderError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderInternal.cxx b/src/decoder/DecoderInternal.cxx
index f35878682..f0bb04125 100644
--- a/src/decoder/DecoderInternal.cxx
+++ b/src/decoder/DecoderInternal.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderInternal.hxx b/src/decoder/DecoderInternal.hxx
index 24b665e85..f33c80402 100644
--- a/src/decoder/DecoderInternal.hxx
+++ b/src/decoder/DecoderInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderList.cxx b/src/decoder/DecoderList.cxx
index cd6881ce2..e153b1398 100644
--- a/src/decoder/DecoderList.cxx
+++ b/src/decoder/DecoderList.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include "DecoderList.hxx"
#include "DecoderPlugin.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "plugins/AudiofileDecoderPlugin.hxx"
#include "plugins/PcmDecoderPlugin.hxx"
#include "plugins/DsdiffDecoderPlugin.hxx"
@@ -48,44 +48,42 @@
#include <string.h>
const struct DecoderPlugin *const decoder_plugins[] = {
-#ifdef HAVE_MAD
+#ifdef ENABLE_MAD
&mad_decoder_plugin,
#endif
-#ifdef HAVE_MPG123
+#ifdef ENABLE_MPG123
&mpg123_decoder_plugin,
#endif
#ifdef ENABLE_VORBIS_DECODER
&vorbis_decoder_plugin,
#endif
-#if defined(HAVE_FLAC)
+#ifdef ENABLE_FLAC
&oggflac_decoder_plugin,
-#endif
-#ifdef HAVE_FLAC
&flac_decoder_plugin,
#endif
-#ifdef HAVE_OPUS
+#ifdef ENABLE_OPUS
&opus_decoder_plugin,
#endif
#ifdef ENABLE_SNDFILE
&sndfile_decoder_plugin,
#endif
-#ifdef HAVE_AUDIOFILE
+#ifdef ENABLE_AUDIOFILE
&audiofile_decoder_plugin,
#endif
#ifdef ENABLE_DSD
&dsdiff_decoder_plugin,
&dsf_decoder_plugin,
#endif
-#ifdef HAVE_FAAD
+#ifdef ENABLE_FAAD
&faad_decoder_plugin,
#endif
-#ifdef HAVE_MPCDEC
+#ifdef ENABLE_MPCDEC
&mpcdec_decoder_plugin,
#endif
-#ifdef HAVE_WAVPACK
+#ifdef ENABLE_WAVPACK
&wavpack_decoder_plugin,
#endif
-#ifdef HAVE_MODPLUG
+#ifdef ENABLE_MODPLUG
&modplug_decoder_plugin,
#endif
#ifdef ENABLE_MIKMOD_DECODER
@@ -100,13 +98,13 @@ const struct DecoderPlugin *const decoder_plugins[] = {
#ifdef ENABLE_FLUIDSYNTH
&fluidsynth_decoder_plugin,
#endif
-#ifdef HAVE_ADPLUG
+#ifdef ENABLE_ADPLUG
&adplug_decoder_plugin,
#endif
-#ifdef HAVE_FFMPEG
+#ifdef ENABLE_FFMPEG
&ffmpeg_decoder_plugin,
#endif
-#ifdef HAVE_GME
+#ifdef ENABLE_GME
&gme_decoder_plugin,
#endif
&pcm_decoder_plugin,
@@ -129,12 +127,13 @@ decoder_plugin_from_name(const char *name)
void decoder_plugin_init_all(void)
{
- struct config_param empty;
+ ConfigBlock empty;
for (unsigned i = 0; decoder_plugins[i] != nullptr; ++i) {
const DecoderPlugin &plugin = *decoder_plugins[i];
- const struct config_param *param =
- config_find_block(CONF_DECODER, "plugin", plugin.name);
+ const auto *param =
+ config_find_block(ConfigBlockOption::DECODER, "plugin",
+ plugin.name);
if (param == nullptr)
param = &empty;
diff --git a/src/decoder/DecoderList.hxx b/src/decoder/DecoderList.hxx
index 47085d4ae..26ecc51d7 100644
--- a/src/decoder/DecoderList.hxx
+++ b/src/decoder/DecoderList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,10 +34,12 @@ const struct DecoderPlugin *
decoder_plugin_from_name(const char *name);
/* this is where we "load" all the "plugins" ;-) */
-void decoder_plugin_init_all(void);
+void
+decoder_plugin_init_all();
/* this is where we "unload" all the "plugins" */
-void decoder_plugin_deinit_all(void);
+void
+decoder_plugin_deinit_all();
template<typename F>
static inline const DecoderPlugin *
diff --git a/src/decoder/DecoderPlugin.cxx b/src/decoder/DecoderPlugin.cxx
index a0722c348..60b1c36d4 100644
--- a/src/decoder/DecoderPlugin.cxx
+++ b/src/decoder/DecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/DecoderPlugin.hxx b/src/decoder/DecoderPlugin.hxx
index dbf3db9aa..7aab05615 100644
--- a/src/decoder/DecoderPlugin.hxx
+++ b/src/decoder/DecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
#include "Compiler.h"
-struct config_param;
+struct ConfigBlock;
class InputStream;
struct tag_handler;
class Path;
@@ -44,16 +44,16 @@ struct DecoderPlugin {
* @return true if the plugin was initialized successfully,
* false if the plugin is not available
*/
- bool (*init)(const config_param &param);
+ bool (*init)(const ConfigBlock &block);
/**
* Deinitialize a decoder plugin which was initialized
* successfully. Optional method.
*/
- void (*finish)(void);
+ void (*finish)();
/**
- * Decode a stream (data read from an #input_stream object).
+ * Decode a stream (data read from an #InputStream object).
*
* Either implement this method or file_decode(). If
* possible, it is recommended to implement this method,
@@ -107,14 +107,13 @@ struct DecoderPlugin {
/**
* Initialize a decoder plugin.
*
- * @param param a configuration block for this plugin, or nullptr if none
- * is configured
+ * @param block a configuration block for this plugin
* @return true if the plugin was initialized successfully, false if
* the plugin is not available
*/
- bool Init(const config_param &param) const {
+ bool Init(const ConfigBlock &block) const {
return init != nullptr
- ? init(param)
+ ? init(block)
: true;
}
diff --git a/src/decoder/DecoderPrint.cxx b/src/decoder/DecoderPrint.cxx
index 54b89c36c..6a0822596 100644
--- a/src/decoder/DecoderPrint.cxx
+++ b/src/decoder/DecoderPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,35 +21,35 @@
#include "DecoderPrint.hxx"
#include "DecoderList.hxx"
#include "DecoderPlugin.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
#include <functional>
#include <assert.h>
static void
-decoder_plugin_print(Client &client,
+decoder_plugin_print(Response &r,
const DecoderPlugin &plugin)
{
const char *const*p;
assert(plugin.name != nullptr);
- client_printf(client, "plugin: %s\n", plugin.name);
+ r.Format("plugin: %s\n", plugin.name);
if (plugin.suffixes != nullptr)
for (p = plugin.suffixes; *p != nullptr; ++p)
- client_printf(client, "suffix: %s\n", *p);
+ r.Format("suffix: %s\n", *p);
if (plugin.mime_types != nullptr)
for (p = plugin.mime_types; *p != nullptr; ++p)
- client_printf(client, "mime_type: %s\n", *p);
+ r.Format("mime_type: %s\n", *p);
}
void
-decoder_list_print(Client &client)
+decoder_list_print(Response &r)
{
using namespace std::placeholders;
- const auto f = std::bind(decoder_plugin_print, std::ref(client), _1);
+ const auto f = std::bind(decoder_plugin_print, std::ref(r), _1);
decoder_plugins_for_each_enabled(f);
}
diff --git a/src/decoder/DecoderPrint.hxx b/src/decoder/DecoderPrint.hxx
index 695bd099d..fcb995f6b 100644
--- a/src/decoder/DecoderPrint.hxx
+++ b/src/decoder/DecoderPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,9 @@
#ifndef MPD_DECODER_PRINT_HXX
#define MPD_DECODER_PRINT_HXX
-class Client;
+class Response;
void
-decoder_list_print(Client &client);
+decoder_list_print(Response &r);
#endif
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index b4362a548..2a7275a68 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -60,14 +60,14 @@ decoder_command_finished_locked(DecoderControl &dc)
}
/**
- * Opens the input stream with input_stream::Open(), and waits until
+ * Opens the input stream with InputStream::Open(), and waits until
* the stream gets ready. If a decoder STOP command is received
* during that, it cancels the operation (but does not close the
* stream).
*
* Unlock the decoder before calling this function.
*
- * @return an input_stream on success or if #DecoderCommand::STOP is
+ * @return an InputStream on success or if #DecoderCommand::STOP is
* received, nullptr on error
*/
static InputStream *
@@ -267,12 +267,10 @@ static bool
decoder_run_stream(Decoder &decoder, const char *uri)
{
DecoderControl &dc = decoder.dc;
- InputStream *input_stream;
- bool success;
dc.Unlock();
- input_stream = decoder_input_stream_open(dc, uri);
+ InputStream *input_stream = decoder_input_stream_open(dc, uri);
if (input_stream == nullptr) {
dc.Lock();
return false;
@@ -281,7 +279,7 @@ decoder_run_stream(Decoder &decoder, const char *uri)
dc.Lock();
bool tried = false;
- success = dc.command == DecoderCommand::STOP ||
+ const bool success = dc.command == DecoderCommand::STOP ||
decoder_run_stream_locked(decoder, *input_stream, uri,
tried) ||
/* fallback to mp3: this is needed for bastard streams
@@ -385,13 +383,12 @@ decoder_run_song(DecoderControl &dc,
tags on "stream" songs are just remembered
from the last time we played it*/
song.IsFile() ? new Tag(song.GetTag()) : nullptr);
- int ret;
dc.state = DecoderState::START;
decoder_command_finished_locked(dc);
- ret = !path_fs.IsNull()
+ const int ret = !path_fs.IsNull()
? decoder_run_file(decoder, uri, path_fs)
: decoder_run_stream(decoder, uri);
diff --git a/src/decoder/DecoderThread.hxx b/src/decoder/DecoderThread.hxx
index d5fde281c..c262a679b 100644
--- a/src/decoder/DecoderThread.hxx
+++ b/src/decoder/DecoderThread.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.cxx b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
index 9cc37ade4..dd3f2b7ff 100644
--- a/src/decoder/plugins/AdPlugDecoderPlugin.cxx
+++ b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,14 +38,14 @@ static constexpr Domain adplug_domain("adplug");
static unsigned sample_rate;
static bool
-adplug_init(const config_param &param)
+adplug_init(const ConfigBlock &block)
{
FormatDebug(adplug_domain, "adplug %s",
CAdPlug::get_version().c_str());
Error error;
- sample_rate = param.GetBlockValue("sample_rate", 48000u);
+ sample_rate = block.GetBlockValue("sample_rate", 48000u);
if (!audio_check_sample_rate(sample_rate, error)) {
LogError(error);
return false;
diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.h b/src/decoder/plugins/AdPlugDecoderPlugin.h
index 539dbbf0a..16d9e507b 100644
--- a/src/decoder/plugins/AdPlugDecoderPlugin.h
+++ b/src/decoder/plugins/AdPlugDecoderPlugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
index a0ef71e49..7d59d9460 100644
--- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx
+++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -43,7 +43,7 @@ audiofile_error_func(long, const char *msg)
}
static bool
-audiofile_init(const config_param &)
+audiofile_init(const ConfigBlock &)
{
afSetErrorHandler(audiofile_error_func);
return true;
diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.hxx b/src/decoder/plugins/AudiofileDecoderPlugin.hxx
index 61129076d..dfeda0f7d 100644
--- a/src/decoder/plugins/AudiofileDecoderPlugin.hxx
+++ b/src/decoder/plugins/AudiofileDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/DsdLib.cxx b/src/decoder/plugins/DsdLib.cxx
index d826970f7..8fefbb48c 100644
--- a/src/decoder/plugins/DsdLib.cxx
+++ b/src/decoder/plugins/DsdLib.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include <string.h>
#include <stdlib.h>
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
#include <id3tag.h>
#endif
@@ -48,7 +48,7 @@ DsdId::Equals(const char *s) const
}
/**
- * Skip the #input_stream to the specified offset.
+ * Skip the #InputStream to the specified offset.
*/
bool
dsdlib_skip_to(Decoder *decoder, InputStream &is,
@@ -64,7 +64,7 @@ dsdlib_skip_to(Decoder *decoder, InputStream &is,
}
/**
- * Skip some bytes from the #input_stream.
+ * Skip some bytes from the #InputStream.
*/
bool
dsdlib_skip(Decoder *decoder, InputStream &is,
@@ -103,31 +103,29 @@ dsdlib_valid_freq(uint32_t samplefreq)
}
}
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
void
dsdlib_tag_id3(InputStream &is,
const struct tag_handler *handler,
- void *handler_ctx, int64_t tagoffset)
+ void *handler_ctx, offset_type tagoffset)
{
- assert(tagoffset >= 0);
-
if (tagoffset == 0 || !is.KnownSize())
return;
- if (!dsdlib_skip_to(nullptr, is, tagoffset))
- return;
-
/* Prevent broken files causing problems */
const auto size = is.GetSize();
- const auto offset = is.GetOffset();
- if (offset >= size)
+ if (tagoffset >= size)
return;
- const id3_length_t count = size - offset;
+ const auto count64 = size - tagoffset;
+ if (count64 < 10 || count64 > 1024 * 1024)
+ return;
- if (count < 10 || count > 1024 * 1024)
+ if (!dsdlib_skip_to(nullptr, is, tagoffset))
return;
+ const id3_length_t count = count64;
+
id3_byte_t *const id3_buf = new id3_byte_t[count];
if (id3_buf == nullptr)
return;
diff --git a/src/decoder/plugins/DsdLib.hxx b/src/decoder/plugins/DsdLib.hxx
index 8295bcbf6..27cd0d37f 100644
--- a/src/decoder/plugins/DsdLib.hxx
+++ b/src/decoder/plugins/DsdLib.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -81,6 +81,6 @@ dsdlib_valid_freq(uint32_t samplefreq);
void
dsdlib_tag_id3(InputStream &is,
const struct tag_handler *handler,
- void *handler_ctx, int64_t tagoffset);
+ void *handler_ctx, offset_type tagoffset);
#endif
diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.cxx b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
index b6c79e11e..bd587e0ce 100644
--- a/src/decoder/plugins/DsdiffDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -72,9 +72,9 @@ struct DsdiffMetaData {
static bool lsbitfirst;
static bool
-dsdiff_init(const config_param &param)
+dsdiff_init(const ConfigBlock &block)
{
- lsbitfirst = param.GetBlockValue("lsbitfirst", false);
+ lsbitfirst = block.GetBlockValue("lsbitfirst", false);
return true;
}
@@ -244,7 +244,7 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
/** offset for title tag */
offset_type title_offset = 0;
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
offset_type id3_offset = 0;
#endif
@@ -269,7 +269,7 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
chunk_size = chunk_header->GetSize();
title_offset = is.GetOffset();
}
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
/* 'ID3 ' chunk, offspec. Used by sacdextract */
if (chunk_header->id.Equals("ID3 ")) {
chunk_size = chunk_header->GetSize();
@@ -283,7 +283,7 @@ dsdiff_read_metadata_extra(Decoder *decoder, InputStream &is,
/* done processing chunk headers, process tags if any */
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
if (id3_offset != 0) {
/* a ID3 tag has preference over the other tags, do not process
other tags if we have one */
diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.hxx b/src/decoder/plugins/DsdiffDecoderPlugin.hxx
index 7aa36752b..503e99756 100644
--- a/src/decoder/plugins/DsdiffDecoderPlugin.hxx
+++ b/src/decoder/plugins/DsdiffDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/DsfDecoderPlugin.cxx b/src/decoder/plugins/DsfDecoderPlugin.cxx
index 690616d15..b111dbd51 100644
--- a/src/decoder/plugins/DsfDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsfDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -47,7 +47,7 @@ struct DsfMetaData {
unsigned sample_rate, channels;
bool bitreverse;
offset_type n_blocks;
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
offset_type id3_offset;
#endif
};
@@ -111,7 +111,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is,
if (sizeof(dsf_header) != chunk_size)
return false;
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
const offset_type metadata_offset = dsf_header.pmeta.Read();
#endif
@@ -174,7 +174,7 @@ dsf_read_metadata(Decoder *decoder, InputStream &is,
metadata->n_blocks = data_size / block_size;
metadata->channels = channels;
metadata->sample_rate = samplefreq;
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
metadata->id3_offset = metadata_offset;
#endif
/* check bits per sample format, determine if bitreverse is needed */
@@ -352,7 +352,7 @@ dsf_scan_stream(InputStream &is,
audio_format.sample_rate);
tag_handler_invoke_duration(handler, handler_ctx, songtime);
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
/* Add available tags from the ID3 tag */
dsdlib_tag_id3(is, handler, handler_ctx, metadata.id3_offset);
#endif
diff --git a/src/decoder/plugins/DsfDecoderPlugin.hxx b/src/decoder/plugins/DsfDecoderPlugin.hxx
index 02bea0b5c..5da6217e9 100644
--- a/src/decoder/plugins/DsfDecoderPlugin.hxx
+++ b/src/decoder/plugins/DsfDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index add23aaa4..8ea2b685c 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FaadDecoderPlugin.hxx b/src/decoder/plugins/FaadDecoderPlugin.hxx
index 968433e9b..3c42b4226 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.hxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 689089107..9493fee69 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,14 +20,25 @@
/* necessary because libavutil/common.h uses UINT64_C */
#define __STDC_CONSTANT_MACROS
+#include "lib/ffmpeg/Time.hxx"
#include "config.h"
#include "FfmpegDecoderPlugin.hxx"
#include "lib/ffmpeg/Domain.hxx"
+#include "lib/ffmpeg/Error.hxx"
+#include "lib/ffmpeg/LogError.hxx"
+#include "lib/ffmpeg/Init.hxx"
+#include "lib/ffmpeg/Buffer.hxx"
#include "../DecoderAPI.hxx"
#include "FfmpegMetaData.hxx"
+#include "FfmpegIo.hxx"
+#include "pcm/Interleave.hxx"
+#include "tag/TagBuilder.hxx"
#include "tag/TagHandler.hxx"
+#include "tag/ReplayGain.hxx"
+#include "tag/MixRamp.hxx"
#include "input/InputStream.hxx"
#include "CheckAudioFormat.hxx"
+#include "util/ConstBuffer.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "LogV.hxx"
@@ -38,7 +49,6 @@ extern "C" {
#include <libavformat/avio.h>
#include <libavutil/avutil.h>
#include <libavutil/log.h>
-#include <libavutil/mathematics.h>
#if LIBAVUTIL_VERSION_MAJOR >= 53
#include <libavutil/frame.h>
@@ -48,270 +58,95 @@ extern "C" {
#include <assert.h>
#include <string.h>
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
-static LogLevel
-import_ffmpeg_level(int level)
-{
- if (level <= AV_LOG_FATAL)
- return LogLevel::ERROR;
-
- if (level <= AV_LOG_WARNING)
- return LogLevel::WARNING;
-
- if (level <= AV_LOG_INFO)
- return LogLevel::INFO;
-
- return LogLevel::DEBUG;
-}
-
-static void
-mpd_ffmpeg_log_callback(gcc_unused void *ptr, int level,
- const char *fmt, va_list vl)
-{
- const AVClass * cls = nullptr;
-
- if (ptr != nullptr)
- 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 Domain d(domain);
- LogFormatV(d, import_ffmpeg_level(level), fmt, vl);
- }
-}
-
-struct AvioStream {
- Decoder *const decoder;
- InputStream &input;
-
- AVIOContext *io;
-
- AvioStream(Decoder *_decoder, InputStream &_input)
- :decoder(_decoder), input(_input), io(nullptr) {}
-
- ~AvioStream() {
- if (io != nullptr) {
- av_free(io->buffer);
- av_free(io);
- }
- }
-
- bool Open();
-};
-
-static int
-mpd_ffmpeg_stream_read(void *opaque, uint8_t *buf, int size)
-{
- AvioStream *stream = (AvioStream *)opaque;
-
- return decoder_read(stream->decoder, stream->input,
- (void *)buf, size);
-}
-
-static int64_t
-mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
-{
- AvioStream *stream = (AvioStream *)opaque;
-
- switch (whence) {
- case SEEK_SET:
- break;
-
- case SEEK_CUR:
- pos += stream->input.GetOffset();
- break;
-
- case SEEK_END:
- if (!stream->input.KnownSize())
- return -1;
-
- pos += stream->input.GetSize();
- break;
-
- case AVSEEK_SIZE:
- if (!stream->input.KnownSize())
- return -1;
-
- return stream->input.GetSize();
-
- default:
- return -1;
- }
-
- if (!stream->input.LockSeek(pos, IgnoreError()))
- return -1;
-
- return stream->input.GetOffset();
-}
-
-bool
-AvioStream::Open()
-{
- constexpr size_t BUFFER_SIZE = 8192;
- auto buffer = (unsigned char *)av_malloc(BUFFER_SIZE);
- if (buffer == nullptr)
- return false;
-
- io = avio_alloc_context(buffer, BUFFER_SIZE,
- false, this,
- mpd_ffmpeg_stream_read, nullptr,
- input.IsSeekable()
- ? mpd_ffmpeg_stream_seek : nullptr);
- /* If avio_alloc_context() fails, who frees the buffer? The
- libavformat API documentation does not specify this, it
- only says that AVIOContext.buffer must be freed in the end,
- however no AVIOContext exists in that failure code path. */
- return io != nullptr;
-}
-
-/**
- * API compatibility wrapper for av_open_input_stream() and
- * avformat_open_input().
- */
-static int
-mpd_ffmpeg_open_input(AVFormatContext **ic_ptr,
- AVIOContext *pb,
- const char *filename,
- AVInputFormat *fmt)
+static AVFormatContext *
+FfmpegOpenInput(AVIOContext *pb,
+ const char *filename,
+ AVInputFormat *fmt)
{
AVFormatContext *context = avformat_alloc_context();
if (context == nullptr)
- return AVERROR(ENOMEM);
+ return nullptr;
context->pb = pb;
- *ic_ptr = context;
- return avformat_open_input(ic_ptr, filename, fmt, nullptr);
+
+ avformat_open_input(&context, filename, fmt, nullptr);
+ return context;
}
static bool
-ffmpeg_init(gcc_unused const config_param &param)
+ffmpeg_init(gcc_unused const ConfigBlock &block)
{
- av_log_set_callback(mpd_ffmpeg_log_callback);
-
- av_register_all();
+ FfmpegInit();
return true;
}
+gcc_pure
static int
-ffmpeg_find_audio_stream(const AVFormatContext *format_context)
+ffmpeg_find_audio_stream(const AVFormatContext &format_context)
{
- for (unsigned i = 0; i < format_context->nb_streams; ++i)
- if (format_context->streams[i]->codec->codec_type ==
+ for (unsigned i = 0; i < format_context.nb_streams; ++i)
+ if (format_context.streams[i]->codec->codec_type ==
AVMEDIA_TYPE_AUDIO)
return i;
return -1;
}
-gcc_const
-static double
-time_from_ffmpeg(int64_t t, const AVRational time_base)
-{
- assert(t != (int64_t)AV_NOPTS_VALUE);
-
- return (double)av_rescale_q(t, time_base, (AVRational){1, 1024})
- / (double)1024;
-}
-
-template<typename Ratio>
-static constexpr AVRational
-RatioToAVRational()
-{
- return { Ratio::num, Ratio::den };
-}
-
-gcc_const
-static int64_t
-time_to_ffmpeg(SongTime t, const AVRational time_base)
-{
- return av_rescale_q(t.count(),
- RatioToAVRational<SongTime::period>(),
- time_base);
-}
-
-/**
- * Replace #AV_NOPTS_VALUE with the given fallback.
- */
-static constexpr int64_t
-timestamp_fallback(int64_t t, int64_t fallback)
-{
- return gcc_likely(t != int64_t(AV_NOPTS_VALUE))
- ? t
- : fallback;
-}
-
/**
* Accessor for AVStream::start_time that replaces AV_NOPTS_VALUE with
* zero. We can't use AV_NOPTS_VALUE in calculations, and we simply
* assume that the stream's start time is zero, which appears to be
* the best way out of that situation.
*/
-static int64_t
+static constexpr int64_t
start_time_fallback(const AVStream &stream)
{
- return timestamp_fallback(stream.start_time, 0);
-}
-
-static void
-copy_interleave_frame2(uint8_t *dest, uint8_t **src,
- unsigned nframes, unsigned nchannels,
- unsigned sample_size)
-{
- for (unsigned frame = 0; frame < nframes; ++frame) {
- for (unsigned channel = 0; channel < nchannels; ++channel) {
- memcpy(dest, src[channel] + frame * sample_size,
- sample_size);
- dest += sample_size;
- }
- }
+ return FfmpegTimestampFallback(stream.start_time, 0);
}
/**
- * Copy PCM data from a AVFrame to an interleaved buffer.
+ * Copy PCM data from a non-empty AVFrame to an interleaved buffer.
*/
-static int
-copy_interleave_frame(const AVCodecContext *codec_context,
- const AVFrame *frame,
- uint8_t **output_buffer,
- uint8_t **global_buffer, int *global_buffer_size)
+static ConstBuffer<void>
+copy_interleave_frame(const AVCodecContext &codec_context,
+ const AVFrame &frame,
+ FfmpegBuffer &global_buffer,
+ Error &error)
{
+ assert(frame.nb_samples > 0);
+
int plane_size;
const int data_size =
av_samples_get_buffer_size(&plane_size,
- codec_context->channels,
- frame->nb_samples,
- codec_context->sample_fmt, 1);
- if (data_size <= 0)
- return data_size;
-
- if (av_sample_fmt_is_planar(codec_context->sample_fmt) &&
- codec_context->channels > 1) {
- if(*global_buffer_size < data_size) {
- av_freep(global_buffer);
-
- *global_buffer = (uint8_t*)av_malloc(data_size);
-
- if (!*global_buffer)
- /* Not enough memory - shouldn't happen */
- return AVERROR(ENOMEM);
- *global_buffer_size = data_size;
+ codec_context.channels,
+ frame.nb_samples,
+ codec_context.sample_fmt, 1);
+ assert(data_size != 0);
+ if (data_size < 0) {
+ SetFfmpegError(error, data_size);
+ return 0;
+ }
+
+ void *output_buffer;
+ if (av_sample_fmt_is_planar(codec_context.sample_fmt) &&
+ codec_context.channels > 1) {
+ output_buffer = global_buffer.GetT<uint8_t>(data_size);
+ if (output_buffer == nullptr) {
+ /* Not enough memory - shouldn't happen */
+ error.SetErrno(ENOMEM);
+ return 0;
}
- *output_buffer = *global_buffer;
- copy_interleave_frame2(*output_buffer, frame->extended_data,
- frame->nb_samples,
- codec_context->channels,
- av_get_bytes_per_sample(codec_context->sample_fmt));
+
+ PcmInterleave(output_buffer,
+ ConstBuffer<const void *>((const void *const*)frame.extended_data,
+ codec_context.channels),
+ frame.nb_samples,
+ av_get_bytes_per_sample(codec_context.sample_fmt));
} else {
- *output_buffer = frame->extended_data[0];
+ output_buffer = frame.extended_data[0];
}
- return data_size;
+ return { output_buffer, (size_t)data_size };
}
/**
@@ -343,81 +178,82 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
}
/**
+ * Decode an #AVPacket and send the resulting PCM data to the decoder
+ * API.
+ *
* @param min_frame skip all data before this PCM frame number; this
* is used after seeking to skip data in an AVPacket until the exact
* desired time stamp has been reached
*/
static DecoderCommand
ffmpeg_send_packet(Decoder &decoder, InputStream &is,
- const AVPacket *packet,
- AVCodecContext *codec_context,
- const AVStream *stream,
- AVFrame *frame,
+ AVPacket packet,
+ AVCodecContext &codec_context,
+ const AVStream &stream,
+ AVFrame &frame,
uint64_t min_frame, size_t pcm_frame_size,
- uint8_t **buffer, int *buffer_size)
+ FfmpegBuffer &buffer)
{
size_t skip_bytes = 0;
- const auto pts = StreamRelativePts(*packet, *stream);
+ const auto pts = StreamRelativePts(packet, stream);
if (pts >= 0) {
if (min_frame > 0) {
- auto cur_frame = PtsToPcmFrame(pts, *stream,
- *codec_context);
+ auto cur_frame = PtsToPcmFrame(pts, stream,
+ codec_context);
if (cur_frame < min_frame)
skip_bytes = pcm_frame_size * (min_frame - cur_frame);
} else
decoder_timestamp(decoder,
- time_from_ffmpeg(pts, stream->time_base));
+ FfmpegTimeToDouble(pts,
+ stream.time_base));
}
- AVPacket packet2 = *packet;
-
- uint8_t *output_buffer;
+ Error error;
DecoderCommand cmd = DecoderCommand::NONE;
- while (packet2.size > 0 && cmd == DecoderCommand::NONE) {
- int audio_size = 0;
+ while (packet.size > 0 && cmd == DecoderCommand::NONE) {
int got_frame = 0;
- int len = avcodec_decode_audio4(codec_context,
- frame, &got_frame,
- &packet2);
- if (len >= 0 && got_frame) {
- audio_size = copy_interleave_frame(codec_context,
- frame,
- &output_buffer,
- buffer, buffer_size);
- if (audio_size < 0)
- len = audio_size;
- }
-
+ int len = avcodec_decode_audio4(&codec_context,
+ &frame, &got_frame,
+ &packet);
if (len < 0) {
/* if error, we skip the frame */
- LogDefault(ffmpeg_domain,
- "decoding failed, frame skipped");
+ LogFfmpegError(len, "decoding failed, frame skipped");
break;
}
- packet2.data += len;
- packet2.size -= len;
+ packet.data += len;
+ packet.size -= len;
- if (audio_size <= 0)
+ if (!got_frame || frame.nb_samples <= 0)
continue;
- const uint8_t *data = output_buffer;
+ auto output_buffer =
+ copy_interleave_frame(codec_context, frame,
+ buffer, error);
+ if (output_buffer.IsNull()) {
+ /* this must be a serious error,
+ e.g. OOM */
+ LogError(error);
+ return DecoderCommand::STOP;
+ }
+
if (skip_bytes > 0) {
- if (skip_bytes >= size_t(audio_size)) {
- skip_bytes -= audio_size;
+ if (skip_bytes >= output_buffer.size) {
+ skip_bytes -= output_buffer.size;
continue;
}
- data += skip_bytes;
- audio_size -= skip_bytes;
+ output_buffer.data =
+ (const uint8_t *)output_buffer.data + skip_bytes;
+ output_buffer.size -= skip_bytes;
skip_bytes = 0;
}
cmd = decoder_data(decoder, is,
- data, audio_size,
- codec_context->bit_rate / 1000);
+ output_buffer.data, output_buffer.size,
+ codec_context.bit_rate / 1000);
}
return cmd;
}
@@ -460,10 +296,8 @@ ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
static AVInputFormat *
ffmpeg_probe(Decoder *decoder, InputStream &is)
{
- enum {
- BUFFER_SIZE = 16384,
- PADDING = 16,
- };
+ constexpr size_t BUFFER_SIZE = 16384;
+ constexpr size_t PADDING = 16;
unsigned char buffer[BUFFER_SIZE];
size_t nbytes = decoder_read(decoder, is, buffer, BUFFER_SIZE);
@@ -503,85 +337,163 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
}
static void
-ffmpeg_decode(Decoder &decoder, InputStream &input)
+FfmpegParseMetaData(AVDictionary &dict, ReplayGainInfo &rg, MixRampInfo &mr)
{
- AVInputFormat *input_format = ffmpeg_probe(&decoder, input);
- if (input_format == nullptr)
- return;
+ AVDictionaryEntry *i = nullptr;
- FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)",
- input_format->name, input_format->long_name);
+ while ((i = av_dict_get(&dict, "", i,
+ AV_DICT_IGNORE_SUFFIX)) != nullptr) {
+ const char *name = i->key;
+ const char *value = i->value;
- AvioStream stream(&decoder, input);
- if (!stream.Open()) {
- LogError(ffmpeg_domain, "Failed to open stream");
- return;
+ if (!ParseReplayGainTag(rg, name, value))
+ ParseMixRampTag(mr, name, value);
}
+}
- //ffmpeg works with ours "fileops" helper
- AVFormatContext *format_context = nullptr;
- if (mpd_ffmpeg_open_input(&format_context, stream.io,
- input.GetURI(),
- input_format) != 0) {
- LogError(ffmpeg_domain, "Open failed");
+static void
+FfmpegParseMetaData(const AVStream &stream,
+ ReplayGainInfo &rg, MixRampInfo &mr)
+{
+ FfmpegParseMetaData(*stream.metadata, rg, mr);
+}
+
+static void
+FfmpegParseMetaData(const AVFormatContext &format_context, int audio_stream,
+ ReplayGainInfo &rg, MixRampInfo &mr)
+{
+ assert(audio_stream >= 0);
+
+ FfmpegParseMetaData(*format_context.metadata, rg, mr);
+ FfmpegParseMetaData(*format_context.streams[audio_stream],
+ rg, mr);
+}
+
+static void
+FfmpegParseMetaData(Decoder &decoder,
+ const AVFormatContext &format_context, int audio_stream)
+{
+ ReplayGainInfo rg;
+ rg.Clear();
+
+ MixRampInfo mr;
+ mr.Clear();
+
+ FfmpegParseMetaData(format_context, audio_stream, rg, mr);
+
+ if (rg.IsDefined())
+ decoder_replay_gain(decoder, &rg);
+
+ if (mr.IsDefined())
+ decoder_mixramp(decoder, std::move(mr));
+}
+
+static void
+FfmpegScanMetadata(const AVStream &stream,
+ const tag_handler &handler, void *handler_ctx)
+{
+ FfmpegScanDictionary(stream.metadata, &handler, handler_ctx);
+}
+
+static void
+FfmpegScanMetadata(const AVFormatContext &format_context, int audio_stream,
+ const tag_handler &handler, void *handler_ctx)
+{
+ assert(audio_stream >= 0);
+
+ FfmpegScanDictionary(format_context.metadata, &handler, handler_ctx);
+ FfmpegScanMetadata(*format_context.streams[audio_stream],
+ handler, handler_ctx);
+}
+
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(56, 1, 0)
+
+static void
+FfmpegScanTag(const AVFormatContext &format_context, int audio_stream,
+ TagBuilder &tag)
+{
+ FfmpegScanMetadata(format_context, audio_stream,
+ full_tag_handler, &tag);
+}
+
+/**
+ * Check if a new stream tag was received and pass it to
+ * decoder_tag().
+ */
+static void
+FfmpegCheckTag(Decoder &decoder, InputStream &is,
+ AVFormatContext &format_context, int audio_stream)
+{
+ AVStream &stream = *format_context.streams[audio_stream];
+ if ((stream.event_flags & AVSTREAM_EVENT_FLAG_METADATA_UPDATED) == 0)
+ /* no new metadata */
return;
- }
+ /* clear the flag */
+ stream.event_flags &= ~AVSTREAM_EVENT_FLAG_METADATA_UPDATED;
+
+ TagBuilder tag;
+ FfmpegScanTag(format_context, audio_stream, tag);
+ if (!tag.IsEmpty())
+ decoder_tag(decoder, is, tag.Commit());
+}
+
+#endif
+
+static void
+FfmpegDecode(Decoder &decoder, InputStream &input,
+ AVFormatContext &format_context)
+{
const int find_result =
- avformat_find_stream_info(format_context, nullptr);
+ avformat_find_stream_info(&format_context, nullptr);
if (find_result < 0) {
LogError(ffmpeg_domain, "Couldn't find stream info");
- avformat_close_input(&format_context);
return;
}
int audio_stream = ffmpeg_find_audio_stream(format_context);
if (audio_stream == -1) {
LogError(ffmpeg_domain, "No audio stream inside");
- avformat_close_input(&format_context);
return;
}
- AVStream *av_stream = format_context->streams[audio_stream];
+ AVStream &av_stream = *format_context.streams[audio_stream];
- AVCodecContext *codec_context = av_stream->codec;
+ AVCodecContext &codec_context = *av_stream.codec;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
const AVCodecDescriptor *codec_descriptor =
- avcodec_descriptor_get(codec_context->codec_id);
+ avcodec_descriptor_get(codec_context.codec_id);
if (codec_descriptor != nullptr)
FormatDebug(ffmpeg_domain, "codec '%s'",
codec_descriptor->name);
#else
- if (codec_context->codec_name[0] != 0)
+ if (codec_context.codec_name[0] != 0)
FormatDebug(ffmpeg_domain, "codec '%s'",
- codec_context->codec_name);
+ codec_context.codec_name);
#endif
- AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);
+ AVCodec *codec = avcodec_find_decoder(codec_context.codec_id);
if (!codec) {
LogError(ffmpeg_domain, "Unsupported audio codec");
- avformat_close_input(&format_context);
return;
}
const SampleFormat sample_format =
- ffmpeg_sample_format(codec_context->sample_fmt);
+ ffmpeg_sample_format(codec_context.sample_fmt);
if (sample_format == SampleFormat::UNDEFINED) {
// (error message already done by ffmpeg_sample_format())
- avformat_close_input(&format_context);
return;
}
Error error;
AudioFormat audio_format;
if (!audio_format_init_checked(audio_format,
- codec_context->sample_rate,
+ codec_context.sample_rate,
sample_format,
- codec_context->channels, error)) {
+ codec_context.channels, error)) {
LogError(error);
- avformat_close_input(&format_context);
return;
}
@@ -590,22 +502,20 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
values into AVCodecContext.channels - a change that will be
reverted later by avcodec_decode_audio3() */
- const int open_result = avcodec_open2(codec_context, codec, nullptr);
+ const int open_result = avcodec_open2(&codec_context, codec, nullptr);
if (open_result < 0) {
LogError(ffmpeg_domain, "Could not open codec");
- avformat_close_input(&format_context);
return;
}
const SignedSongTime total_time =
- format_context->duration != (int64_t)AV_NOPTS_VALUE
- ? SignedSongTime::FromScale<uint64_t>(format_context->duration,
- AV_TIME_BASE)
- : SignedSongTime::Negative();
+ FromFfmpegTimeChecked(av_stream.duration, av_stream.time_base);
decoder_initialized(decoder, audio_format,
input.IsSeekable(), total_time);
+ FfmpegParseMetaData(decoder, format_context, audio_stream);
+
#if LIBAVUTIL_VERSION_MAJOR >= 53
AVFrame *frame = av_frame_alloc();
#else
@@ -613,70 +523,119 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
#endif
if (!frame) {
LogError(ffmpeg_domain, "Could not allocate frame");
- avformat_close_input(&format_context);
return;
}
- uint8_t *interleaved_buffer = nullptr;
- int interleaved_buffer_size = 0;
+ FfmpegBuffer interleaved_buffer;
uint64_t min_frame = 0;
- DecoderCommand cmd;
- do {
- AVPacket packet;
- if (av_read_frame(format_context, &packet) < 0)
- /* end of file */
- break;
-
- if (packet.stream_index == audio_stream) {
- cmd = ffmpeg_send_packet(decoder, input,
- &packet, codec_context,
- av_stream,
- frame,
- min_frame, audio_format.GetFrameSize(),
- &interleaved_buffer, &interleaved_buffer_size);
- min_frame = 0;
- } else
- cmd = decoder_get_command(decoder);
-
- av_free_packet(&packet);
-
+ DecoderCommand cmd = decoder_get_command(decoder);
+ while (cmd != DecoderCommand::STOP) {
if (cmd == DecoderCommand::SEEK) {
int64_t where =
- time_to_ffmpeg(decoder_seek_time(decoder),
- av_stream->time_base) +
- start_time_fallback(*av_stream);
+ ToFfmpegTime(decoder_seek_time(decoder),
+ av_stream.time_base) +
+ start_time_fallback(av_stream);
/* AVSEEK_FLAG_BACKWARD asks FFmpeg to seek to
the packet boundary before the seek time
stamp, not after */
-
- if (av_seek_frame(format_context, audio_stream, where,
+ if (av_seek_frame(&format_context, audio_stream, where,
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
decoder_seek_error(decoder);
else {
- avcodec_flush_buffers(codec_context);
+ avcodec_flush_buffers(&codec_context);
min_frame = decoder_seek_where_frame(decoder);
decoder_command_finished(decoder);
}
}
- } while (cmd != DecoderCommand::STOP);
+
+ AVPacket packet;
+ if (av_read_frame(&format_context, &packet) < 0)
+ /* end of file */
+ break;
+
+#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(56, 1, 0)
+ FfmpegCheckTag(decoder, input, format_context, audio_stream);
+#endif
+
+ if (packet.stream_index == audio_stream) {
+ cmd = ffmpeg_send_packet(decoder, input,
+ packet, codec_context,
+ av_stream,
+ *frame,
+ min_frame, audio_format.GetFrameSize(),
+ interleaved_buffer);
+ min_frame = 0;
+ } else
+ cmd = decoder_get_command(decoder);
+
+ av_free_packet(&packet);
+ }
#if LIBAVUTIL_VERSION_MAJOR >= 53
av_frame_free(&frame);
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
avcodec_free_frame(&frame);
#else
- av_freep(&frame);
+ av_free(frame);
#endif
- av_freep(&interleaved_buffer);
- avcodec_close(codec_context);
+ avcodec_close(&codec_context);
+}
+
+static void
+ffmpeg_decode(Decoder &decoder, InputStream &input)
+{
+ AVInputFormat *input_format = ffmpeg_probe(&decoder, input);
+ if (input_format == nullptr)
+ return;
+
+ FormatDebug(ffmpeg_domain, "detected input format '%s' (%s)",
+ input_format->name, input_format->long_name);
+
+ AvioStream stream(&decoder, input);
+ if (!stream.Open()) {
+ LogError(ffmpeg_domain, "Failed to open stream");
+ return;
+ }
+
+ AVFormatContext *format_context =
+ FfmpegOpenInput(stream.io, input.GetURI(), input_format);
+ if (format_context == nullptr) {
+ LogError(ffmpeg_domain, "Open failed");
+ return;
+ }
+
+ FfmpegDecode(decoder, input, *format_context);
avformat_close_input(&format_context);
}
-//no tag reading in ffmpeg, check if playable
+static bool
+FfmpegScanStream(AVFormatContext &format_context,
+ const struct tag_handler &handler, void *handler_ctx)
+{
+ const int find_result =
+ avformat_find_stream_info(&format_context, nullptr);
+ if (find_result < 0)
+ return false;
+
+ const int audio_stream = ffmpeg_find_audio_stream(format_context);
+ if (audio_stream < 0)
+ return false;
+
+ const AVStream &stream = *format_context.streams[audio_stream];
+ if (stream.duration != (int64_t)AV_NOPTS_VALUE)
+ tag_handler_invoke_duration(&handler, handler_ctx,
+ FromFfmpegTime(stream.duration,
+ stream.time_base));
+
+ FfmpegScanMetadata(format_context, audio_stream, handler, handler_ctx);
+
+ return true;
+}
+
static bool
ffmpeg_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx)
@@ -689,33 +648,14 @@ ffmpeg_scan_stream(InputStream &is,
if (!stream.Open())
return false;
- AVFormatContext *f = nullptr;
- if (mpd_ffmpeg_open_input(&f, stream.io, is.GetURI(),
- input_format) != 0)
- return false;
-
- const int find_result =
- avformat_find_stream_info(f, nullptr);
- if (find_result < 0) {
- avformat_close_input(&f);
+ AVFormatContext *f =
+ FfmpegOpenInput(stream.io, is.GetURI(), input_format);
+ if (f == nullptr)
return false;
- }
-
- if (f->duration != (int64_t)AV_NOPTS_VALUE) {
- const auto duration =
- SongTime::FromScale<uint64_t>(f->duration,
- AV_TIME_BASE);
- tag_handler_invoke_duration(handler, handler_ctx, duration);
- }
-
- ffmpeg_scan_dictionary(f->metadata, handler, handler_ctx);
- int idx = ffmpeg_find_audio_stream(f);
- if (idx >= 0)
- ffmpeg_scan_dictionary(f->streams[idx]->metadata,
- handler, handler_ctx);
+ bool result = FfmpegScanStream(*f, *handler, handler_ctx);
avformat_close_input(&f);
- return true;
+ return result;
}
/**
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.hxx b/src/decoder/plugins/FfmpegDecoderPlugin.hxx
index 0a3e78e4b..5f2710d10 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.hxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FfmpegIo.cxx b/src/decoder/plugins/FfmpegIo.cxx
new file mode 100644
index 000000000..08fddffa5
--- /dev/null
+++ b/src/decoder/plugins/FfmpegIo.cxx
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "FfmpegIo.hxx"
+#include "../DecoderAPI.hxx"
+#include "input/InputStream.hxx"
+#include "util/Error.hxx"
+
+AvioStream::~AvioStream()
+{
+ if (io != nullptr) {
+ av_free(io->buffer);
+ av_free(io);
+ }
+}
+
+inline int
+AvioStream::Read(void *dest, int size)
+{
+ return decoder_read(decoder, input, dest, size);
+}
+
+inline int64_t
+AvioStream::Seek(int64_t pos, int whence)
+{
+ switch (whence) {
+ case SEEK_SET:
+ break;
+
+ case SEEK_CUR:
+ pos += input.GetOffset();
+ break;
+
+ case SEEK_END:
+ if (!input.KnownSize())
+ return -1;
+
+ pos += input.GetSize();
+ break;
+
+ case AVSEEK_SIZE:
+ if (!input.KnownSize())
+ return -1;
+
+ return input.GetSize();
+
+ default:
+ return -1;
+ }
+
+ if (!input.LockSeek(pos, IgnoreError()))
+ return -1;
+
+ return input.GetOffset();
+}
+
+int
+AvioStream::_Read(void *opaque, uint8_t *buf, int size)
+{
+ AvioStream &stream = *(AvioStream *)opaque;
+
+ return stream.Read(buf, size);
+}
+
+int64_t
+AvioStream::_Seek(void *opaque, int64_t pos, int whence)
+{
+ AvioStream &stream = *(AvioStream *)opaque;
+
+ return stream.Seek(pos, whence);
+}
+
+bool
+AvioStream::Open()
+{
+ constexpr size_t BUFFER_SIZE = 8192;
+ auto buffer = (unsigned char *)av_malloc(BUFFER_SIZE);
+ if (buffer == nullptr)
+ return false;
+
+ io = avio_alloc_context(buffer, BUFFER_SIZE,
+ false, this,
+ _Read, nullptr,
+ input.IsSeekable() ? _Seek : nullptr);
+ /* If avio_alloc_context() fails, who frees the buffer? The
+ libavformat API documentation does not specify this, it
+ only says that AVIOContext.buffer must be freed in the end,
+ however no AVIOContext exists in that failure code path. */
+ return io != nullptr;
+}
diff --git a/src/decoder/plugins/FfmpegIo.hxx b/src/decoder/plugins/FfmpegIo.hxx
new file mode 100644
index 000000000..2deb7fd38
--- /dev/null
+++ b/src/decoder/plugins/FfmpegIo.hxx
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_IO_HXX
+#define MPD_FFMPEG_IO_HXX
+
+#include "check.h"
+
+extern "C" {
+#include "libavformat/avio.h"
+}
+
+#include <stdint.h>
+
+class InputStream;
+struct Decoder;
+
+struct AvioStream {
+ Decoder *const decoder;
+ InputStream &input;
+
+ AVIOContext *io;
+
+ AvioStream(Decoder *_decoder, InputStream &_input)
+ :decoder(_decoder), input(_input), io(nullptr) {}
+
+ ~AvioStream();
+
+ bool Open();
+
+private:
+ int Read(void *buffer, int size);
+ int64_t Seek(int64_t pos, int whence);
+
+ static int _Read(void *opaque, uint8_t *buf, int size);
+ static int64_t _Seek(void *opaque, int64_t pos, int whence);
+};
+
+#endif
diff --git a/src/decoder/plugins/FfmpegMetaData.cxx b/src/decoder/plugins/FfmpegMetaData.cxx
index a39466945..102d5669e 100644
--- a/src/decoder/plugins/FfmpegMetaData.cxx
+++ b/src/decoder/plugins/FfmpegMetaData.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,11 @@
#include "tag/TagTable.hxx"
#include "tag/TagHandler.hxx"
-static const struct tag_table ffmpeg_tags[] = {
+extern "C" {
+#include <libavutil/dict.h>
+}
+
+static constexpr struct tag_table ffmpeg_tags[] = {
{ "year", TAG_DATE },
{ "author-sort", TAG_ARTIST_SORT },
{ "album_artist", TAG_ALBUM_ARTIST },
@@ -36,9 +40,9 @@ static const struct tag_table ffmpeg_tags[] = {
};
static void
-ffmpeg_copy_metadata(TagType type,
- AVDictionary *m, const char *name,
- const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanTag(TagType type,
+ AVDictionary *m, const char *name,
+ const struct tag_handler *handler, void *handler_ctx)
{
AVDictionaryEntry *mt = nullptr;
@@ -48,8 +52,8 @@ ffmpeg_copy_metadata(TagType type,
}
static void
-ffmpeg_scan_pairs(AVDictionary *dict,
- const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanPairs(AVDictionary *dict,
+ const struct tag_handler *handler, void *handler_ctx)
{
AVDictionaryEntry *i = nullptr;
@@ -59,18 +63,20 @@ ffmpeg_scan_pairs(AVDictionary *dict,
}
void
-ffmpeg_scan_dictionary(AVDictionary *dict,
- const struct tag_handler *handler, void *handler_ctx)
+FfmpegScanDictionary(AVDictionary *dict,
+ const struct tag_handler *handler, void *handler_ctx)
{
- for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
- ffmpeg_copy_metadata(TagType(i), dict, tag_item_names[i],
- handler, handler_ctx);
+ if (handler->tag != nullptr) {
+ for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
+ FfmpegScanTag(TagType(i), dict, tag_item_names[i],
+ handler, handler_ctx);
- for (const struct tag_table *i = ffmpeg_tags;
- i->name != nullptr; ++i)
- ffmpeg_copy_metadata(i->type, dict, i->name,
- handler, handler_ctx);
+ for (const struct tag_table *i = ffmpeg_tags;
+ i->name != nullptr; ++i)
+ FfmpegScanTag(i->type, dict, i->name,
+ handler, handler_ctx);
+ }
if (handler->pair != nullptr)
- ffmpeg_scan_pairs(dict, handler, handler_ctx);
+ FfmpegScanPairs(dict, handler, handler_ctx);
}
diff --git a/src/decoder/plugins/FfmpegMetaData.hxx b/src/decoder/plugins/FfmpegMetaData.hxx
index 5eb41db68..bdf5dd613 100644
--- a/src/decoder/plugins/FfmpegMetaData.hxx
+++ b/src/decoder/plugins/FfmpegMetaData.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,19 +20,11 @@
#ifndef MPD_FFMPEG_METADATA_HXX
#define MPD_FFMPEG_METADATA_HXX
-extern "C" {
-#include <libavutil/dict.h>
-}
-
-/* suppress the ffmpeg compatibility macro */
-#ifdef SampleFormat
-#undef SampleFormat
-#endif
-
+struct AVDictionary;
struct tag_handler;
void
-ffmpeg_scan_dictionary(AVDictionary *dict,
- const tag_handler *handler, void *handler_ctx);
+FfmpegScanDictionary(AVDictionary *dict,
+ const tag_handler *handler, void *handler_ctx);
#endif
diff --git a/src/decoder/plugins/FlacCommon.cxx b/src/decoder/plugins/FlacCommon.cxx
index e86f85569..e68871b1d 100644
--- a/src/decoder/plugins/FlacCommon.cxx
+++ b/src/decoder/plugins/FlacCommon.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacCommon.hxx b/src/decoder/plugins/FlacCommon.hxx
index 34ce0a3fc..e6c800cb9 100644
--- a/src/decoder/plugins/FlacCommon.hxx
+++ b/src/decoder/plugins/FlacCommon.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx
index eea813401..410af9267 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.cxx
+++ b/src/decoder/plugins/FlacDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "FlacMetadata.hxx"
#include "OggCodec.hxx"
#include "fs/Path.hxx"
+#include "fs/NarrowPath.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -84,7 +85,7 @@ flac_scan_file(Path path_fs,
const struct tag_handler *handler, void *handler_ctx)
{
FlacMetadataChain chain;
- if (!chain.Read(path_fs.c_str())) {
+ if (!chain.Read(NarrowPath(path_fs))) {
FormatDebug(flac_domain,
"Failed to read FLAC tags: %s",
chain.GetStatusString());
@@ -291,7 +292,7 @@ flac_decode(Decoder &decoder, InputStream &input_stream)
}
static bool
-oggflac_init(gcc_unused const config_param &param)
+oggflac_init(gcc_unused const ConfigBlock &block)
{
return !!FLAC_API_SUPPORTS_OGG_FLAC;
}
@@ -301,7 +302,7 @@ oggflac_scan_file(Path path_fs,
const struct tag_handler *handler, void *handler_ctx)
{
FlacMetadataChain chain;
- if (!chain.ReadOgg(path_fs.c_str())) {
+ if (!chain.ReadOgg(NarrowPath(path_fs))) {
FormatDebug(flac_domain,
"Failed to read OggFLAC tags: %s",
chain.GetStatusString());
diff --git a/src/decoder/plugins/FlacDecoderPlugin.h b/src/decoder/plugins/FlacDecoderPlugin.h
index fcdecf869..fa92ff32b 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.h
+++ b/src/decoder/plugins/FlacDecoderPlugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacDomain.cxx b/src/decoder/plugins/FlacDomain.cxx
index fc5cc5498..591da3ee2 100644
--- a/src/decoder/plugins/FlacDomain.cxx
+++ b/src/decoder/plugins/FlacDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacDomain.hxx b/src/decoder/plugins/FlacDomain.hxx
index a06c6c6b4..a27b91d40 100644
--- a/src/decoder/plugins/FlacDomain.hxx
+++ b/src/decoder/plugins/FlacDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacIOHandle.cxx b/src/decoder/plugins/FlacIOHandle.cxx
index 0dd895798..b85efe6c8 100644
--- a/src/decoder/plugins/FlacIOHandle.cxx
+++ b/src/decoder/plugins/FlacIOHandle.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacIOHandle.hxx b/src/decoder/plugins/FlacIOHandle.hxx
index 90acc66af..e840528b1 100644
--- a/src/decoder/plugins/FlacIOHandle.hxx
+++ b/src/decoder/plugins/FlacIOHandle.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacInput.cxx b/src/decoder/plugins/FlacInput.cxx
index 5b4c3104d..91f54b807 100644
--- a/src/decoder/plugins/FlacInput.cxx
+++ b/src/decoder/plugins/FlacInput.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacInput.hxx b/src/decoder/plugins/FlacInput.hxx
index 427abccb4..f55b2ebbd 100644
--- a/src/decoder/plugins/FlacInput.hxx
+++ b/src/decoder/plugins/FlacInput.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacMetadata.cxx b/src/decoder/plugins/FlacMetadata.cxx
index 03e276dce..14a9fe294 100644
--- a/src/decoder/plugins/FlacMetadata.cxx
+++ b/src/decoder/plugins/FlacMetadata.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
#include "tag/MixRamp.hxx"
#include "ReplayGainInfo.hxx"
#include "util/ASCII.hxx"
-#include "util/SplitString.hxx"
+#include "util/DivideString.hxx"
bool
flac_parse_replay_gain(ReplayGainInfo &rgi,
@@ -97,7 +97,7 @@ flac_scan_comment(const FLAC__StreamMetadata_VorbisComment_Entry *entry,
{
if (handler->pair != nullptr) {
const char *comment = (const char *)entry->entry;
- const SplitString split(comment, '=');
+ const DivideString split(comment, '=');
if (split.IsDefined() && !split.IsEmpty())
tag_handler_invoke_pair(handler, handler_ctx,
split.GetFirst(),
diff --git a/src/decoder/plugins/FlacMetadata.hxx b/src/decoder/plugins/FlacMetadata.hxx
index d791fa34e..4805f8042 100644
--- a/src/decoder/plugins/FlacMetadata.hxx
+++ b/src/decoder/plugins/FlacMetadata.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacPcm.cxx b/src/decoder/plugins/FlacPcm.cxx
index 311500f26..7ba4a6ad3 100644
--- a/src/decoder/plugins/FlacPcm.cxx
+++ b/src/decoder/plugins/FlacPcm.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FlacPcm.hxx b/src/decoder/plugins/FlacPcm.hxx
index 30c318725..51233a689 100644
--- a/src/decoder/plugins/FlacPcm.hxx
+++ b/src/decoder/plugins/FlacPcm.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
index f19ac5bf4..2b4967b95 100644
--- a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
+++ b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,7 @@ static unsigned sample_rate;
static const char *soundfont_path;
/**
- * Convert a fluidsynth log level to a GLib log level.
+ * Convert a fluidsynth log level to a MPD log level.
*/
static LogLevel
fluidsynth_level_to_mpd(enum fluid_log_level level)
@@ -61,7 +61,7 @@ fluidsynth_level_to_mpd(enum fluid_log_level level)
}
/**
- * The fluidsynth logging callback. It forwards messages to the GLib
+ * The fluidsynth logging callback. It forwards messages to the MPD
* logging library.
*/
static void
@@ -73,17 +73,17 @@ fluidsynth_mpd_log_function(int level, char *message, gcc_unused void *data)
}
static bool
-fluidsynth_init(const config_param &param)
+fluidsynth_init(const ConfigBlock &block)
{
Error error;
- sample_rate = param.GetBlockValue("sample_rate", 48000u);
+ sample_rate = block.GetBlockValue("sample_rate", 48000u);
if (!audio_check_sample_rate(sample_rate, error)) {
LogError(error);
return false;
}
- soundfont_path = param.GetBlockValue("soundfont",
+ soundfont_path = block.GetBlockValue("soundfont",
"/usr/share/sounds/sf2/FluidR3_GM.sf2");
fluid_set_log_function(LAST_LOG_LEVEL,
diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.hxx b/src/decoder/plugins/FluidsynthDecoderPlugin.hxx
index cd8ec2d62..9845fd72e 100644
--- a/src/decoder/plugins/FluidsynthDecoderPlugin.hxx
+++ b/src/decoder/plugins/FluidsynthDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index b47e9ea66..cdaa68dcf 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,11 @@
#include "config.h"
#include "GmeDecoderPlugin.hxx"
#include "../DecoderAPI.hxx"
+#include "config/Block.cxx"
#include "CheckAudioFormat.hxx"
#include "tag/TagHandler.hxx"
#include "fs/Path.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/Alloc.hxx"
#include "util/FormatString.hxx"
#include "util/UriUtil.hxx"
@@ -30,7 +32,6 @@
#include "util/Domain.hxx"
#include "Log.hxx"
-#include <glib.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
@@ -47,65 +48,59 @@ static constexpr unsigned GME_BUFFER_FRAMES = 2048;
static constexpr unsigned GME_BUFFER_SAMPLES =
GME_BUFFER_FRAMES * GME_CHANNELS;
-/**
- * returns the file path stripped of any /tune_xxx.* subtune
- * suffix
- */
-static char *
-get_container_name(Path path_fs)
+struct GmeContainerPath {
+ AllocatedPath path;
+ unsigned track;
+};
+
+#if GME_VERSION >= 0x000600
+static int gme_accuracy;
+#endif
+
+static bool
+gme_plugin_init(gcc_unused const ConfigBlock &block)
{
- const char *subtune_suffix = uri_get_suffix(path_fs.c_str());
- char *path_container = xstrdup(path_fs.c_str());
-
- char pat[64];
- snprintf(pat, sizeof(pat), "%s%s",
- "*/" SUBTUNE_PREFIX "???.",
- subtune_suffix);
- GPatternSpec *path_with_subtune = g_pattern_spec_new(pat);
- if (!g_pattern_match(path_with_subtune,
- strlen(path_container), path_container, nullptr)) {
- g_pattern_spec_free(path_with_subtune);
- return path_container;
- }
+#if GME_VERSION >= 0x000600
+ auto accuracy = block.GetBlockParam("accuracy");
+ gme_accuracy = accuracy != nullptr
+ ? (int)accuracy->GetBoolValue()
+ : -1;
+#endif
- char *ptr = g_strrstr(path_container, "/" SUBTUNE_PREFIX);
- if (ptr != nullptr)
- *ptr='\0';
+ return true;
+}
+
+gcc_pure
+static unsigned
+ParseSubtuneName(const char *base)
+{
+ if (memcmp(base, SUBTUNE_PREFIX, sizeof(SUBTUNE_PREFIX) - 1) != 0)
+ return 0;
+
+ base += sizeof(SUBTUNE_PREFIX) - 1;
- g_pattern_spec_free(path_with_subtune);
- return path_container;
+ char *endptr;
+ auto track = strtoul(base, &endptr, 10);
+ if (endptr == base || *endptr != '.')
+ return 0;
+
+ return track;
}
/**
- * returns tune number from file.nsf/tune_xxx.* style path or 0 if no subtune
- * is appended.
+ * returns the file path stripped of any /tune_xxx.* subtune suffix
+ * and the track number (or 0 if no "tune_xxx" suffix is present).
*/
-static int
-get_song_num(Path path_fs)
+static GmeContainerPath
+ParseContainerPath(Path path_fs)
{
- const char *subtune_suffix = uri_get_suffix(path_fs.c_str());
+ const Path base = path_fs.GetBase();
+ unsigned track;
+ if (base.IsNull() ||
+ (track = ParseSubtuneName(base.c_str())) < 1)
+ return { AllocatedPath(path_fs), 0 };
- char pat[64];
- snprintf(pat, sizeof(pat), "%s%s",
- "*/" SUBTUNE_PREFIX "???.",
- subtune_suffix);
- GPatternSpec *path_with_subtune = g_pattern_spec_new(pat);
-
- if (g_pattern_match(path_with_subtune,
- path_fs.length(), path_fs.data(), nullptr)) {
- char *sub = g_strrstr(path_fs.c_str(), "/" SUBTUNE_PREFIX);
- g_pattern_spec_free(path_with_subtune);
- if (!sub)
- return 0;
-
- sub += strlen("/" SUBTUNE_PREFIX);
- int song_num = strtol(sub, nullptr, 10);
-
- return song_num - 1;
- } else {
- g_pattern_spec_free(path_with_subtune);
- return 0;
- }
+ return { path_fs.GetDirectoryName(), track - 1 };
}
static char *
@@ -136,20 +131,26 @@ gme_container_scan(Path path_fs, const unsigned int tnum)
static void
gme_file_decode(Decoder &decoder, Path path_fs)
{
- char *path_container = get_container_name(path_fs);
+ const auto container = ParseContainerPath(path_fs);
Music_Emu *emu;
const char *gme_err =
- gme_open_file(path_container, &emu, GME_SAMPLE_RATE);
- free(path_container);
+ gme_open_file(container.path.c_str(), &emu, GME_SAMPLE_RATE);
if (gme_err != nullptr) {
LogWarning(gme_domain, gme_err);
return;
}
+ FormatDebug(gme_domain, "emulator type '%s'\n",
+ gme_type_system(gme_type(emu)));
+
+#if GME_VERSION >= 0x000600
+ if (gme_accuracy >= 0)
+ gme_enable_accuracy(emu, gme_accuracy);
+#endif
+
gme_info_t *ti;
- const int song_num = get_song_num(path_fs);
- gme_err = gme_track_info(emu, &ti, song_num);
+ gme_err = gme_track_info(emu, &ti, container.track);
if (gme_err != nullptr) {
LogWarning(gme_domain, gme_err);
gme_delete(emu);
@@ -177,7 +178,7 @@ gme_file_decode(Decoder &decoder, Path path_fs)
decoder_initialized(decoder, audio_format, true, song_len);
- gme_err = gme_start_track(emu, song_num);
+ gme_err = gme_start_track(emu, container.track);
if (gme_err != nullptr)
LogWarning(gme_domain, gme_err);
@@ -212,72 +213,85 @@ gme_file_decode(Decoder &decoder, Path path_fs)
gme_delete(emu);
}
-static bool
-gme_scan_file(Path path_fs,
- const struct tag_handler *handler, void *handler_ctx)
+static void
+ScanGmeInfo(const gme_info_t &info, unsigned song_num, int track_count,
+ const struct tag_handler *handler, void *handler_ctx)
{
- char *path_container = get_container_name(path_fs);
-
- Music_Emu *emu;
- const char *gme_err =
- gme_open_file(path_container, &emu, GME_SAMPLE_RATE);
- free(path_container);
- if (gme_err != nullptr) {
- LogWarning(gme_domain, gme_err);
- return false;
- }
-
- const int song_num = get_song_num(path_fs);
-
- gme_info_t *ti;
- gme_err = gme_track_info(emu, &ti, song_num);
- if (gme_err != nullptr) {
- LogWarning(gme_domain, gme_err);
- gme_delete(emu);
- return false;
- }
-
- assert(ti != nullptr);
-
- if (ti->play_length > 0)
+ if (info.play_length > 0)
tag_handler_invoke_duration(handler, handler_ctx,
- SongTime::FromMS(ti->play_length));
+ SongTime::FromMS(info.play_length));
- if (ti->song != nullptr) {
- if (gme_track_count(emu) > 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 (%d/%d)",
- ti->song, song_num + 1,
- gme_track_count(emu));
+ "%s (%u/%d)",
+ info.song, song_num + 1,
+ track_count);
tag_handler_invoke_tag(handler, handler_ctx,
TAG_TITLE, tag_title);
} else
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_TITLE, ti->song);
+ TAG_TITLE, info.song);
}
- if (ti->author != nullptr)
+ if (info.author != nullptr)
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_ARTIST, ti->author);
+ TAG_ARTIST, info.author);
- if (ti->game != nullptr)
+ if (info.game != nullptr)
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_ALBUM, ti->game);
+ TAG_ALBUM, info.game);
- if (ti->comment != nullptr)
+ if (info.comment != nullptr)
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_COMMENT, ti->comment);
+ TAG_COMMENT, info.comment);
- if (ti->copyright != nullptr)
+ if (info.copyright != nullptr)
tag_handler_invoke_tag(handler, handler_ctx,
- TAG_DATE, ti->copyright);
+ TAG_DATE, info.copyright);
+}
+
+static bool
+ScanMusicEmu(Music_Emu *emu, unsigned song_num,
+ const struct tag_handler *handler, void *handler_ctx)
+{
+ gme_info_t *ti;
+ const char *gme_err = gme_track_info(emu, &ti, song_num);
+ if (gme_err != nullptr) {
+ LogWarning(gme_domain, gme_err);
+ return false;
+ }
+
+ assert(ti != nullptr);
+
+ ScanGmeInfo(*ti, song_num, gme_track_count(emu),
+ handler, handler_ctx);
gme_free_info(ti);
+ return true;
+}
+
+static bool
+gme_scan_file(Path path_fs,
+ const struct tag_handler *handler, void *handler_ctx)
+{
+ const auto container = ParseContainerPath(path_fs);
+
+ Music_Emu *emu;
+ const char *gme_err =
+ gme_open_file(container.path.c_str(), &emu, GME_SAMPLE_RATE);
+ if (gme_err != nullptr) {
+ LogWarning(gme_domain, gme_err);
+ return false;
+ }
+
+ const bool result = ScanMusicEmu(emu, container.track, handler, handler_ctx);
+
gme_delete(emu);
- return true;
+ return result;
}
static const char *const gme_suffixes[] = {
@@ -289,7 +303,7 @@ static const char *const gme_suffixes[] = {
extern const struct DecoderPlugin gme_decoder_plugin;
const struct DecoderPlugin gme_decoder_plugin = {
"gme",
- nullptr,
+ gme_plugin_init,
nullptr,
nullptr,
gme_file_decode,
diff --git a/src/decoder/plugins/GmeDecoderPlugin.hxx b/src/decoder/plugins/GmeDecoderPlugin.hxx
index f4885b6e4..07f78d9e2 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.hxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index de6c9b127..9baa6fb9c 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@
#include <mad.h>
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
#include <id3tag.h>
#endif
@@ -107,9 +107,9 @@ mad_fixed_to_24_buffer(int32_t *dest, const struct mad_synth *synth,
}
static bool
-mp3_plugin_init(gcc_unused const config_param &param)
+mp3_plugin_init(gcc_unused const ConfigBlock &block)
{
- gapless_playback = config_get_bool(CONF_GAPLESS_MP3_PLAYBACK,
+ gapless_playback = config_get_bool(ConfigOption::GAPLESS_MP3_PLAYBACK,
DEFAULT_GAPLESS_MP3_PLAYBACK);
return true;
}
@@ -167,6 +167,15 @@ struct MadDecoder {
bool DecodeFirstFrame(Tag **tag);
+ void AllocateBuffers() {
+ assert(max_frames > 0);
+ assert(frame_offsets == nullptr);
+ assert(times == nullptr);
+
+ frame_offsets = new long[max_frames];
+ times = new mad_timer_t[max_frames];
+ }
+
gcc_pure
long TimeToFrame(SongTime t) const;
@@ -251,7 +260,7 @@ MadDecoder::FillBuffer()
return true;
}
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
static bool
parse_id3_replay_gain_info(ReplayGainInfo &rgi,
struct id3_tag *tag)
@@ -285,7 +294,7 @@ parse_id3_replay_gain_info(ReplayGainInfo &rgi,
}
#endif
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
gcc_pure
static MixRampInfo
parse_id3_mixramp(struct id3_tag *tag)
@@ -317,7 +326,7 @@ parse_id3_mixramp(struct id3_tag *tag)
inline void
MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
{
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
id3_byte_t *allocated = nullptr;
const id3_length_t count = stream.bufend - stream.this_frame;
@@ -369,7 +378,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
id3_tag_delete(id3_tag);
delete[] allocated;
-#else /* !HAVE_ID3TAG */
+#else /* !ENABLE_ID3TAG */
(void)mpd_tag;
/* This code is enabled when libid3tag is disabled. Instead
@@ -386,7 +395,7 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
#endif
}
-#ifndef HAVE_ID3TAG
+#ifndef ENABLE_ID3TAG
/**
* This function emulates libid3tag when it is disabled. Instead of
* doing a real analyzation of the frame, it just checks whether the
@@ -402,7 +411,7 @@ id3_tag_query(const void *p0, size_t length)
? (p[8] << 7) + p[9] + 10
: 0;
}
-#endif /* !HAVE_ID3TAG */
+#endif /* !ENABLE_ID3TAG */
static enum mp3_action
RecoverFrameError(struct mad_stream &stream)
@@ -504,10 +513,10 @@ struct xing {
enum xing_magic magic; /* header magic */
};
-static const unsigned XING_FRAMES = 1;
-static const unsigned XING_BYTES = 2;
-static const unsigned XING_TOC = 4;
-static const unsigned XING_SCALE = 8;
+static constexpr unsigned XING_FRAMES = 1;
+static constexpr unsigned XING_BYTES = 2;
+static constexpr unsigned XING_TOC = 4;
+static constexpr unsigned XING_SCALE = 8;
struct lame_version {
unsigned major;
@@ -819,9 +828,6 @@ MadDecoder::DecodeFirstFrame(Tag **tag)
return false;
}
- frame_offsets = new long[max_frames];
- times = new mad_timer_t[max_frames];
-
return true;
}
@@ -1049,6 +1055,8 @@ mp3_decode(Decoder &decoder, InputStream &input_stream)
return;
}
+ data.AllocateBuffers();
+
Error error;
AudioFormat audio_format;
if (!audio_format_init_checked(audio_format,
diff --git a/src/decoder/plugins/MadDecoderPlugin.hxx b/src/decoder/plugins/MadDecoderPlugin.hxx
index eb2a10d6f..c06f7341a 100644
--- a/src/decoder/plugins/MadDecoderPlugin.hxx
+++ b/src/decoder/plugins/MadDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/MikmodDecoderPlugin.cxx b/src/decoder/plugins/MikmodDecoderPlugin.cxx
index 85633f1fc..135bae15a 100644
--- a/src/decoder/plugins/MikmodDecoderPlugin.cxx
+++ b/src/decoder/plugins/MikmodDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -109,15 +109,15 @@ static bool mikmod_loop;
static unsigned mikmod_sample_rate;
static bool
-mikmod_decoder_init(const config_param &param)
+mikmod_decoder_init(const ConfigBlock &block)
{
static char params[] = "";
- mikmod_loop = param.GetBlockValue("loop", false);
- mikmod_sample_rate = param.GetBlockValue("sample_rate", 44100u);
+ mikmod_loop = block.GetBlockValue("loop", false);
+ mikmod_sample_rate = block.GetBlockValue("sample_rate", 44100u);
if (!audio_valid_sample_rate(mikmod_sample_rate))
FormatFatalError("Invalid sample rate in line %d: %u",
- param.line, mikmod_sample_rate);
+ block.line, mikmod_sample_rate);
md_device = 0;
md_reverb = 0;
diff --git a/src/decoder/plugins/MikmodDecoderPlugin.hxx b/src/decoder/plugins/MikmodDecoderPlugin.hxx
index 27ba2a823..508c7ae28 100644
--- a/src/decoder/plugins/MikmodDecoderPlugin.hxx
+++ b/src/decoder/plugins/MikmodDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/ModplugDecoderPlugin.cxx b/src/decoder/plugins/ModplugDecoderPlugin.cxx
index 3e0a41550..153392929 100644
--- a/src/decoder/plugins/ModplugDecoderPlugin.cxx
+++ b/src/decoder/plugins/ModplugDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,12 +41,12 @@ static constexpr offset_type MODPLUG_FILE_LIMIT = 100 * 1024 * 1024;
static int modplug_loop_count;
static bool
-modplug_decoder_init(const config_param &param)
+modplug_decoder_init(const ConfigBlock &block)
{
- modplug_loop_count = param.GetBlockValue("loop_count", 0);
+ modplug_loop_count = block.GetBlockValue("loop_count", 0);
if (modplug_loop_count < -1)
FormatFatalError("Invalid loop count in line %d: %i",
- param.line, modplug_loop_count);
+ block.line, modplug_loop_count);
return true;
}
diff --git a/src/decoder/plugins/ModplugDecoderPlugin.hxx b/src/decoder/plugins/ModplugDecoderPlugin.hxx
index 08f2ecb12..5d20afc7f 100644
--- a/src/decoder/plugins/ModplugDecoderPlugin.hxx
+++ b/src/decoder/plugins/ModplugDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.cxx b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
index 391b5d691..e1ddd05f0 100644
--- a/src/decoder/plugins/MpcdecDecoderPlugin.cxx
+++ b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -134,8 +134,6 @@ mpc_to_mpd_buffer(MpcdecSampleTraits::pointer_type dest,
static void
mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
{
- MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
-
mpc_decoder_data data(is, &mpd_decoder);
mpc_reader reader;
@@ -195,8 +193,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
decoder_seek_error(mpd_decoder);
}
- mpc_uint32_t vbr_update_bits = 0;
-
+ MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
mpc_frame_info frame;
frame.buffer = (MPC_SAMPLE_FORMAT *)sample_buffer;
mpc_status status = mpc_demux_decode(demux, &frame);
@@ -215,8 +212,8 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
MpcdecSampleTraits::value_type chunk[ARRAY_SIZE(sample_buffer)];
mpc_to_mpd_buffer(chunk, sample_buffer, ret);
- long bit_rate = vbr_update_bits * audio_format.sample_rate
- / 1152 / 1000;
+ long bit_rate = unsigned(frame.bits) * audio_format.sample_rate
+ / (1000 * frame.samples);
cmd = decoder_data(mpd_decoder, is,
chunk, ret * sizeof(chunk[0]),
diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.hxx b/src/decoder/plugins/MpcdecDecoderPlugin.hxx
index 7f71311fa..86216b4c2 100644
--- a/src/decoder/plugins/MpcdecDecoderPlugin.hxx
+++ b/src/decoder/plugins/MpcdecDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/Mpg123DecoderPlugin.cxx b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
index 166529a4d..43c0c868f 100644
--- a/src/decoder/plugins/Mpg123DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include "fs/Path.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
+#include "util/StringView.hxx"
#include "Log.hxx"
#include <mpg123.h>
@@ -37,7 +38,7 @@
static constexpr Domain mpg123_domain("mpg123");
static bool
-mpd_mpg123_init(gcc_unused const config_param &param)
+mpd_mpg123_init(gcc_unused const ConfigBlock &block)
{
mpg123_init();
@@ -111,7 +112,7 @@ AddTagItem(TagBuilder &tag, TagType type, const mpg123_string &s)
assert(s.size >= s.fill);
assert(s.fill > 0);
- tag.AddItem(type, s.p, s.fill - 1);
+ tag.AddItem(type, {s.p, s.fill - 1});
}
static void
diff --git a/src/decoder/plugins/Mpg123DecoderPlugin.hxx b/src/decoder/plugins/Mpg123DecoderPlugin.hxx
index fd089c6a4..e09e6f956 100644
--- a/src/decoder/plugins/Mpg123DecoderPlugin.hxx
+++ b/src/decoder/plugins/Mpg123DecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggCodec.cxx b/src/decoder/plugins/OggCodec.cxx
index c7f39586e..cd35609aa 100644
--- a/src/decoder/plugins/OggCodec.cxx
+++ b/src/decoder/plugins/OggCodec.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggCodec.hxx b/src/decoder/plugins/OggCodec.hxx
index 3b096561c..a47ae566e 100644
--- a/src/decoder/plugins/OggCodec.hxx
+++ b/src/decoder/plugins/OggCodec.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggFind.cxx b/src/decoder/plugins/OggFind.cxx
index 978e1d7cf..b452c0a00 100644
--- a/src/decoder/plugins/OggFind.cxx
+++ b/src/decoder/plugins/OggFind.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggFind.hxx b/src/decoder/plugins/OggFind.hxx
index 2aa4f6c06..47a80a232 100644
--- a/src/decoder/plugins/OggFind.hxx
+++ b/src/decoder/plugins/OggFind.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggSyncState.hxx b/src/decoder/plugins/OggSyncState.hxx
index 024902fff..1641b4aa1 100644
--- a/src/decoder/plugins/OggSyncState.hxx
+++ b/src/decoder/plugins/OggSyncState.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggUtil.cxx b/src/decoder/plugins/OggUtil.cxx
index 6341b0008..a7812238d 100644
--- a/src/decoder/plugins/OggUtil.cxx
+++ b/src/decoder/plugins/OggUtil.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OggUtil.hxx b/src/decoder/plugins/OggUtil.hxx
index 94c380ef4..b9bfe17de 100644
--- a/src/decoder/plugins/OggUtil.hxx
+++ b/src/decoder/plugins/OggUtil.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index e14827e38..0d03566a7 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -61,7 +61,7 @@ IsOpusTags(const ogg_packet &packet)
}
static bool
-mpd_opus_init(gcc_unused const config_param &param)
+mpd_opus_init(gcc_unused const ConfigBlock &block)
{
LogDebug(opus_domain, opus_get_version_string());
diff --git a/src/decoder/plugins/OpusDecoderPlugin.h b/src/decoder/plugins/OpusDecoderPlugin.h
index 260dab99a..c6a8e921d 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.h
+++ b/src/decoder/plugins/OpusDecoderPlugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusDomain.cxx b/src/decoder/plugins/OpusDomain.cxx
index 1efd64a48..d65c9c14a 100644
--- a/src/decoder/plugins/OpusDomain.cxx
+++ b/src/decoder/plugins/OpusDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusDomain.hxx b/src/decoder/plugins/OpusDomain.hxx
index fb19e0301..813bc097c 100644
--- a/src/decoder/plugins/OpusDomain.hxx
+++ b/src/decoder/plugins/OpusDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusHead.cxx b/src/decoder/plugins/OpusHead.cxx
index bfa41d618..3357fdddb 100644
--- a/src/decoder/plugins/OpusHead.cxx
+++ b/src/decoder/plugins/OpusHead.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusHead.hxx b/src/decoder/plugins/OpusHead.hxx
index c478d8d90..b04386ff8 100644
--- a/src/decoder/plugins/OpusHead.hxx
+++ b/src/decoder/plugins/OpusHead.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusReader.hxx b/src/decoder/plugins/OpusReader.hxx
index c5b8e9107..c449a88d1 100644
--- a/src/decoder/plugins/OpusReader.hxx
+++ b/src/decoder/plugins/OpusReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx
index aff5479c0..a77a0f71a 100644
--- a/src/decoder/plugins/OpusTags.cxx
+++ b/src/decoder/plugins/OpusTags.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/OpusTags.hxx b/src/decoder/plugins/OpusTags.hxx
index be3ac3a8d..57c46882e 100644
--- a/src/decoder/plugins/OpusTags.hxx
+++ b/src/decoder/plugins/OpusTags.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/PcmDecoderPlugin.cxx b/src/decoder/plugins/PcmDecoderPlugin.cxx
index c07a7b9b1..d9a8110de 100644
--- a/src/decoder/plugins/PcmDecoderPlugin.cxx
+++ b/src/decoder/plugins/PcmDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/PcmDecoderPlugin.hxx b/src/decoder/plugins/PcmDecoderPlugin.hxx
index 3582e5856..0fd0e6b26 100644
--- a/src/decoder/plugins/PcmDecoderPlugin.hxx
+++ b/src/decoder/plugins/PcmDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index 8435f095f..0d17e98c4 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,87 +22,64 @@
#include "../DecoderAPI.hxx"
#include "tag/TagHandler.hxx"
#include "fs/Path.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/FormatString.hxx"
#include "util/Domain.hxx"
+#include "util/Error.hxx"
#include "system/ByteOrder.hxx"
+#include "system/FatalError.hxx"
#include "Log.hxx"
-#include <errno.h>
-#include <stdlib.h>
#include <string.h>
-#include <glib.h>
#include <sidplay/sidplay2.h>
#include <sidplay/builders/resid.h>
#include <sidplay/utils/SidTuneMod.h>
+#include <sidplay/utils/SidDatabase.h>
#define SUBTUNE_PREFIX "tune_"
static constexpr Domain sidplay_domain("sidplay");
-static GPatternSpec *path_with_subtune;
-static const char *songlength_file;
-static GKeyFile *songlength_database;
+static SidDatabase *songlength_database;
static bool all_files_are_containers;
static unsigned default_songlength;
static bool filter_setting;
-static GKeyFile *
-sidplay_load_songlength_db(const char *path)
+static SidDatabase *
+sidplay_load_songlength_db(const Path path)
{
- GError *error = nullptr;
- gchar *data;
- gsize size;
-
- if (!g_file_get_contents(path, &data, &size, &error)) {
+ SidDatabase *db = new SidDatabase();
+ if (db->open(path.c_str()) < 0) {
FormatError(sidplay_domain,
"unable to read songlengths file %s: %s",
- path, error->message);
- g_error_free(error);
- return nullptr;
- }
-
- /* replace any ; comment characters with # */
- for (gsize i = 0; i < size; i++)
- if (data[i] == ';')
- data[i] = '#';
-
- GKeyFile *db = g_key_file_new();
- bool success = g_key_file_load_from_data(db, data, size,
- G_KEY_FILE_NONE, &error);
- g_free(data);
- if (!success) {
- FormatError(sidplay_domain,
- "unable to parse songlengths file %s: %s",
- path, error->message);
- g_error_free(error);
- g_key_file_free(db);
+ path.c_str(), db->error());
+ delete db;
return nullptr;
}
- g_key_file_set_list_separator(db, ' ');
return db;
}
static bool
-sidplay_init(const config_param &param)
+sidplay_init(const ConfigBlock &block)
{
/* read the songlengths database file */
- songlength_file = param.GetBlockValue("songlength_database");
- if (songlength_file != nullptr)
- songlength_database = sidplay_load_songlength_db(songlength_file);
+ Error error;
+ const auto database_path = block.GetBlockPath("songlength_database", error);
+ if (!database_path.IsNull())
+ songlength_database = sidplay_load_songlength_db(database_path);
+ else if (error.IsDefined())
+ FatalError(error);
- default_songlength = param.GetBlockValue("default_songlength", 0u);
+ default_songlength = block.GetBlockValue("default_songlength", 0u);
all_files_are_containers =
- param.GetBlockValue("all_files_are_containers", true);
+ block.GetBlockValue("all_files_are_containers", true);
- path_with_subtune=g_pattern_spec_new(
- "*/" SUBTUNE_PREFIX "???.sid");
-
- filter_setting = param.GetBlockValue("filter", true);
+ filter_setting = block.GetBlockValue("filter", true);
return true;
}
@@ -110,96 +87,61 @@ sidplay_init(const config_param &param)
static void
sidplay_finish()
{
- g_pattern_spec_free(path_with_subtune);
-
- if(songlength_database)
- g_key_file_free(songlength_database);
+ delete songlength_database;
}
-/**
- * returns the file path stripped of any /tune_xxx.sid subtune
- * suffix
- */
-static char *
-get_container_name(Path path_fs)
+struct SidplayContainerPath {
+ AllocatedPath path;
+ unsigned track;
+};
+
+gcc_pure
+static unsigned
+ParseSubtuneName(const char *base)
{
- char *path_container = strdup(path_fs.c_str());
+ if (memcmp(base, SUBTUNE_PREFIX, sizeof(SUBTUNE_PREFIX) - 1) != 0)
+ return 0;
- if(!g_pattern_match(path_with_subtune,
- strlen(path_container), path_container, nullptr))
- return path_container;
+ base += sizeof(SUBTUNE_PREFIX) - 1;
- char *ptr=g_strrstr(path_container, "/" SUBTUNE_PREFIX);
- if(ptr) *ptr='\0';
+ char *endptr;
+ auto track = strtoul(base, &endptr, 10);
+ if (endptr == base || *endptr != '.')
+ return 0;
- return path_container;
+ return track;
}
/**
- * returns tune number from file.sid/tune_xxx.sid style path or 1 if
- * no subtune is appended
+ * returns the file path stripped of any /tune_xxx.* subtune suffix
+ * and the track number (or 1 if no "tune_xxx" suffix is present).
*/
-static unsigned
-get_song_num(const char *path_fs)
+static SidplayContainerPath
+ParseContainerPath(Path path_fs)
{
- if(g_pattern_match(path_with_subtune,
- strlen(path_fs), path_fs, nullptr)) {
- char *sub=g_strrstr(path_fs, "/" SUBTUNE_PREFIX);
- if(!sub) return 1;
-
- sub+=strlen("/" SUBTUNE_PREFIX);
- int song_num=strtol(sub, nullptr, 10);
-
- if (errno == EINVAL)
- return 1;
- else
- return song_num;
- } else
- return 1;
+ const Path base = path_fs.GetBase();
+ unsigned track;
+ if (base.IsNull() ||
+ (track = ParseSubtuneName(base.c_str())) < 1)
+ return { AllocatedPath(path_fs), 1 };
+
+ return { path_fs.GetDirectoryName(), track };
}
/* get the song length in seconds */
static SignedSongTime
-get_song_length(Path path_fs)
+get_song_length(SidTuneMod &tune)
{
+ assert(tune);
+
if (songlength_database == nullptr)
return SignedSongTime::Negative();
- char *sid_file = get_container_name(path_fs);
- SidTuneMod tune(sid_file);
- free(sid_file);
- if(!tune) {
- LogWarning(sidplay_domain,
- "failed to load file for calculating md5 sum");
+ const auto length = songlength_database->length(tune);
+ if (length < 0)
return SignedSongTime::Negative();
- }
- char md5sum[SIDTUNE_MD5_LENGTH+1];
- tune.createMD5(md5sum);
-
- const unsigned song_num = get_song_num(path_fs.c_str());
- gsize num_items;
- gchar **values=g_key_file_get_string_list(songlength_database,
- "Database", md5sum, &num_items, nullptr);
- if(!values || song_num>num_items) {
- g_strfreev(values);
- return SignedSongTime::Negative();
- }
-
- int minutes=strtol(values[song_num-1], nullptr, 10);
- if(errno==EINVAL) minutes=0;
-
- int seconds;
- char *ptr=strchr(values[song_num-1], ':');
- if(ptr) {
- seconds=strtol(ptr+1, nullptr, 10);
- if(errno==EINVAL) seconds=0;
- } else
- seconds=0;
-
- g_strfreev(values);
-
- return SignedSongTime::FromS((minutes * 60) + seconds);
+ return SignedSongTime::FromS(length);
}
static void
@@ -209,18 +151,17 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
/* load the tune */
- char *path_container=get_container_name(path_fs);
- SidTune tune(path_container, nullptr, true);
- free(path_container);
+ const auto container = ParseContainerPath(path_fs);
+ SidTuneMod tune(container.path.c_str());
if (!tune) {
LogWarning(sidplay_domain, "failed to load file");
return;
}
- const int song_num = get_song_num(path_fs.c_str());
+ const int song_num = container.track;
tune.selectSong(song_num);
- auto duration = get_song_length(path_fs);
+ auto duration = get_song_length(tune);
if (duration.IsNegative() && default_songlength > 0)
duration = SongTime::FromS(default_songlength);
@@ -347,14 +288,15 @@ static bool
sidplay_scan_file(Path path_fs,
const struct tag_handler *handler, void *handler_ctx)
{
- const int song_num = get_song_num(path_fs.c_str());
- char *path_container=get_container_name(path_fs);
+ const auto container = ParseContainerPath(path_fs);
+ const unsigned song_num = container.track;
- SidTune tune(path_container, nullptr, true);
- free(path_container);
+ SidTuneMod tune(container.path.c_str());
if (!tune)
return false;
+ tune.selectSong(song_num);
+
const SidTuneInfo &info = tune.getInfo();
/* title */
@@ -385,7 +327,7 @@ sidplay_scan_file(Path path_fs,
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
/* time */
- const auto duration = get_song_length(path_fs);
+ const auto duration = get_song_length(tune);
if (!duration.IsNegative())
tag_handler_invoke_duration(handler, handler_ctx,
SongTime(duration));
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.hxx b/src/decoder/plugins/SidplayDecoderPlugin.hxx
index 58786e646..d54ab9fa6 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.hxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx
index 5518c70be..d8e4b0ba4 100644
--- a/src/decoder/plugins/SndfileDecoderPlugin.cxx
+++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
static constexpr Domain sndfile_domain("sndfile");
static bool
-sndfile_init(gcc_unused const config_param &param)
+sndfile_init(gcc_unused const ConfigBlock &block)
{
LogDebug(sndfile_domain, sf_version_string());
return true;
@@ -125,7 +125,7 @@ sndfile_vio_tell(void *user_data)
}
/**
- * This SF_VIRTUAL_IO implementation wraps MPD's #input_stream to a
+ * This SF_VIRTUAL_IO implementation wraps MPD's #InputStream to a
* libsndfile stream.
*/
static SF_VIRTUAL_IO vio = {
diff --git a/src/decoder/plugins/SndfileDecoderPlugin.hxx b/src/decoder/plugins/SndfileDecoderPlugin.hxx
index d56acdd5a..c793e1356 100644
--- a/src/decoder/plugins/SndfileDecoderPlugin.hxx
+++ b/src/decoder/plugins/SndfileDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/VorbisComments.cxx b/src/decoder/plugins/VorbisComments.cxx
index 062f46acf..e742e32ff 100644
--- a/src/decoder/plugins/VorbisComments.cxx
+++ b/src/decoder/plugins/VorbisComments.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#include "tag/ReplayGain.hxx"
#include "ReplayGainInfo.hxx"
#include "util/ASCII.hxx"
-#include "util/SplitString.hxx"
+#include "util/DivideString.hxx"
#include <stddef.h>
#include <stdlib.h>
@@ -74,7 +74,7 @@ vorbis_scan_comment(const char *comment,
const struct tag_handler *handler, void *handler_ctx)
{
if (handler->pair != nullptr) {
- const SplitString split(comment, '=');
+ const DivideString split(comment, '=');
if (split.IsDefined() && !split.IsEmpty())
tag_handler_invoke_pair(handler, handler_ctx,
split.GetFirst(),
diff --git a/src/decoder/plugins/VorbisComments.hxx b/src/decoder/plugins/VorbisComments.hxx
index 893c89277..54912aed7 100644
--- a/src/decoder/plugins/VorbisComments.hxx
+++ b/src/decoder/plugins/VorbisComments.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx
index e0d3d1374..d7069a2f4 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.cxx
+++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "../DecoderAPI.hxx"
#include "input/InputStream.hxx"
#include "OggCodec.hxx"
+#include "pcm/Interleave.hxx"
#include "util/Error.hxx"
#include "util/Macros.hxx"
#include "CheckAudioFormat.hxx"
@@ -181,20 +182,15 @@ static void
vorbis_interleave(float *dest, const float *const*src,
unsigned nframes, unsigned channels)
{
- for (const float *const*src_end = src + channels;
- src != src_end; ++src, ++dest) {
- float *gcc_restrict d = dest;
- for (const float *gcc_restrict s = *src, *s_end = s + nframes;
- s != s_end; ++s, d += channels)
- *d = *s;
- }
+ PcmInterleaveFloat(dest, ConstBuffer<const float *>(src, channels),
+ nframes);
}
#endif
/* public */
static bool
-vorbis_init(gcc_unused const config_param &param)
+vorbis_init(gcc_unused const ConfigBlock &block)
{
#ifndef HAVE_TREMOR
LogDebug(vorbis_domain, vorbis_version_string());
@@ -263,7 +259,7 @@ vorbis_stream_decode(Decoder &decoder,
unsigned kbit_rate = 0;
DecoderCommand cmd = decoder_get_command(decoder);
- do {
+ while (cmd != DecoderCommand::STOP) {
if (cmd == DecoderCommand::SEEK) {
auto seek_where = decoder_seek_where_frame(decoder);
if (0 == ov_pcm_seek_page(&vf, seek_where)) {
@@ -332,7 +328,7 @@ vorbis_stream_decode(Decoder &decoder,
cmd = decoder_data(decoder, input_stream,
buffer, nbytes,
kbit_rate);
- } while (cmd != DecoderCommand::STOP);
+ }
ov_clear(&vf);
}
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.h b/src/decoder/plugins/VorbisDecoderPlugin.h
index b54df2e97..1e2aee47e 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.h
+++ b/src/decoder/plugins/VorbisDecoderPlugin.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/VorbisDomain.cxx b/src/decoder/plugins/VorbisDomain.cxx
index e3d880efa..2855e325d 100644
--- a/src/decoder/plugins/VorbisDomain.cxx
+++ b/src/decoder/plugins/VorbisDomain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/VorbisDomain.hxx b/src/decoder/plugins/VorbisDomain.hxx
index 48715e328..bd63e5948 100644
--- a/src/decoder/plugins/VorbisDomain.hxx
+++ b/src/decoder/plugins/VorbisDomain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index 67859bbd2..339fd6910 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,10 @@
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/Macros.hxx"
+#include "util/Alloc.hxx"
#include "Log.hxx"
#include <wavpack/wavpack.h>
-#include <glib.h>
#include <assert.h>
#include <stdio.h>
@@ -322,7 +322,7 @@ wavpack_scan_file(Path path_fs,
}
/*
- * mpd input_stream <=> WavpackStreamReader wrapper callbacks
+ * #InputStream <=> WavpackStreamReader wrapper callbacks
*/
/* This struct is needed for per-stream last_byte storage. */
@@ -484,10 +484,10 @@ wavpack_open_wvc(Decoder &decoder, const char *uri)
if (uri == nullptr)
return nullptr;
- char *wvc_url = g_strconcat(uri, "c", nullptr);
+ char *wvc_url = xstrcatdup(uri, "c");
InputStream *is_wvc = decoder_open_uri(decoder, uri, IgnoreError());
- g_free(wvc_url);
+ free(wvc_url);
if (is_wvc == nullptr)
return nullptr;
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.hxx b/src/decoder/plugins/WavpackDecoderPlugin.hxx
index 2e5f9bd42..f2ee72e25 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.hxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/WildmidiDecoderPlugin.cxx b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
index fc58f0977..64fa33b05 100644
--- a/src/decoder/plugins/WildmidiDecoderPlugin.cxx
+++ b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,11 +38,11 @@ static constexpr Domain wildmidi_domain("wildmidi");
static constexpr unsigned WILDMIDI_SAMPLE_RATE = 48000;
static bool
-wildmidi_init(const config_param &param)
+wildmidi_init(const ConfigBlock &block)
{
Error error;
const AllocatedPath path =
- param.GetBlockPath("config_file",
+ block.GetBlockPath("config_file",
"/etc/timidity/timidity.cfg",
error);
if (path.IsNull())
diff --git a/src/decoder/plugins/WildmidiDecoderPlugin.hxx b/src/decoder/plugins/WildmidiDecoderPlugin.hxx
index fc87aab80..ec896662b 100644
--- a/src/decoder/plugins/WildmidiDecoderPlugin.hxx
+++ b/src/decoder/plugins/WildmidiDecoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/decoder/plugins/XiphTags.cxx b/src/decoder/plugins/XiphTags.cxx
index 11a0bcd42..24a2aa623 100644
--- a/src/decoder/plugins/XiphTags.cxx
+++ b/src/decoder/plugins/XiphTags.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,6 @@
const struct tag_table xiph_tags[] = {
{ "tracknumber", TAG_TRACK },
{ "discnumber", TAG_DISC },
- { "album artist", TAG_ALBUM_ARTIST },
{ "description", TAG_COMMENT },
{ nullptr, TAG_NUM_OF_ITEM_TYPES }
};
diff --git a/src/decoder/plugins/XiphTags.hxx b/src/decoder/plugins/XiphTags.hxx
index 48a27425f..d83e116c1 100644
--- a/src/decoder/plugins/XiphTags.hxx
+++ b/src/decoder/plugins/XiphTags.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/EncoderAPI.hxx b/src/encoder/EncoderAPI.hxx
index b147eac21..def543c58 100644
--- a/src/encoder/EncoderAPI.hxx
+++ b/src/encoder/EncoderAPI.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,10 +27,11 @@
// IWYU pragma: begin_exports
+#include "EncoderInterface.hxx"
#include "EncoderPlugin.hxx"
#include "AudioFormat.hxx"
#include "tag/Tag.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
// IWYU pragma: end_exports
diff --git a/src/encoder/EncoderInterface.hxx b/src/encoder/EncoderInterface.hxx
new file mode 100644
index 000000000..c1ecd872f
--- /dev/null
+++ b/src/encoder/EncoderInterface.hxx
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ENCODER_INTERFACE_HXX
+#define MPD_ENCODER_INTERFACE_HXX
+
+#include "EncoderPlugin.hxx"
+
+#include <assert.h>
+
+struct Encoder {
+ const EncoderPlugin &plugin;
+
+#ifndef NDEBUG
+ bool open, pre_tag, tag, end;
+#endif
+
+ explicit Encoder(const EncoderPlugin &_plugin)
+ :plugin(_plugin)
+#ifndef NDEBUG
+ , open(false)
+#endif
+ {}
+
+
+ /**
+ * Frees an #Encoder object.
+ */
+ void Dispose() {
+ assert(!open);
+
+ plugin.finish(this);
+ }
+
+ /**
+ * Opens the object. You must call this prior to using it.
+ * Before you free it, you must call Close(). You may open
+ * and close (reuse) one encoder any number of times.
+ *
+ * After this function returns successfully and before the
+ * first encoder_write() call, you should invoke
+ * encoder_read() to obtain the file header.
+ *
+ * @param audio_format the encoder's input audio format; the plugin
+ * may modify the struct to adapt it to its abilities
+ * @return true on success
+ */
+ bool Open(AudioFormat &audio_format, Error &error) {
+ assert(!open);
+
+ bool success = plugin.open(this, audio_format, error);
+#ifndef NDEBUG
+ open = success;
+ pre_tag = tag = end = false;
+#endif
+ return success;
+ }
+
+
+ /**
+ * Closes the object. This disables the encoder, and readies
+ * it for reusal by calling Open() again.
+ */
+ void Close() {
+ assert(open);
+
+ if (plugin.close != nullptr)
+ plugin.close(this);
+
+#ifndef NDEBUG
+ open = false;
+#endif
+ }
+};
+
+/**
+ * Ends the stream: flushes the encoder object, generate an
+ * end-of-stream marker (if applicable), make everything which might
+ * currently be buffered available by encoder_read().
+ *
+ * After this function has been called, the encoder may not be usable
+ * for more data, and only encoder_read() and Encoder::Close() can be
+ * called.
+ *
+ * @param encoder the encoder
+ * @return true on success
+ */
+static inline bool
+encoder_end(Encoder *encoder, Error &error)
+{
+ assert(encoder->open);
+ assert(!encoder->end);
+
+#ifndef NDEBUG
+ encoder->end = true;
+#endif
+
+ /* this method is optional */
+ return encoder->plugin.end != nullptr
+ ? encoder->plugin.end(encoder, error)
+ : true;
+}
+
+/**
+ * Flushes an encoder object, make everything which might currently be
+ * buffered available by encoder_read().
+ *
+ * @param encoder the encoder
+ * @return true on success
+ */
+static inline bool
+encoder_flush(Encoder *encoder, Error &error)
+{
+ assert(encoder->open);
+ assert(!encoder->pre_tag);
+ assert(!encoder->tag);
+ assert(!encoder->end);
+
+ /* this method is optional */
+ return encoder->plugin.flush != nullptr
+ ? encoder->plugin.flush(encoder, error)
+ : true;
+}
+
+/**
+ * Prepare for sending a tag to the encoder. This is used by some
+ * encoders to flush the previous sub-stream, in preparation to begin
+ * a new one.
+ *
+ * @param encoder the encoder
+ * @return true on success
+ */
+static inline bool
+encoder_pre_tag(Encoder *encoder, Error &error)
+{
+ assert(encoder->open);
+ assert(!encoder->pre_tag);
+ assert(!encoder->tag);
+ assert(!encoder->end);
+
+ /* this method is optional */
+ bool success = encoder->plugin.pre_tag != nullptr
+ ? encoder->plugin.pre_tag(encoder, error)
+ : true;
+
+#ifndef NDEBUG
+ encoder->pre_tag = success;
+#endif
+ return success;
+}
+
+/**
+ * Sends a tag to the encoder.
+ *
+ * Instructions: call encoder_pre_tag(); then obtain flushed data with
+ * encoder_read(); finally call encoder_tag().
+ *
+ * @param encoder the encoder
+ * @param tag the tag object
+ * @return true on success
+ */
+static inline bool
+encoder_tag(Encoder *encoder, const Tag &tag, Error &error)
+{
+ assert(encoder->open);
+ assert(!encoder->pre_tag);
+ assert(encoder->tag);
+ assert(!encoder->end);
+
+#ifndef NDEBUG
+ encoder->tag = false;
+#endif
+
+ /* this method is optional */
+ return encoder->plugin.tag != nullptr
+ ? encoder->plugin.tag(encoder, tag, error)
+ : true;
+}
+
+/**
+ * Writes raw PCM data to the encoder.
+ *
+ * @param encoder the encoder
+ * @param data the buffer containing PCM samples
+ * @param length the length of the buffer in bytes
+ * @return true on success
+ */
+static inline bool
+encoder_write(Encoder *encoder, const void *data, size_t length,
+ Error &error)
+{
+ assert(encoder->open);
+ assert(!encoder->pre_tag);
+ assert(!encoder->tag);
+ assert(!encoder->end);
+
+ return encoder->plugin.write(encoder, data, length, error);
+}
+
+/**
+ * Reads encoded data from the encoder.
+ *
+ * Call this repeatedly until no more data is returned.
+ *
+ * @param encoder the encoder
+ * @param dest the destination buffer to copy to
+ * @param length the maximum length of the destination buffer
+ * @return the number of bytes written to #dest
+ */
+static inline size_t
+encoder_read(Encoder *encoder, void *dest, size_t length)
+{
+ assert(encoder->open);
+ assert(!encoder->pre_tag || !encoder->tag);
+
+#ifndef NDEBUG
+ if (encoder->pre_tag) {
+ encoder->pre_tag = false;
+ encoder->tag = true;
+ }
+#endif
+
+ return encoder->plugin.read(encoder, dest, length);
+}
+
+/**
+ * Get mime type of encoded content.
+ *
+ * @return an constant string, nullptr on failure
+ */
+static inline const char *
+encoder_get_mime_type(Encoder *encoder)
+{
+ /* this method is optional */
+ return encoder->plugin.get_mime_type != nullptr
+ ? encoder->plugin.get_mime_type(encoder)
+ : nullptr;
+}
+
+#endif
diff --git a/src/encoder/EncoderList.cxx b/src/encoder/EncoderList.cxx
index 4bca5a4fe..f074f610b 100644
--- a/src/encoder/EncoderList.cxx
+++ b/src/encoder/EncoderList.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,16 +33,16 @@
const EncoderPlugin *const encoder_plugins[] = {
&null_encoder_plugin,
-#ifdef ENABLE_VORBIS_ENCODER
+#ifdef ENABLE_VORBISENC
&vorbis_encoder_plugin,
#endif
-#ifdef HAVE_OPUS
+#ifdef ENABLE_OPUS
&opus_encoder_plugin,
#endif
-#ifdef ENABLE_LAME_ENCODER
+#ifdef ENABLE_LAME
&lame_encoder_plugin,
#endif
-#ifdef ENABLE_TWOLAME_ENCODER
+#ifdef ENABLE_TWOLAME
&twolame_encoder_plugin,
#endif
#ifdef ENABLE_WAVE_ENCODER
@@ -51,7 +51,7 @@ const EncoderPlugin *const encoder_plugins[] = {
#ifdef ENABLE_FLAC_ENCODER
&flac_encoder_plugin,
#endif
-#ifdef ENABLE_SHINE_ENCODER
+#ifdef ENABLE_SHINE
&shine_encoder_plugin,
#endif
nullptr
diff --git a/src/encoder/EncoderList.hxx b/src/encoder/EncoderList.hxx
index e18d8ec74..19a4dd6d8 100644
--- a/src/encoder/EncoderList.hxx
+++ b/src/encoder/EncoderList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/EncoderPlugin.hxx b/src/encoder/EncoderPlugin.hxx
index 95e4e5838..09b68a0a8 100644
--- a/src/encoder/EncoderPlugin.hxx
+++ b/src/encoder/EncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,35 +20,18 @@
#ifndef MPD_ENCODER_PLUGIN_HXX
#define MPD_ENCODER_PLUGIN_HXX
-#include <assert.h>
-#include <stdbool.h>
#include <stddef.h>
-struct EncoderPlugin;
+struct Encoder;
struct AudioFormat;
-struct config_param;
+struct ConfigBlock;
struct Tag;
class Error;
-struct Encoder {
- const EncoderPlugin &plugin;
-
-#ifndef NDEBUG
- bool open, pre_tag, tag, end;
-#endif
-
- explicit Encoder(const EncoderPlugin &_plugin)
- :plugin(_plugin)
-#ifndef NDEBUG
- , open(false)
-#endif
- {}
-};
-
struct EncoderPlugin {
const char *name;
- Encoder *(*init)(const config_param &param,
+ Encoder *(*init)(const ConfigBlock &block,
Error &error);
void (*finish)(Encoder *encoder);
@@ -65,7 +48,7 @@ struct EncoderPlugin {
bool (*pre_tag)(Encoder *encoder, Error &error);
- bool (*tag)(Encoder *encoder, const Tag *tag,
+ bool (*tag)(Encoder *encoder, const Tag &tag,
Error &error);
bool (*write)(Encoder *encoder,
@@ -81,241 +64,14 @@ struct EncoderPlugin {
* Creates a new encoder object.
*
* @param plugin the encoder plugin
- * @param param optional configuration
* @param error location to store the error occurring, or nullptr to ignore errors.
* @return an encoder object on success, nullptr on failure
*/
static inline Encoder *
-encoder_init(const EncoderPlugin &plugin, const config_param &param,
- Error &error_r)
-{
- return plugin.init(param, error_r);
-}
-
-/**
- * Frees an encoder object.
- *
- * @param encoder the encoder
- */
-static inline void
-encoder_finish(Encoder *encoder)
-{
- assert(!encoder->open);
-
- encoder->plugin.finish(encoder);
-}
-
-/**
- * Opens an encoder object. You must call this prior to using it.
- * Before you free it, you must call encoder_close(). You may open
- * and close (reuse) one encoder any number of times.
- *
- * After this function returns successfully and before the first
- * encoder_write() call, you should invoke encoder_read() to obtain
- * the file header.
- *
- * @param encoder the encoder
- * @param audio_format the encoder's input audio format; the plugin
- * may modify the struct to adapt it to its abilities
- * @return true on success
- */
-static inline bool
-encoder_open(Encoder *encoder, AudioFormat &audio_format,
+encoder_init(const EncoderPlugin &plugin, const ConfigBlock &block,
Error &error)
{
- assert(!encoder->open);
-
- bool success = encoder->plugin.open(encoder, audio_format, error);
-#ifndef NDEBUG
- encoder->open = success;
- encoder->pre_tag = encoder->tag = encoder->end = false;
-#endif
- return success;
-}
-
-/**
- * Closes an encoder object. This disables the encoder, and readies
- * it for reusal by calling encoder_open() again.
- *
- * @param encoder the encoder
- */
-static inline void
-encoder_close(Encoder *encoder)
-{
- assert(encoder->open);
-
- if (encoder->plugin.close != nullptr)
- encoder->plugin.close(encoder);
-
-#ifndef NDEBUG
- encoder->open = false;
-#endif
-}
-
-/**
- * Ends the stream: flushes the encoder object, generate an
- * end-of-stream marker (if applicable), make everything which might
- * currently be buffered available by encoder_read().
- *
- * After this function has been called, the encoder may not be usable
- * for more data, and only encoder_read() and encoder_close() can be
- * called.
- *
- * @param encoder the encoder
- * @return true on success
- */
-static inline bool
-encoder_end(Encoder *encoder, Error &error)
-{
- assert(encoder->open);
- assert(!encoder->end);
-
-#ifndef NDEBUG
- encoder->end = true;
-#endif
-
- /* this method is optional */
- return encoder->plugin.end != nullptr
- ? encoder->plugin.end(encoder, error)
- : true;
-}
-
-/**
- * Flushes an encoder object, make everything which might currently be
- * buffered available by encoder_read().
- *
- * @param encoder the encoder
- * @return true on success
- */
-static inline bool
-encoder_flush(Encoder *encoder, Error &error)
-{
- assert(encoder->open);
- assert(!encoder->pre_tag);
- assert(!encoder->tag);
- assert(!encoder->end);
-
- /* this method is optional */
- return encoder->plugin.flush != nullptr
- ? encoder->plugin.flush(encoder, error)
- : true;
-}
-
-/**
- * Prepare for sending a tag to the encoder. This is used by some
- * encoders to flush the previous sub-stream, in preparation to begin
- * a new one.
- *
- * @param encoder the encoder
- * @param tag the tag object
- * @return true on success
- */
-static inline bool
-encoder_pre_tag(Encoder *encoder, Error &error)
-{
- assert(encoder->open);
- assert(!encoder->pre_tag);
- assert(!encoder->tag);
- assert(!encoder->end);
-
- /* this method is optional */
- bool success = encoder->plugin.pre_tag != nullptr
- ? encoder->plugin.pre_tag(encoder, error)
- : true;
-
-#ifndef NDEBUG
- encoder->pre_tag = success;
-#endif
- return success;
-}
-
-/**
- * Sends a tag to the encoder.
- *
- * Instructions: call encoder_pre_tag(); then obtain flushed data with
- * encoder_read(); finally call encoder_tag().
- *
- * @param encoder the encoder
- * @param tag the tag object
- * @return true on success
- */
-static inline bool
-encoder_tag(Encoder *encoder, const Tag *tag, Error &error)
-{
- assert(encoder->open);
- assert(!encoder->pre_tag);
- assert(encoder->tag);
- assert(!encoder->end);
-
-#ifndef NDEBUG
- encoder->tag = false;
-#endif
-
- /* this method is optional */
- return encoder->plugin.tag != nullptr
- ? encoder->plugin.tag(encoder, tag, error)
- : true;
-}
-
-/**
- * Writes raw PCM data to the encoder.
- *
- * @param encoder the encoder
- * @param data the buffer containing PCM samples
- * @param length the length of the buffer in bytes
- * @return true on success
- */
-static inline bool
-encoder_write(Encoder *encoder, const void *data, size_t length,
- Error &error)
-{
- assert(encoder->open);
- assert(!encoder->pre_tag);
- assert(!encoder->tag);
- assert(!encoder->end);
-
- return encoder->plugin.write(encoder, data, length, error);
-}
-
-/**
- * Reads encoded data from the encoder.
- *
- * Call this repeatedly until no more data is returned.
- *
- * @param encoder the encoder
- * @param dest the destination buffer to copy to
- * @param length the maximum length of the destination buffer
- * @return the number of bytes written to #dest
- */
-static inline size_t
-encoder_read(Encoder *encoder, void *dest, size_t length)
-{
- assert(encoder->open);
- assert(!encoder->pre_tag || !encoder->tag);
-
-#ifndef NDEBUG
- if (encoder->pre_tag) {
- encoder->pre_tag = false;
- encoder->tag = true;
- }
-#endif
-
- return encoder->plugin.read(encoder, dest, length);
-}
-
-/**
- * Get mime type of encoded content.
- *
- * @param plugin the encoder plugin
- * @return an constant string, nullptr on failure
- */
-static inline const char *
-encoder_get_mime_type(Encoder *encoder)
-{
- /* this method is optional */
- return encoder->plugin.get_mime_type != nullptr
- ? encoder->plugin.get_mime_type(encoder)
- : nullptr;
+ return plugin.init(block, error);
}
#endif
diff --git a/src/encoder/ToOutputStream.cxx b/src/encoder/ToOutputStream.cxx
new file mode 100644
index 000000000..43345cf70
--- /dev/null
+++ b/src/encoder/ToOutputStream.cxx
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "ToOutputStream.hxx"
+#include "EncoderInterface.hxx"
+#include "fs/io/OutputStream.hxx"
+
+bool
+EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error)
+{
+ while (true) {
+ /* read from the encoder */
+
+ char buffer[32768];
+ size_t nbytes = encoder_read(&encoder, buffer, sizeof(buffer));
+ if (nbytes == 0)
+ return true;
+
+ /* write everything to the stream */
+
+ if (!os.Write(buffer, nbytes, error))
+ return false;
+ }
+}
diff --git a/src/encoder/ToOutputStream.hxx b/src/encoder/ToOutputStream.hxx
new file mode 100644
index 000000000..e3fb7b908
--- /dev/null
+++ b/src/encoder/ToOutputStream.hxx
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ENCODER_TO_OUTPUT_STREAM_HXX
+#define MPD_ENCODER_TO_OUTPUT_STREAM_HXX
+
+#include "check.h"
+
+struct Encoder;
+class OutputStream;
+class Error;
+
+bool
+EncoderToOutputStream(OutputStream &os, Encoder &encoder, Error &error);
+
+#endif
diff --git a/src/encoder/plugins/FlacEncoderPlugin.cxx b/src/encoder/plugins/FlacEncoderPlugin.cxx
index 9317b02ea..86a3588df 100644
--- a/src/encoder/plugins/FlacEncoderPlugin.cxx
+++ b/src/encoder/plugins/FlacEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -56,21 +56,21 @@ struct flac_encoder {
static constexpr Domain flac_encoder_domain("vorbis_encoder");
static bool
-flac_encoder_configure(struct flac_encoder *encoder, const config_param &param,
+flac_encoder_configure(struct flac_encoder *encoder, const ConfigBlock &block,
gcc_unused Error &error)
{
- encoder->compression = param.GetBlockValue("compression", 5u);
+ encoder->compression = block.GetBlockValue("compression", 5u);
return true;
}
static Encoder *
-flac_encoder_init(const config_param &param, Error &error)
+flac_encoder_init(const ConfigBlock &block, Error &error)
{
flac_encoder *encoder = new flac_encoder();
- /* load configuration from "param" */
- if (!flac_encoder_configure(encoder, param, error)) {
+ /* load configuration from "block" */
+ if (!flac_encoder_configure(encoder, block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
diff --git a/src/encoder/plugins/FlacEncoderPlugin.hxx b/src/encoder/plugins/FlacEncoderPlugin.hxx
index 0cdc01600..dcd899974 100644
--- a/src/encoder/plugins/FlacEncoderPlugin.hxx
+++ b/src/encoder/plugins/FlacEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/LameEncoderPlugin.cxx b/src/encoder/plugins/LameEncoderPlugin.cxx
index 3878b52bb..7c6313109 100644
--- a/src/encoder/plugins/LameEncoderPlugin.cxx
+++ b/src/encoder/plugins/LameEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -47,18 +47,18 @@ struct LameEncoder final {
LameEncoder():encoder(lame_encoder_plugin) {}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
};
static constexpr Domain lame_encoder_domain("lame_encoder");
bool
-LameEncoder::Configure(const config_param &param, Error &error)
+LameEncoder::Configure(const ConfigBlock &block, Error &error)
{
const char *value;
char *endptr;
- value = param.GetBlockValue("quality");
+ value = block.GetBlockValue("quality");
if (value != nullptr) {
/* a quality was configured (VBR) */
@@ -72,7 +72,7 @@ LameEncoder::Configure(const config_param &param, Error &error)
return false;
}
- if (param.GetBlockValue("bitrate") != nullptr) {
+ if (block.GetBlockValue("bitrate") != nullptr) {
error.Set(config_domain,
"quality and bitrate are both defined");
return false;
@@ -80,7 +80,7 @@ LameEncoder::Configure(const config_param &param, Error &error)
} else {
/* a bit rate was configured */
- value = param.GetBlockValue("bitrate");
+ value = block.GetBlockValue("bitrate");
if (value == nullptr) {
error.Set(config_domain,
"neither bitrate nor quality defined");
@@ -101,12 +101,12 @@ LameEncoder::Configure(const config_param &param, Error &error)
}
static Encoder *
-lame_encoder_init(const config_param &param, Error &error)
+lame_encoder_init(const ConfigBlock &block, Error &error)
{
LameEncoder *encoder = new LameEncoder();
- /* load configuration from "param" */
- if (!encoder->Configure(param, error)) {
+ /* load configuration from "block" */
+ if (!encoder->Configure(block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
diff --git a/src/encoder/plugins/LameEncoderPlugin.hxx b/src/encoder/plugins/LameEncoderPlugin.hxx
index 03e398f67..5a077f7cc 100644
--- a/src/encoder/plugins/LameEncoderPlugin.hxx
+++ b/src/encoder/plugins/LameEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/NullEncoderPlugin.cxx b/src/encoder/plugins/NullEncoderPlugin.cxx
index 1d571d465..99be7aec4 100644
--- a/src/encoder/plugins/NullEncoderPlugin.cxx
+++ b/src/encoder/plugins/NullEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@ struct NullEncoder final {
};
static Encoder *
-null_encoder_init(gcc_unused const config_param &param,
+null_encoder_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
NullEncoder *encoder = new NullEncoder();
diff --git a/src/encoder/plugins/NullEncoderPlugin.hxx b/src/encoder/plugins/NullEncoderPlugin.hxx
index 6acf88e49..9fabe81fd 100644
--- a/src/encoder/plugins/NullEncoderPlugin.hxx
+++ b/src/encoder/plugins/NullEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/OggSerial.cxx b/src/encoder/plugins/OggSerial.cxx
index 677829439..639d2b3c1 100644
--- a/src/encoder/plugins/OggSerial.cxx
+++ b/src/encoder/plugins/OggSerial.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/OggSerial.hxx b/src/encoder/plugins/OggSerial.hxx
index ceba8ebf9..21ae02804 100644
--- a/src/encoder/plugins/OggSerial.hxx
+++ b/src/encoder/plugins/OggSerial.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/OggStream.hxx b/src/encoder/plugins/OggStream.hxx
index 805238c1d..376a697a1 100644
--- a/src/encoder/plugins/OggStream.hxx
+++ b/src/encoder/plugins/OggStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/OpusEncoderPlugin.cxx b/src/encoder/plugins/OpusEncoderPlugin.cxx
index 2b52228cb..e17cb86fd 100644
--- a/src/encoder/plugins/OpusEncoderPlugin.cxx
+++ b/src/encoder/plugins/OpusEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -73,9 +73,9 @@ static constexpr Domain opus_encoder_domain("opus_encoder");
static bool
opus_encoder_configure(struct opus_encoder *encoder,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
- const char *value = param.GetBlockValue("bitrate", "auto");
+ const char *value = block.GetBlockValue("bitrate", "auto");
if (strcmp(value, "auto") == 0)
encoder->bitrate = OPUS_AUTO;
else if (strcmp(value, "max") == 0)
@@ -90,13 +90,13 @@ opus_encoder_configure(struct opus_encoder *encoder,
}
}
- encoder->complexity = param.GetBlockValue("complexity", 10u);
+ encoder->complexity = block.GetBlockValue("complexity", 10u);
if (encoder->complexity > 10) {
error.Format(config_domain, "Invalid complexity");
return false;
}
- value = param.GetBlockValue("signal", "auto");
+ value = block.GetBlockValue("signal", "auto");
if (strcmp(value, "auto") == 0)
encoder->signal = OPUS_AUTO;
else if (strcmp(value, "voice") == 0)
@@ -112,12 +112,12 @@ opus_encoder_configure(struct opus_encoder *encoder,
}
static Encoder *
-opus_encoder_init(const config_param &param, Error &error)
+opus_encoder_init(const ConfigBlock &block, Error &error)
{
opus_encoder *encoder = new opus_encoder();
- /* load configuration from "param" */
- if (!opus_encoder_configure(encoder, param, error)) {
+ /* load configuration from "block" */
+ if (!opus_encoder_configure(encoder, block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
diff --git a/src/encoder/plugins/OpusEncoderPlugin.hxx b/src/encoder/plugins/OpusEncoderPlugin.hxx
index 4e71694b9..09067e37d 100644
--- a/src/encoder/plugins/OpusEncoderPlugin.hxx
+++ b/src/encoder/plugins/OpusEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/ShineEncoderPlugin.cxx b/src/encoder/plugins/ShineEncoderPlugin.cxx
index 1b00f7d53..34040b018 100644
--- a/src/encoder/plugins/ShineEncoderPlugin.cxx
+++ b/src/encoder/plugins/ShineEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -52,7 +52,7 @@ struct ShineEncoder {
ShineEncoder():encoder(shine_encoder_plugin){}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
bool Setup(Error &error);
@@ -60,22 +60,21 @@ struct ShineEncoder {
};
inline bool
-ShineEncoder::Configure(const config_param &param,
- gcc_unused Error &error)
+ShineEncoder::Configure(const ConfigBlock &block, gcc_unused Error &error)
{
shine_set_config_mpeg_defaults(&config.mpeg);
- config.mpeg.bitr = param.GetBlockValue("bitrate", 128);
+ config.mpeg.bitr = block.GetBlockValue("bitrate", 128);
return true;
}
static Encoder *
-shine_encoder_init(const config_param &param, Error &error)
+shine_encoder_init(const ConfigBlock &block, Error &error)
{
ShineEncoder *encoder = new ShineEncoder();
- /* load configuration from "param" */
- if (!encoder->Configure(param, error)) {
+ /* load configuration from "block" */
+ if (!encoder->Configure(block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
diff --git a/src/encoder/plugins/ShineEncoderPlugin.hxx b/src/encoder/plugins/ShineEncoderPlugin.hxx
index 8b1520a74..ecde902fb 100644
--- a/src/encoder/plugins/ShineEncoderPlugin.hxx
+++ b/src/encoder/plugins/ShineEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/TwolameEncoderPlugin.cxx b/src/encoder/plugins/TwolameEncoderPlugin.cxx
index 2eb6b2b1c..262fc6c33 100644
--- a/src/encoder/plugins/TwolameEncoderPlugin.cxx
+++ b/src/encoder/plugins/TwolameEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -53,18 +53,18 @@ struct TwolameEncoder final {
TwolameEncoder():encoder(twolame_encoder_plugin) {}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
};
static constexpr Domain twolame_encoder_domain("twolame_encoder");
bool
-TwolameEncoder::Configure(const config_param &param, Error &error)
+TwolameEncoder::Configure(const ConfigBlock &block, Error &error)
{
const char *value;
char *endptr;
- value = param.GetBlockValue("quality");
+ value = block.GetBlockValue("quality");
if (value != nullptr) {
/* a quality was configured (VBR) */
@@ -78,7 +78,7 @@ TwolameEncoder::Configure(const config_param &param, Error &error)
return false;
}
- if (param.GetBlockValue("bitrate") != nullptr) {
+ if (block.GetBlockValue("bitrate") != nullptr) {
error.Set(config_domain,
"quality and bitrate are both defined");
return false;
@@ -86,7 +86,7 @@ TwolameEncoder::Configure(const config_param &param, Error &error)
} else {
/* a bit rate was configured */
- value = param.GetBlockValue("bitrate");
+ value = block.GetBlockValue("bitrate");
if (value == nullptr) {
error.Set(config_domain,
"neither bitrate nor quality defined");
@@ -107,15 +107,15 @@ TwolameEncoder::Configure(const config_param &param, Error &error)
}
static Encoder *
-twolame_encoder_init(const config_param &param, Error &error_r)
+twolame_encoder_init(const ConfigBlock &block, Error &error_r)
{
FormatDebug(twolame_encoder_domain,
"libtwolame version %s", get_twolame_version());
TwolameEncoder *encoder = new TwolameEncoder();
- /* load configuration from "param" */
- if (!encoder->Configure(param, error_r)) {
+ /* load configuration from "block" */
+ if (!encoder->Configure(block, error_r)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
diff --git a/src/encoder/plugins/TwolameEncoderPlugin.hxx b/src/encoder/plugins/TwolameEncoderPlugin.hxx
index 531dd3e90..2c0b250da 100644
--- a/src/encoder/plugins/TwolameEncoderPlugin.hxx
+++ b/src/encoder/plugins/TwolameEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/VorbisEncoderPlugin.cxx b/src/encoder/plugins/VorbisEncoderPlugin.cxx
index ecc784a47..11e057eaa 100644
--- a/src/encoder/plugins/VorbisEncoderPlugin.cxx
+++ b/src/encoder/plugins/VorbisEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,14 +25,13 @@
#include "tag/Tag.hxx"
#include "AudioFormat.hxx"
#include "config/ConfigError.hxx"
+#include "util/StringUtil.hxx"
#include "util/NumberParser.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include <vorbis/vorbisenc.h>
-#include <glib.h>
-
struct vorbis_encoder {
/** the base class */
Encoder encoder;
@@ -58,18 +57,18 @@ struct vorbis_encoder {
static constexpr Domain vorbis_encoder_domain("vorbis_encoder");
static bool
-vorbis_encoder_configure(struct vorbis_encoder *encoder,
- const config_param &param, Error &error)
+vorbis_encoder_configure(struct vorbis_encoder &encoder,
+ const ConfigBlock &block, Error &error)
{
- const char *value = param.GetBlockValue("quality");
+ const char *value = block.GetBlockValue("quality");
if (value != nullptr) {
/* a quality was configured (VBR) */
char *endptr;
- encoder->quality = ParseDouble(value, &endptr);
+ encoder.quality = ParseDouble(value, &endptr);
- if (*endptr != '\0' || encoder->quality < -1.0 ||
- encoder->quality > 10.0) {
+ if (*endptr != '\0' || encoder.quality < -1.0 ||
+ encoder.quality > 10.0) {
error.Format(config_domain,
"quality \"%s\" is not a number in the "
"range -1 to 10",
@@ -77,7 +76,7 @@ vorbis_encoder_configure(struct vorbis_encoder *encoder,
return false;
}
- if (param.GetBlockValue("bitrate") != nullptr) {
+ if (block.GetBlockValue("bitrate") != nullptr) {
error.Set(config_domain,
"quality and bitrate are both defined");
return false;
@@ -85,18 +84,18 @@ vorbis_encoder_configure(struct vorbis_encoder *encoder,
} else {
/* a bit rate was configured */
- value = param.GetBlockValue("bitrate");
+ value = block.GetBlockValue("bitrate");
if (value == nullptr) {
error.Set(config_domain,
"neither bitrate nor quality defined");
return false;
}
- encoder->quality = -2.0;
+ encoder.quality = -2.0;
char *endptr;
- encoder->bitrate = ParseInt(value, &endptr);
- if (*endptr != '\0' || encoder->bitrate <= 0) {
+ encoder.bitrate = ParseInt(value, &endptr);
+ if (*endptr != '\0' || encoder.bitrate <= 0) {
error.Set(config_domain,
"bitrate should be a positive integer");
return false;
@@ -107,12 +106,12 @@ vorbis_encoder_configure(struct vorbis_encoder *encoder,
}
static Encoder *
-vorbis_encoder_init(const config_param &param, Error &error)
+vorbis_encoder_init(const ConfigBlock &block, Error &error)
{
vorbis_encoder *encoder = new vorbis_encoder();
- /* load configuration from "param" */
- if (!vorbis_encoder_configure(encoder, param, error)) {
+ /* load configuration from "block" */
+ if (!vorbis_encoder_configure(*encoder, block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
@@ -132,63 +131,63 @@ vorbis_encoder_finish(Encoder *_encoder)
}
static bool
-vorbis_encoder_reinit(struct vorbis_encoder *encoder, Error &error)
+vorbis_encoder_reinit(struct vorbis_encoder &encoder, Error &error)
{
- vorbis_info_init(&encoder->vi);
+ vorbis_info_init(&encoder.vi);
- if (encoder->quality >= -1.0) {
+ if (encoder.quality >= -1.0) {
/* a quality was configured (VBR) */
- if (0 != vorbis_encode_init_vbr(&encoder->vi,
- encoder->audio_format.channels,
- encoder->audio_format.sample_rate,
- encoder->quality * 0.1)) {
+ if (0 != vorbis_encode_init_vbr(&encoder.vi,
+ encoder.audio_format.channels,
+ encoder.audio_format.sample_rate,
+ encoder.quality * 0.1)) {
error.Set(vorbis_encoder_domain,
"error initializing vorbis vbr");
- vorbis_info_clear(&encoder->vi);
+ vorbis_info_clear(&encoder.vi);
return false;
}
} else {
/* a bit rate was configured */
- if (0 != vorbis_encode_init(&encoder->vi,
- encoder->audio_format.channels,
- encoder->audio_format.sample_rate, -1.0,
- encoder->bitrate * 1000, -1.0)) {
+ if (0 != vorbis_encode_init(&encoder.vi,
+ encoder.audio_format.channels,
+ encoder.audio_format.sample_rate, -1.0,
+ encoder.bitrate * 1000, -1.0)) {
error.Set(vorbis_encoder_domain,
"error initializing vorbis encoder");
- vorbis_info_clear(&encoder->vi);
+ vorbis_info_clear(&encoder.vi);
return false;
}
}
- vorbis_analysis_init(&encoder->vd, &encoder->vi);
- vorbis_block_init(&encoder->vd, &encoder->vb);
- encoder->stream.Initialize(GenerateOggSerial());
+ vorbis_analysis_init(&encoder.vd, &encoder.vi);
+ vorbis_block_init(&encoder.vd, &encoder.vb);
+ encoder.stream.Initialize(GenerateOggSerial());
return true;
}
static void
-vorbis_encoder_headerout(struct vorbis_encoder *encoder, vorbis_comment *vc)
+vorbis_encoder_headerout(struct vorbis_encoder &encoder, vorbis_comment &vc)
{
ogg_packet packet, comments, codebooks;
- vorbis_analysis_headerout(&encoder->vd, vc,
+ vorbis_analysis_headerout(&encoder.vd, &vc,
&packet, &comments, &codebooks);
- encoder->stream.PacketIn(packet);
- encoder->stream.PacketIn(comments);
- encoder->stream.PacketIn(codebooks);
+ encoder.stream.PacketIn(packet);
+ encoder.stream.PacketIn(comments);
+ encoder.stream.PacketIn(codebooks);
}
static void
-vorbis_encoder_send_header(struct vorbis_encoder *encoder)
+vorbis_encoder_send_header(struct vorbis_encoder &encoder)
{
vorbis_comment vc;
vorbis_comment_init(&vc);
- vorbis_encoder_headerout(encoder, &vc);
+ vorbis_encoder_headerout(encoder, vc);
vorbis_comment_clear(&vc);
}
@@ -197,11 +196,11 @@ vorbis_encoder_open(Encoder *_encoder,
AudioFormat &audio_format,
Error &error)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
audio_format.format = SampleFormat::FLOAT;
- encoder->audio_format = audio_format;
+ encoder.audio_format = audio_format;
if (!vorbis_encoder_reinit(encoder, error))
return false;
@@ -212,78 +211,78 @@ vorbis_encoder_open(Encoder *_encoder,
}
static void
-vorbis_encoder_clear(struct vorbis_encoder *encoder)
+vorbis_encoder_clear(struct vorbis_encoder &encoder)
{
- encoder->stream.Deinitialize();
- vorbis_block_clear(&encoder->vb);
- vorbis_dsp_clear(&encoder->vd);
- vorbis_info_clear(&encoder->vi);
+ encoder.stream.Deinitialize();
+ vorbis_block_clear(&encoder.vb);
+ vorbis_dsp_clear(&encoder.vd);
+ vorbis_info_clear(&encoder.vi);
}
static void
vorbis_encoder_close(Encoder *_encoder)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
vorbis_encoder_clear(encoder);
}
static void
-vorbis_encoder_blockout(struct vorbis_encoder *encoder)
+vorbis_encoder_blockout(struct vorbis_encoder &encoder)
{
- while (vorbis_analysis_blockout(&encoder->vd, &encoder->vb) == 1) {
- vorbis_analysis(&encoder->vb, nullptr);
- vorbis_bitrate_addblock(&encoder->vb);
+ while (vorbis_analysis_blockout(&encoder.vd, &encoder.vb) == 1) {
+ vorbis_analysis(&encoder.vb, nullptr);
+ vorbis_bitrate_addblock(&encoder.vb);
ogg_packet packet;
- while (vorbis_bitrate_flushpacket(&encoder->vd, &packet))
- encoder->stream.PacketIn(packet);
+ while (vorbis_bitrate_flushpacket(&encoder.vd, &packet))
+ encoder.stream.PacketIn(packet);
}
}
static bool
vorbis_encoder_flush(Encoder *_encoder, gcc_unused Error &error)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
- encoder->stream.Flush();
+ encoder.stream.Flush();
return true;
}
static bool
vorbis_encoder_pre_tag(Encoder *_encoder, gcc_unused Error &error)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
- vorbis_analysis_wrote(&encoder->vd, 0);
+ vorbis_analysis_wrote(&encoder.vd, 0);
vorbis_encoder_blockout(encoder);
/* reinitialize vorbis_dsp_state and vorbis_block to reset the
end-of-stream marker */
- vorbis_block_clear(&encoder->vb);
- vorbis_dsp_clear(&encoder->vd);
- vorbis_analysis_init(&encoder->vd, &encoder->vi);
- vorbis_block_init(&encoder->vd, &encoder->vb);
+ vorbis_block_clear(&encoder.vb);
+ vorbis_dsp_clear(&encoder.vd);
+ vorbis_analysis_init(&encoder.vd, &encoder.vi);
+ vorbis_block_init(&encoder.vd, &encoder.vb);
- encoder->stream.Flush();
+ encoder.stream.Flush();
return true;
}
static void
-copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag *tag)
+copy_tag_to_vorbis_comment(vorbis_comment *vc, const Tag &tag)
{
- for (const auto &item : *tag) {
- char *name = g_ascii_strup(tag_item_names[item.type], -1);
+ for (const auto &item : tag) {
+ char name[64];
+ ToUpperASCII(name, tag_item_names[item.type], sizeof(name));
vorbis_comment_add_tag(vc, name, item.value);
- g_free(name);
}
}
static bool
-vorbis_encoder_tag(Encoder *_encoder, const Tag *tag,
+vorbis_encoder_tag(Encoder *_encoder, const Tag &tag,
gcc_unused Error &error)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
vorbis_comment comment;
/* write the vorbis_comment object */
@@ -293,11 +292,11 @@ vorbis_encoder_tag(Encoder *_encoder, const Tag *tag,
/* reset ogg_stream_state and begin a new stream */
- encoder->stream.Reinitialize(GenerateOggSerial());
+ encoder.stream.Reinitialize(GenerateOggSerial());
/* send that vorbis_comment to the ogg_stream_state */
- vorbis_encoder_headerout(encoder, &comment);
+ vorbis_encoder_headerout(encoder, comment);
vorbis_comment_clear(&comment);
return true;
@@ -317,19 +316,19 @@ vorbis_encoder_write(Encoder *_encoder,
const void *data, size_t length,
gcc_unused Error &error)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
- unsigned num_frames = length / encoder->audio_format.GetFrameSize();
+ unsigned num_frames = length / encoder.audio_format.GetFrameSize();
/* this is for only 16-bit audio */
- interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&encoder->vd,
+ interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&encoder.vd,
num_frames),
(const float *)data,
num_frames,
- encoder->audio_format.channels);
+ encoder.audio_format.channels);
- vorbis_analysis_wrote(&encoder->vd, num_frames);
+ vorbis_analysis_wrote(&encoder.vd, num_frames);
vorbis_encoder_blockout(encoder);
return true;
}
@@ -337,9 +336,9 @@ vorbis_encoder_write(Encoder *_encoder,
static size_t
vorbis_encoder_read(Encoder *_encoder, void *dest, size_t length)
{
- struct vorbis_encoder *encoder = (struct vorbis_encoder *)_encoder;
+ struct vorbis_encoder &encoder = *(struct vorbis_encoder *)_encoder;
- return encoder->stream.PageOut(dest, length);
+ return encoder.stream.PageOut(dest, length);
}
static const char *
diff --git a/src/encoder/plugins/VorbisEncoderPlugin.hxx b/src/encoder/plugins/VorbisEncoderPlugin.hxx
index 80703bf88..a6d1c46d2 100644
--- a/src/encoder/plugins/VorbisEncoderPlugin.hxx
+++ b/src/encoder/plugins/VorbisEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/encoder/plugins/WaveEncoderPlugin.cxx b/src/encoder/plugins/WaveEncoderPlugin.cxx
index 97a26e821..3493bed3a 100644
--- a/src/encoder/plugins/WaveEncoderPlugin.cxx
+++ b/src/encoder/plugins/WaveEncoderPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -79,7 +79,7 @@ fill_wave_header(struct wave_header *header, int channels, int bits,
}
static Encoder *
-wave_encoder_init(gcc_unused const config_param &param,
+wave_encoder_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
WaveEncoder *encoder = new WaveEncoder();
diff --git a/src/encoder/plugins/WaveEncoderPlugin.hxx b/src/encoder/plugins/WaveEncoderPlugin.hxx
index 341b98adc..878985612 100644
--- a/src/encoder/plugins/WaveEncoderPlugin.hxx
+++ b/src/encoder/plugins/WaveEncoderPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/BufferedSocket.cxx b/src/event/BufferedSocket.cxx
index 939824baa..40aea6618 100644
--- a/src/event/BufferedSocket.cxx
+++ b/src/event/BufferedSocket.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "BufferedSocket.hxx"
-#include "system/SocketError.hxx"
+#include "net/SocketError.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Compiler.h"
diff --git a/src/event/BufferedSocket.hxx b/src/event/BufferedSocket.hxx
index b1882de2f..1478f82ca 100644
--- a/src/event/BufferedSocket.hxx
+++ b/src/event/BufferedSocket.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/Call.cxx b/src/event/Call.cxx
index bc16c4e95..216d4a5e8 100644
--- a/src/event/Call.cxx
+++ b/src/event/Call.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/Call.hxx b/src/event/Call.hxx
index 808965de1..f16337ac3 100644
--- a/src/event/Call.hxx
+++ b/src/event/Call.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/DeferredMonitor.cxx b/src/event/DeferredMonitor.cxx
index 3e824012f..7d23746de 100644
--- a/src/event/DeferredMonitor.cxx
+++ b/src/event/DeferredMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/DeferredMonitor.hxx b/src/event/DeferredMonitor.hxx
index c4aa605fc..2697a7226 100644
--- a/src/event/DeferredMonitor.hxx
+++ b/src/event/DeferredMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/FullyBufferedSocket.cxx b/src/event/FullyBufferedSocket.cxx
index 457add2b0..ba7f7b455 100644
--- a/src/event/FullyBufferedSocket.cxx
+++ b/src/event/FullyBufferedSocket.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "FullyBufferedSocket.hxx"
-#include "system/SocketError.hxx"
+#include "net/SocketError.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Compiler.h"
diff --git a/src/event/FullyBufferedSocket.hxx b/src/event/FullyBufferedSocket.hxx
index b03152be2..77b5c4416 100644
--- a/src/event/FullyBufferedSocket.hxx
+++ b/src/event/FullyBufferedSocket.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/IdleMonitor.cxx b/src/event/IdleMonitor.cxx
index 4af656a22..32b412825 100644
--- a/src/event/IdleMonitor.cxx
+++ b/src/event/IdleMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/IdleMonitor.hxx b/src/event/IdleMonitor.hxx
index 8d4d2681a..c7e9e4035 100644
--- a/src/event/IdleMonitor.hxx
+++ b/src/event/IdleMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx
index 1bac7c551..fca1f516f 100644
--- a/src/event/Loop.cxx
+++ b/src/event/Loop.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/Loop.hxx b/src/event/Loop.hxx
index 56804dc81..4001e31a0 100644
--- a/src/event/Loop.hxx
+++ b/src/event/Loop.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/MultiSocketMonitor.cxx b/src/event/MultiSocketMonitor.cxx
index ef77de425..6fc420b8d 100644
--- a/src/event/MultiSocketMonitor.cxx
+++ b/src/event/MultiSocketMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/MultiSocketMonitor.hxx b/src/event/MultiSocketMonitor.hxx
index b40ee8caa..eb6f51aa8 100644
--- a/src/event/MultiSocketMonitor.hxx
+++ b/src/event/MultiSocketMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroup.hxx b/src/event/PollGroup.hxx
index a2f176860..f376d50ca 100644
--- a/src/event/PollGroup.hxx
+++ b/src/event/PollGroup.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroupEPoll.hxx b/src/event/PollGroupEPoll.hxx
index d8edb8a1f..9457823a6 100644
--- a/src/event/PollGroupEPoll.hxx
+++ b/src/event/PollGroupEPoll.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroupPoll.cxx b/src/event/PollGroupPoll.cxx
index 402f8616f..b961c3f90 100644
--- a/src/event/PollGroupPoll.cxx
+++ b/src/event/PollGroupPoll.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroupPoll.hxx b/src/event/PollGroupPoll.hxx
index f7a3ccb4f..8d73280b4 100644
--- a/src/event/PollGroupPoll.hxx
+++ b/src/event/PollGroupPoll.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroupWinSelect.cxx b/src/event/PollGroupWinSelect.cxx
index 26c8abd46..796f699e2 100644
--- a/src/event/PollGroupWinSelect.cxx
+++ b/src/event/PollGroupWinSelect.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollGroupWinSelect.hxx b/src/event/PollGroupWinSelect.hxx
index d01067709..276a602a6 100644
--- a/src/event/PollGroupWinSelect.hxx
+++ b/src/event/PollGroupWinSelect.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/PollResultGeneric.hxx b/src/event/PollResultGeneric.hxx
index 35daf7f08..3dbeda0e4 100644
--- a/src/event/PollResultGeneric.hxx
+++ b/src/event/PollResultGeneric.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/ServerSocket.cxx b/src/event/ServerSocket.cxx
index 313f0a6cf..f82c533c3 100644
--- a/src/event/ServerSocket.cxx
+++ b/src/event/ServerSocket.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,10 +19,14 @@
#include "config.h"
#include "ServerSocket.hxx"
-#include "system/SocketUtil.hxx"
-#include "system/SocketError.hxx"
+#include "net/StaticSocketAddress.hxx"
+#include "net/AllocatedSocketAddress.hxx"
+#include "net/SocketAddress.hxx"
+#include "net/SocketUtil.hxx"
+#include "net/SocketError.hxx"
+#include "net/Resolver.hxx"
+#include "net/ToString.hxx"
#include "event/SocketMonitor.hxx"
-#include "system/Resolver.hxx"
#include "system/fd_util.h"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
@@ -52,39 +56,35 @@
#include <netdb.h>
#endif
-#define DEFAULT_PORT 6600
-
class OneServerSocket final : private SocketMonitor {
ServerSocket &parent;
const unsigned serial;
+#ifdef HAVE_UN
AllocatedPath path;
+#endif
- size_t address_length;
- struct sockaddr *address;
+ const AllocatedSocketAddress address;
public:
+ template<typename A>
OneServerSocket(EventLoop &_loop, ServerSocket &_parent,
unsigned _serial,
- const struct sockaddr *_address,
- size_t _address_length)
+ A &&_address)
:SocketMonitor(_loop),
parent(_parent), serial(_serial),
+#ifdef HAVE_UN
path(AllocatedPath::Null()),
- address_length(_address_length),
- address((sockaddr *)xmemdup(_address, _address_length))
+#endif
+ address(std::forward<A>(_address))
{
- assert(_address != nullptr);
- assert(_address_length > 0);
}
OneServerSocket(const OneServerSocket &other) = delete;
OneServerSocket &operator=(const OneServerSocket &other) = delete;
~OneServerSocket() {
- free(address);
-
if (IsDefined())
Close();
}
@@ -93,11 +93,13 @@ public:
return serial;
}
+#ifdef HAVE_UN
void SetPath(AllocatedPath &&_path) {
assert(path.IsNull());
path = std::move(_path);
}
+#endif
bool Open(Error &error);
@@ -106,7 +108,7 @@ public:
gcc_pure
std::string ToString() const {
- return sockaddr_to_string(address, address_length);
+ return ::ToString(address);
}
void SetFD(int _fd) {
@@ -150,10 +152,10 @@ get_remote_uid(int fd)
inline void
OneServerSocket::Accept()
{
- struct sockaddr_storage peer_address;
+ StaticSocketAddress peer_address;
size_t peer_address_length = sizeof(peer_address);
int peer_fd =
- accept_cloexec_nonblock(Get(), (struct sockaddr*)&peer_address,
+ accept_cloexec_nonblock(Get(), peer_address.GetAddress(),
&peer_address_length);
if (peer_fd < 0) {
const SocketErrorMessage msg;
@@ -162,6 +164,8 @@ OneServerSocket::Accept()
return;
}
+ peer_address.SetSize(peer_address_length);
+
if (socket_keepalive(peer_fd)) {
const SocketErrorMessage msg;
FormatError(server_socket_domain,
@@ -169,9 +173,8 @@ OneServerSocket::Accept()
(const char *)msg);
}
- parent.OnAccept(peer_fd,
- (const sockaddr &)peer_address,
- peer_address_length, get_remote_uid(peer_fd));
+ parent.OnAccept(peer_fd, peer_address,
+ get_remote_uid(peer_fd));
}
bool
@@ -186,19 +189,21 @@ OneServerSocket::Open(Error &error)
{
assert(!IsDefined());
- int _fd = socket_bind_listen(address->sa_family,
+ int _fd = socket_bind_listen(address.GetFamily(),
SOCK_STREAM, 0,
- address, address_length, 5,
+ address, 5,
error);
if (_fd < 0)
return false;
+#ifdef HAVE_UN
/* allow everybody to connect */
if (!path.IsNull())
chmod(path.c_str(), 0666);
+#endif
- /* register in the GLib main loop */
+ /* register in the EventLoop */
SetFD(_fd);
@@ -282,10 +287,19 @@ ServerSocket::Close()
}
OneServerSocket &
-ServerSocket::AddAddress(const sockaddr &address, size_t address_length)
+ServerSocket::AddAddress(SocketAddress address)
{
sockets.emplace_back(loop, *this, next_serial,
- &address, address_length);
+ address);
+
+ return sockets.back();
+}
+
+OneServerSocket &
+ServerSocket::AddAddress(AllocatedSocketAddress &&address)
+{
+ sockets.emplace_back(loop, *this, next_serial,
+ std::move(address));
return sockets.back();
}
@@ -295,17 +309,18 @@ ServerSocket::AddFD(int fd, Error &error)
{
assert(fd >= 0);
- struct sockaddr_storage address;
+ StaticSocketAddress address;
socklen_t address_length = sizeof(address);
- if (getsockname(fd, (struct sockaddr *)&address,
+ if (getsockname(fd, address.GetAddress(),
&address_length) < 0) {
SetSocketError(error);
error.AddPrefix("Failed to get socket address: ");
return false;
}
- OneServerSocket &s = AddAddress((const sockaddr &)address,
- address_length);
+ address.SetSize(address_length);
+
+ OneServerSocket &s = AddAddress(address);
s.SetFD(fd);
return true;
@@ -322,7 +337,7 @@ ServerSocket::AddPortIPv4(unsigned port)
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
- AddAddress((const sockaddr &)sin, sizeof(sin));
+ AddAddress({(const sockaddr *)&sin, sizeof(sin)});
}
#ifdef HAVE_IPV6
@@ -335,7 +350,7 @@ ServerSocket::AddPortIPv6(unsigned port)
sin.sin6_port = htons(port);
sin.sin6_family = AF_INET6;
- AddAddress((const sockaddr &)sin, sizeof(sin));
+ AddAddress({(const sockaddr *)&sin, sizeof(sin)});
}
/**
@@ -394,7 +409,7 @@ ServerSocket::AddHost(const char *hostname, unsigned port, Error &error)
return false;
for (const struct addrinfo *i = ai; i != nullptr; i = i->ai_next)
- AddAddress(*i->ai_addr, i->ai_addrlen);
+ AddAddress(SocketAddress(i->ai_addr, i->ai_addrlen));
freeaddrinfo(ai);
@@ -414,21 +429,14 @@ bool
ServerSocket::AddPath(AllocatedPath &&path, Error &error)
{
#ifdef HAVE_UN
- struct sockaddr_un s_un;
-
- const size_t path_length = path.length();
- if (path_length >= sizeof(s_un.sun_path)) {
- error.Set(server_socket_domain,
- "UNIX socket path is too long");
- return false;
- }
+ (void)error;
RemoveFile(path);
- s_un.sun_family = AF_UNIX;
- memcpy(s_un.sun_path, path.c_str(), path_length + 1);
+ AllocatedSocketAddress address;
+ address.SetLocal(path.c_str());
- OneServerSocket &s = AddAddress((const sockaddr &)s_un, sizeof(s_un));
+ OneServerSocket &s = AddAddress(std::move(address));
s.SetPath(std::move(path));
return true;
diff --git a/src/event/ServerSocket.hxx b/src/event/ServerSocket.hxx
index 4c3fd9f1d..a59ac3f2a 100644
--- a/src/event/ServerSocket.hxx
+++ b/src/event/ServerSocket.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,16 +24,11 @@
#include <stddef.h>
-struct sockaddr;
+class SocketAddress;
+class AllocatedSocketAddress;
class EventLoop;
class Error;
class AllocatedPath;
-
-typedef void (*server_socket_callback_t)(int fd,
- const struct sockaddr *address,
- size_t address_length, int uid,
- void *ctx);
-
class OneServerSocket;
/**
@@ -57,7 +52,8 @@ public:
}
private:
- OneServerSocket &AddAddress(const sockaddr &address, size_t length);
+ OneServerSocket &AddAddress(SocketAddress address);
+ OneServerSocket &AddAddress(AllocatedSocketAddress &&address);
/**
* Add a listener on a port on all IPv4 interfaces.
@@ -78,8 +74,7 @@ public:
* Add a listener on a port on all interfaces.
*
* @param port the TCP port
- * @param error_r location to store the error occurring, or nullptr to
- * ignore errors
+ * @param error location to store the error occurring
* @return true on success
*/
bool AddPort(unsigned port, Error &error);
@@ -90,8 +85,7 @@ public:
*
* @param hostname the host name to be resolved
* @param port the TCP port
- * @param error_r location to store the error occurring, or nullptr to
- * ignore errors
+ * @param error location to store the error occurring
* @return true on success
*/
bool AddHost(const char *hostname, unsigned port, Error &error);
@@ -100,8 +94,7 @@ public:
* Add a listener on a Unix domain socket.
*
* @param path the absolute socket path
- * @param error_r location to store the error occurring, or nullptr to
- * ignore errors
+ * @param error location to store the error occurring
* @return true on success
*/
bool AddPath(AllocatedPath &&path, Error &error);
@@ -117,8 +110,7 @@ public:
void Close();
protected:
- virtual void OnAccept(int fd, const sockaddr &address,
- size_t address_length, int uid) = 0;
+ virtual void OnAccept(int fd, SocketAddress address, int uid) = 0;
};
#endif
diff --git a/src/event/SignalMonitor.cxx b/src/event/SignalMonitor.cxx
index 2d8fe681f..c9a7085eb 100644
--- a/src/event/SignalMonitor.cxx
+++ b/src/event/SignalMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/SignalMonitor.hxx b/src/event/SignalMonitor.hxx
index a41e57ef9..6bed61c66 100644
--- a/src/event/SignalMonitor.hxx
+++ b/src/event/SignalMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/SocketMonitor.cxx b/src/event/SocketMonitor.cxx
index 69207287d..00e6e6c45 100644
--- a/src/event/SocketMonitor.cxx
+++ b/src/event/SocketMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/SocketMonitor.hxx b/src/event/SocketMonitor.hxx
index 56d4273f0..4231e3ec0 100644
--- a/src/event/SocketMonitor.hxx
+++ b/src/event/SocketMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/TimeoutMonitor.cxx b/src/event/TimeoutMonitor.cxx
index 007e8aa2c..1bda47c5c 100644
--- a/src/event/TimeoutMonitor.cxx
+++ b/src/event/TimeoutMonitor.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/TimeoutMonitor.hxx b/src/event/TimeoutMonitor.hxx
index 414d48aa6..00289a0db 100644
--- a/src/event/TimeoutMonitor.hxx
+++ b/src/event/TimeoutMonitor.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/event/WakeFD.hxx b/src/event/WakeFD.hxx
index c6222b59c..4b3792111 100644
--- a/src/event/WakeFD.hxx
+++ b/src/event/WakeFD.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/FilterConfig.cxx b/src/filter/FilterConfig.cxx
index d8c1fc6c2..c5f24362c 100644
--- a/src/filter/FilterConfig.cxx
+++ b/src/filter/FilterConfig.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,10 +21,11 @@
#include "FilterConfig.hxx"
#include "plugins/ChainFilterPlugin.hxx"
#include "FilterPlugin.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Param.hxx"
#include "config/ConfigOption.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigError.hxx"
+#include "config/Block.hxx"
#include "util/Error.hxx"
#include <algorithm>
@@ -34,8 +35,8 @@
static bool
filter_chain_append_new(Filter &chain, const char *template_name, Error &error)
{
- const struct config_param *cfg =
- config_find_block(CONF_AUDIO_FILTER, "name", template_name);
+ const auto *cfg = config_find_block(ConfigBlockOption::AUDIO_FILTER,
+ "name", template_name);
if (cfg == nullptr) {
error.Format(config_domain,
"filter template not found: %s",
diff --git a/src/filter/FilterConfig.hxx b/src/filter/FilterConfig.hxx
index 1018eed51..1c6f14f73 100644
--- a/src/filter/FilterConfig.hxx
+++ b/src/filter/FilterConfig.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@ class Error;
* configured filter sections.
* @param chain the chain to append filters on
* @param spec the filter chain specification
- * @param error_r space to return an error description
+ * @param error space to return an error description
* @return true on success
*/
bool
diff --git a/src/filter/FilterInternal.hxx b/src/filter/FilterInternal.hxx
index d2e619540..6969e8a18 100644
--- a/src/filter/FilterInternal.hxx
+++ b/src/filter/FilterInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,12 +38,10 @@ public:
/**
* Opens the filter, preparing it for FilterPCM().
*
- * @param filter the filter object
* @param af the audio format of incoming data; the
* plugin may modify the object to enforce another input
* format
- * @param error location to store the error occurring, or nullptr
- * to ignore errors.
+ * @param error location to store the error occurring
* @return the format of outgoing data or
* AudioFormat::Undefined() on error
*/
@@ -57,10 +55,8 @@ public:
/**
* Filters a block of PCM data.
*
- * @param filter the filter object
* @param src the input buffer
- * @param error location to store the error occurring, or nullptr
- * to ignore errors.
+ * @param error location to store the error occurring
* @return the destination buffer on success (will be
* invalidated by Close() or FilterPCM()), nullptr on
* error
diff --git a/src/filter/FilterPlugin.cxx b/src/filter/FilterPlugin.cxx
index 98314f771..93d1942a0 100644
--- a/src/filter/FilterPlugin.cxx
+++ b/src/filter/FilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "FilterPlugin.hxx"
#include "FilterRegistry.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "config/ConfigError.hxx"
#include "util/Error.hxx"
@@ -28,20 +28,20 @@
Filter *
filter_new(const struct filter_plugin *plugin,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
assert(plugin != nullptr);
assert(!error.IsDefined());
- return plugin->init(param, error);
+ return plugin->init(block, error);
}
Filter *
-filter_configured_new(const config_param &param, Error &error)
+filter_configured_new(const ConfigBlock &block, Error &error)
{
assert(!error.IsDefined());
- const char *plugin_name = param.GetBlockValue("plugin");
+ const char *plugin_name = block.GetBlockValue("plugin");
if (plugin_name == nullptr) {
error.Set(config_domain, "No filter plugin specified");
return nullptr;
@@ -54,5 +54,5 @@ filter_configured_new(const config_param &param, Error &error)
return nullptr;
}
- return filter_new(plugin, param, error);
+ return filter_new(plugin, block, error);
}
diff --git a/src/filter/FilterPlugin.hxx b/src/filter/FilterPlugin.hxx
index 443d29881..68ad74240 100644
--- a/src/filter/FilterPlugin.hxx
+++ b/src/filter/FilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#ifndef MPD_FILTER_PLUGIN_HXX
#define MPD_FILTER_PLUGIN_HXX
-struct config_param;
+struct ConfigBlock;
class Filter;
class Error;
@@ -36,32 +36,32 @@ struct filter_plugin {
/**
* Allocates and configures a filter.
*/
- Filter *(*init)(const config_param &param, Error &error);
+ Filter *(*init)(const ConfigBlock &block, Error &error);
};
/**
* Creates a new instance of the specified filter plugin.
*
* @param plugin the filter plugin
- * @param param optional configuration section
+ * @param block configuration section
* @param error location to store the error occurring, or nullptr to
* ignore errors.
* @return a new filter object, or nullptr on error
*/
Filter *
filter_new(const struct filter_plugin *plugin,
- const config_param &param, Error &error);
+ const ConfigBlock &block, Error &error);
/**
* Creates a new filter, loads configuration and the plugin name from
* the specified configuration section.
*
- * @param param the configuration section
+ * @param block the configuration section
* @param error location to store the error occurring, or nullptr to
* ignore errors.
* @return a new filter object, or nullptr on error
*/
Filter *
-filter_configured_new(const config_param &param, Error &error);
+filter_configured_new(const ConfigBlock &block, Error &error);
#endif
diff --git a/src/filter/FilterRegistry.cxx b/src/filter/FilterRegistry.cxx
index 286fb8db3..8c679940f 100644
--- a/src/filter/FilterRegistry.cxx
+++ b/src/filter/FilterRegistry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/FilterRegistry.hxx b/src/filter/FilterRegistry.hxx
index 24618a87a..51fac615f 100644
--- a/src/filter/FilterRegistry.hxx
+++ b/src/filter/FilterRegistry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/plugins/AutoConvertFilterPlugin.cxx b/src/filter/plugins/AutoConvertFilterPlugin.cxx
index 8586cb86e..52918080e 100644
--- a/src/filter/plugins/AutoConvertFilterPlugin.cxx
+++ b/src/filter/plugins/AutoConvertFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include "filter/FilterInternal.hxx"
#include "filter/FilterRegistry.hxx"
#include "AudioFormat.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "util/ConstBuffer.hxx"
#include <assert.h>
@@ -70,7 +70,7 @@ AutoConvertFilter::Open(AudioFormat &in_audio_format, Error &error)
if (in_audio_format != child_audio_format) {
/* yes - create a convert_filter */
- const config_param empty;
+ const ConfigBlock empty;
convert = filter_new(&convert_filter_plugin, empty, error);
if (convert == nullptr) {
filter->Close();
diff --git a/src/filter/plugins/AutoConvertFilterPlugin.hxx b/src/filter/plugins/AutoConvertFilterPlugin.hxx
index c5dfdd2f6..1b9061331 100644
--- a/src/filter/plugins/AutoConvertFilterPlugin.hxx
+++ b/src/filter/plugins/AutoConvertFilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/plugins/ChainFilterPlugin.cxx b/src/filter/plugins/ChainFilterPlugin.cxx
index 4aeee69af..b965295f7 100644
--- a/src/filter/plugins/ChainFilterPlugin.cxx
+++ b/src/filter/plugins/ChainFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -70,7 +70,7 @@ private:
static constexpr Domain chain_filter_domain("chain_filter");
static Filter *
-chain_filter_init(gcc_unused const config_param &param,
+chain_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new ChainFilter();
diff --git a/src/filter/plugins/ChainFilterPlugin.hxx b/src/filter/plugins/ChainFilterPlugin.hxx
index b36aa3322..8f346e178 100644
--- a/src/filter/plugins/ChainFilterPlugin.hxx
+++ b/src/filter/plugins/ChainFilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,7 +33,7 @@ class Filter;
* Creates a new filter chain.
*/
Filter *
-filter_chain_new(void);
+filter_chain_new();
/**
* Appends a new filter at the end of the filter chain. You must call
diff --git a/src/filter/plugins/ConvertFilterPlugin.cxx b/src/filter/plugins/ConvertFilterPlugin.cxx
index 5c6a07ba1..18053abd0 100644
--- a/src/filter/plugins/ConvertFilterPlugin.cxx
+++ b/src/filter/plugins/ConvertFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -59,7 +59,7 @@ public:
};
static Filter *
-convert_filter_init(gcc_unused const config_param &param,
+convert_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new ConvertFilter();
diff --git a/src/filter/plugins/ConvertFilterPlugin.hxx b/src/filter/plugins/ConvertFilterPlugin.hxx
index bb4673651..8dd0bcd8e 100644
--- a/src/filter/plugins/ConvertFilterPlugin.hxx
+++ b/src/filter/plugins/ConvertFilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/filter/plugins/NormalizeFilterPlugin.cxx b/src/filter/plugins/NormalizeFilterPlugin.cxx
index 372ab53ac..77e8c1535 100644
--- a/src/filter/plugins/NormalizeFilterPlugin.cxx
+++ b/src/filter/plugins/NormalizeFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -42,7 +42,7 @@ public:
};
static Filter *
-normalize_filter_init(gcc_unused const config_param &param,
+normalize_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new NormalizeFilter();
diff --git a/src/filter/plugins/NullFilterPlugin.cxx b/src/filter/plugins/NullFilterPlugin.cxx
index ebd8e4ec5..0bd8170f0 100644
--- a/src/filter/plugins/NullFilterPlugin.cxx
+++ b/src/filter/plugins/NullFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -48,7 +48,7 @@ public:
};
static Filter *
-null_filter_init(gcc_unused const config_param &param,
+null_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new NullFilter();
diff --git a/src/filter/plugins/ReplayGainFilterPlugin.cxx b/src/filter/plugins/ReplayGainFilterPlugin.cxx
index f76e48e37..ca1119331 100644
--- a/src/filter/plugins/ReplayGainFilterPlugin.cxx
+++ b/src/filter/plugins/ReplayGainFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -150,7 +150,7 @@ ReplayGainFilter::Update()
}
static Filter *
-replay_gain_filter_init(gcc_unused const config_param &param,
+replay_gain_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new ReplayGainFilter();
diff --git a/src/filter/plugins/ReplayGainFilterPlugin.hxx b/src/filter/plugins/ReplayGainFilterPlugin.hxx
index 346541b97..ec0cafc60 100644
--- a/src/filter/plugins/ReplayGainFilterPlugin.hxx
+++ b/src/filter/plugins/ReplayGainFilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,9 +38,9 @@ replay_gain_filter_set_mixer(Filter *_filter, Mixer *mixer,
unsigned base);
/**
- * Sets a new #replay_gain_info at the beginning of a new song.
+ * Sets a new #ReplayGainInfo at the beginning of a new song.
*
- * @param info the new #replay_gain_info value, or nullptr if no replay
+ * @param info the new #ReplayGainInfo value, or nullptr if no replay
* gain data is available for the current song
*/
void
diff --git a/src/filter/plugins/RouteFilterPlugin.cxx b/src/filter/plugins/RouteFilterPlugin.cxx
index 4094119f2..11eb534c9 100644
--- a/src/filter/plugins/RouteFilterPlugin.cxx
+++ b/src/filter/plugins/RouteFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,7 +41,7 @@
#include "config.h"
#include "config/ConfigError.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "AudioFormat.hxx"
#include "filter/FilterPlugin.hxx"
#include "filter/FilterInternal.hxx"
@@ -114,11 +114,11 @@ public:
* a>b, c>d, e>f, ...
* where a... are non-unique, non-negative integers
* and input channel a gets copied to output channel b, etc.
- * @param param the configuration block to read
+ * @param block the configuration block to read
* @param filter a route_filter whose min_channels and sources[] to set
* @return true on success, false on error
*/
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class Filter */
AudioFormat Open(AudioFormat &af, Error &error) override;
@@ -128,7 +128,7 @@ public:
};
bool
-RouteFilter::Configure(const config_param &param, Error &error) {
+RouteFilter::Configure(const ConfigBlock &block, Error &error) {
/* TODO:
* With a more clever way of marking "don't copy to output N",
@@ -142,7 +142,7 @@ RouteFilter::Configure(const config_param &param, Error &error) {
min_output_channels = 0;
// A cowardly default, just passthrough stereo
- const char *routes = param.GetBlockValue("routes", "0>0, 1>1");
+ const char *routes = block.GetBlockValue("routes", "0>0, 1>1");
while (true) {
routes = StripLeft(routes);
@@ -205,10 +205,10 @@ RouteFilter::Configure(const config_param &param, Error &error) {
}
static Filter *
-route_filter_init(const config_param &param, Error &error)
+route_filter_init(const ConfigBlock &block, Error &error)
{
RouteFilter *filter = new RouteFilter();
- if (!filter->Configure(param, error)) {
+ if (!filter->Configure(block, error)) {
delete filter;
return nullptr;
}
diff --git a/src/filter/plugins/VolumeFilterPlugin.cxx b/src/filter/plugins/VolumeFilterPlugin.cxx
index 39188da00..4a7abb953 100644
--- a/src/filter/plugins/VolumeFilterPlugin.cxx
+++ b/src/filter/plugins/VolumeFilterPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -50,7 +50,7 @@ public:
};
static Filter *
-volume_filter_init(gcc_unused const config_param &param,
+volume_filter_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new VolumeFilter();
diff --git a/src/filter/plugins/VolumeFilterPlugin.hxx b/src/filter/plugins/VolumeFilterPlugin.hxx
index b5317dc6f..93191b2d3 100644
--- a/src/filter/plugins/VolumeFilterPlugin.hxx
+++ b/src/filter/plugins/VolumeFilterPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/AllocatedPath.cxx b/src/fs/AllocatedPath.cxx
index ceaad73ea..8b03ed2f1 100644
--- a/src/fs/AllocatedPath.cxx
+++ b/src/fs/AllocatedPath.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,33 +24,14 @@
#include "util/Error.hxx"
#include "Compiler.h"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
-#include <string.h>
-
-#ifdef HAVE_GLIB
-
-inline AllocatedPath::AllocatedPath(Donate, pointer _value)
- :value(_value) {
- g_free(_value);
-}
-
-#endif
-
/* no inlining, please */
AllocatedPath::~AllocatedPath() {}
AllocatedPath
AllocatedPath::FromUTF8(const char *path_utf8)
{
-#ifdef HAVE_GLIB
- char *path = ::PathFromUTF8(path_utf8);
- if (path == nullptr)
- return AllocatedPath::Null();
-
- return AllocatedPath(Donate(), path);
+#if defined(HAVE_FS_CHARSET) || defined(WIN32)
+ return AllocatedPath(::PathFromUTF8(path_utf8));
#else
return FromFS(path_utf8);
#endif
@@ -80,38 +61,16 @@ AllocatedPath::ToUTF8() const
return ::PathToUTF8(c_str());
}
-const char *
-AllocatedPath::RelativeFS(const char *other_fs) const
-{
- const size_t l = length();
- if (memcmp(data(), other_fs, l) != 0)
- return nullptr;
-
- other_fs += l;
- if (*other_fs != 0) {
- if (!PathTraitsFS::IsSeparator(*other_fs))
- /* mismatch */
- return nullptr;
-
- /* skip remaining path separators */
- do {
- ++other_fs;
- } while (PathTraitsFS::IsSeparator(*other_fs));
- }
-
- return other_fs;
-}
-
void
AllocatedPath::ChopSeparators()
{
size_t l = length();
- const char *p = data();
+ const auto *p = data();
while (l >= 2 && PathTraitsFS::IsSeparator(p[l - 1])) {
--l;
-#if GCC_CHECK_VERSION(4,7) && !defined(__clang__)
+#if GCC_CHECK_VERSION(4,7)
value.pop_back();
#else
value.erase(value.end() - 1, value.end());
diff --git a/src/fs/AllocatedPath.hxx b/src/fs/AllocatedPath.hxx
index c345470c8..e733c00a9 100644
--- a/src/fs/AllocatedPath.hxx
+++ b/src/fs/AllocatedPath.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "Traits.hxx"
#include "Path.hxx"
+#include <cstddef>
#include <utility>
#include <string>
@@ -44,13 +45,7 @@ class AllocatedPath {
string value;
- struct Donate {};
-
- /**
- * Donate the allocated pointer to a new #AllocatedPath object.
- */
- AllocatedPath(Donate, pointer _value);
-
+ AllocatedPath(std::nullptr_t):value() {}
AllocatedPath(const_pointer _value):value(_value) {}
AllocatedPath(string &&_value):value(std::move(_value)) {}
@@ -82,7 +77,7 @@ public:
*/
gcc_const
static AllocatedPath Null() {
- return AllocatedPath("");
+ return AllocatedPath(nullptr);
}
gcc_pure
@@ -169,11 +164,21 @@ public:
return *this;
}
+ gcc_pure
+ bool operator==(const AllocatedPath &other) const {
+ return value == other.value;
+ }
+
+ gcc_pure
+ bool operator!=(const AllocatedPath &other) const {
+ return value != other.value;
+ }
+
/**
* Allows the caller to "steal" the internal value by
* providing a rvalue reference to the std::string attribute.
*/
- std::string &&Steal() {
+ string &&Steal() {
return std::move(value);
}
@@ -244,7 +249,9 @@ public:
* nullptr on mismatch.
*/
gcc_pure
- const char *RelativeFS(const char *other_fs) const;
+ const_pointer Relative(Path other_fs) const {
+ return PathTraitsFS::Relative(c_str(), other_fs.c_str());
+ }
/**
* Chop trailing directory separators.
@@ -252,7 +259,7 @@ public:
void ChopSeparators();
gcc_pure
- bool IsAbsolute() {
+ bool IsAbsolute() const {
return PathTraitsFS::IsAbsolute(c_str());
}
};
diff --git a/src/fs/Charset.cxx b/src/fs/Charset.cxx
index c634c9340..f0fc1063c 100644
--- a/src/fs/Charset.cxx
+++ b/src/fs/Charset.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,12 +21,14 @@
#include "Charset.hxx"
#include "Domain.hxx"
#include "Limits.hxx"
-#include "system/FatalError.hxx"
#include "Log.hxx"
-#include "Traits.hxx"
+#include "lib/icu/Converter.hxx"
+#include "util/Error.hxx"
+#include "util/AllocatedString.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
+#ifdef WIN32
+#include "lib/icu/Win32.hxx"
+#include <windows.h>
#endif
#include <algorithm>
@@ -34,130 +36,121 @@
#include <assert.h>
#include <string.h>
-#ifdef HAVE_GLIB
-
-/**
- * Maximal number of bytes required to represent path name in UTF-8
- * (including nul-terminator).
- * This value is a rought estimate of upper bound.
- * It's based on path name limit in bytes (MPD_PATH_MAX)
- * and assumption that some weird encoding could represent some UTF-8 4 byte
- * sequences with single byte.
- */
-static constexpr size_t MPD_PATH_MAX_UTF8 = (MPD_PATH_MAX - 1) * 4 + 1;
+#ifdef HAVE_FS_CHARSET
static std::string fs_charset;
-gcc_pure
-static bool
-IsSupportedCharset(const char *charset)
-{
- /* convert a space to check if the charset is valid */
- char *test = g_convert(" ", 1, charset, "UTF-8", nullptr, nullptr, nullptr);
- if (test == nullptr)
- return false;
+static IcuConverter *fs_converter;
- g_free(test);
- return true;
-}
-
-void
-SetFSCharset(const char *charset)
+bool
+SetFSCharset(const char *charset, Error &error)
{
assert(charset != nullptr);
+ assert(fs_converter == nullptr);
- if (!IsSupportedCharset(charset))
- FormatFatalError("invalid filesystem charset: %s", charset);
-
- fs_charset = charset;
+ fs_converter = IcuConverter::Create(charset, error);
+ if (fs_converter == nullptr)
+ return false;
FormatDebug(path_domain,
"SetFSCharset: fs charset is: %s", fs_charset.c_str());
+ return true;
}
#endif
+void
+DeinitFSCharset()
+{
+#ifdef HAVE_ICU_CONVERTER
+ delete fs_converter;
+ fs_converter = nullptr;
+#endif
+}
+
const char *
GetFSCharset()
{
-#ifdef HAVE_GLIB
+#ifdef HAVE_FS_CHARSET
return fs_charset.empty() ? "UTF-8" : fs_charset.c_str();
+#elif defined(WIN32)
+ return "ACP";
#else
return "UTF-8";
#endif
}
-static inline void FixSeparators(std::string &s)
+static inline PathTraitsUTF8::string &&
+FixSeparators(PathTraitsUTF8::string &&s)
{
-#ifdef WIN32
// For whatever reason GCC can't convert constexpr to value reference.
// This leads to link errors when passing separators directly.
- auto from = PathTraitsFS::SEPARATOR;
auto to = PathTraitsUTF8::SEPARATOR;
- std::replace(s.begin(), s.end(), from, to);
-#else
- (void)s;
-#endif
+ decltype(to) from = PathTraitsFS::SEPARATOR;
+
+ if (from != to)
+ /* convert backslash to slash on WIN32 */
+ std::replace(s.begin(), s.end(), from, to);
+
+ return std::move(s);
}
-std::string
-PathToUTF8(const char *path_fs)
+PathTraitsUTF8::string
+PathToUTF8(PathTraitsFS::const_pointer path_fs)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_fs != nullptr);
#endif
-#ifdef HAVE_GLIB
- if (fs_charset.empty()) {
+#ifdef WIN32
+ const auto buffer = WideCharToMultiByte(CP_UTF8, path_fs);
+ if (buffer.IsNull())
+ return PathTraitsUTF8::string();
+
+ return FixSeparators(PathTraitsUTF8::string(buffer.c_str()));
+#else
+#ifdef HAVE_FS_CHARSET
+ if (fs_converter == nullptr)
+#endif
+ return FixSeparators(path_fs);
+#ifdef HAVE_FS_CHARSET
+
+ const auto buffer = fs_converter->ToUTF8(path_fs);
+ if (buffer.IsNull())
+ return PathTraitsUTF8::string();
+
+ return FixSeparators(PathTraitsUTF8::string(buffer.c_str()));
#endif
- auto result = std::string(path_fs);
- FixSeparators(result);
- return result;
-#ifdef HAVE_GLIB
- }
-
- GIConv conv = g_iconv_open("utf-8", fs_charset.c_str());
- if (conv == reinterpret_cast<GIConv>(-1))
- return std::string();
-
- // g_iconv() does not need nul-terminator,
- // std::string could be created without it too.
- char path_utf8[MPD_PATH_MAX_UTF8 - 1];
- char *in = const_cast<char *>(path_fs);
- char *out = path_utf8;
- size_t in_left = strlen(path_fs);
- size_t out_left = sizeof(path_utf8);
-
- size_t ret = g_iconv(conv, &in, &in_left, &out, &out_left);
-
- g_iconv_close(conv);
-
- if (ret == static_cast<size_t>(-1) || in_left > 0)
- return std::string();
-
- auto result_path = std::string(path_utf8, sizeof(path_utf8) - out_left);
- FixSeparators(result_path);
- return result_path;
#endif
}
-#ifdef HAVE_GLIB
+#if defined(HAVE_FS_CHARSET) || defined(WIN32)
-char *
-PathFromUTF8(const char *path_utf8)
+PathTraitsFS::string
+PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8)
{
#if !CLANG_CHECK_VERSION(3,6)
/* disabled on clang due to -Wtautological-pointer-compare */
assert(path_utf8 != nullptr);
#endif
- if (fs_charset.empty())
- return g_strdup(path_utf8);
+#ifdef WIN32
+ const auto buffer = MultiByteToWideChar(CP_UTF8, path_utf8);
+ if (buffer.IsNull())
+ return PathTraitsFS::string();
+
+ return PathTraitsFS::string(buffer.c_str());
+#else
+ if (fs_converter == nullptr)
+ return path_utf8;
+
+ const auto buffer = fs_converter->FromUTF8(path_utf8);
+ if (buffer.IsNull())
+ return PathTraitsFS::string();
- return g_convert(path_utf8, -1,
- fs_charset.c_str(), "utf-8",
- nullptr, nullptr, nullptr);
+ return PathTraitsFS::string(buffer.c_str());
+#endif
}
#endif
diff --git a/src/fs/Charset.hxx b/src/fs/Charset.hxx
index 0a71d7c58..7ef19eba3 100644
--- a/src/fs/Charset.hxx
+++ b/src/fs/Charset.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,13 @@
#include "check.h"
#include "Compiler.h"
+#include "Traits.hxx"
-#include <string>
+#if (defined(HAVE_ICU) || defined(HAVE_ICONV)) && !defined(WIN32)
+#define HAVE_FS_CHARSET
+#endif
+
+class Error;
/**
* Gets file system character set name.
@@ -32,19 +37,26 @@ gcc_const
const char *
GetFSCharset();
+bool
+SetFSCharset(const char *charset, Error &error);
+
void
-SetFSCharset(const char *charset);
+DeinitFSCharset();
/**
* Convert the path to UTF-8.
* Returns empty string on error.
*/
gcc_pure gcc_nonnull_all
-std::string
-PathToUTF8(const char *path_fs);
+PathTraitsUTF8::string
+PathToUTF8(PathTraitsFS::const_pointer path_fs);
-gcc_malloc gcc_nonnull_all
-char *
-PathFromUTF8(const char *path_utf8);
+/**
+ * Convert the path from UTF-8.
+ * Returns empty string on error.
+ */
+gcc_pure gcc_nonnull_all
+PathTraitsFS::string
+PathFromUTF8(PathTraitsUTF8::const_pointer path_utf8);
#endif
diff --git a/src/fs/CheckFile.cxx b/src/fs/CheckFile.cxx
index a35443674..e900fe9af 100644
--- a/src/fs/CheckFile.cxx
+++ b/src/fs/CheckFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,7 @@
#include "CheckFile.hxx"
#include "Log.hxx"
#include "config/ConfigError.hxx"
-#include "FileSystem.hxx"
+#include "FileInfo.hxx"
#include "Path.hxx"
#include "AllocatedPath.hxx"
#include "DirectoryReader.hxx"
@@ -32,31 +32,37 @@
void
CheckDirectoryReadable(Path path_fs)
{
- struct stat st;
- if (!StatFile(path_fs, st)) {
- FormatErrno(config_domain,
- "Failed to stat directory \"%s\"",
- path_fs.c_str());
+ Error error;
+
+ FileInfo fi;
+ if (!GetFileInfo(path_fs, fi, error)) {
+ LogError(error);
return;
}
- if (!S_ISDIR(st.st_mode)) {
+ if (!fi.IsDirectory()) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
- "Not a directory: %s", path_fs.c_str());
+ "Not a directory: %s", path_utf8.c_str());
return;
}
#ifndef WIN32
- const auto x = AllocatedPath::Build(path_fs, ".");
- if (!StatFile(x, st) && errno == EACCES)
+ const auto x = AllocatedPath::Build(path_fs,
+ PathTraitsFS::CURRENT_DIRECTORY);
+ if (!GetFileInfo(x, fi) && errno == EACCES) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
"No permission to traverse (\"execute\") directory: %s",
- path_fs.c_str());
+ path_utf8.c_str());
+ }
#endif
const DirectoryReader reader(path_fs);
- if (reader.HasFailed() && errno == EACCES)
+ if (reader.HasFailed() && errno == EACCES) {
+ const auto path_utf8 = path_fs.ToUTF8();
FormatError(config_domain,
- "No permission to read directory: %s", path_fs.c_str());
-
+ "No permission to read directory: %s",
+ path_utf8.c_str());
+ }
}
diff --git a/src/fs/CheckFile.hxx b/src/fs/CheckFile.hxx
index 00559647d..52fe45f0a 100644
--- a/src/fs/CheckFile.hxx
+++ b/src/fs/CheckFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/Config.cxx b/src/fs/Config.cxx
index 6aa23005c..0b39a362f 100644
--- a/src/fs/Config.cxx
+++ b/src/fs/Config.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,40 +22,22 @@
#include "Charset.hxx"
#include "config/ConfigGlobal.hxx"
-#ifdef WIN32
-#include <windows.h> // for GetACP()
-#include <stdio.h> // for sprintf()
-#elif defined(HAVE_GLIB)
-#include <glib.h>
-#endif
-
-void
-ConfigureFS()
+bool
+ConfigureFS(Error &error)
{
-#if defined(HAVE_GLIB) || defined(WIN32)
- const char *charset = nullptr;
-
- charset = config_get_string(CONF_FS_CHARSET, nullptr);
- if (charset == nullptr) {
-#ifndef WIN32
- const gchar **encodings;
- g_get_filename_charsets(&encodings);
-
- if (encodings[0] != nullptr && *encodings[0] != '\0')
- charset = encodings[0];
+#ifdef HAVE_FS_CHARSET
+ const char *charset = config_get_string(ConfigOption::FS_CHARSET);
+ return charset == nullptr || SetFSCharset(charset, error);
#else
- /* Glib claims that file system encoding is always utf-8
- * on native Win32 (i.e. not Cygwin).
- * However this is true only if <gstdio.h> helpers are used.
- * MPD uses regular <stdio.h> functions.
- * Those functions use encoding determined by GetACP(). */
- static char win_charset[13];
- sprintf(win_charset, "cp%u", GetACP());
- charset = win_charset;
+ (void)error;
+ return true;
#endif
- }
+}
- if (charset != nullptr)
- SetFSCharset(charset);
+void
+DeinitFS()
+{
+#ifdef HAVE_FS_CHARSET
+ DeinitFSCharset();
#endif
}
diff --git a/src/fs/Config.hxx b/src/fs/Config.hxx
index d4f1709f5..1db710551 100644
--- a/src/fs/Config.hxx
+++ b/src/fs/Config.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,10 +22,15 @@
#include "check.h"
+class Error;
+
/**
* Performs global one-time initialization of this class.
*/
+bool
+ConfigureFS(Error &error);
+
void
-ConfigureFS();
+DeinitFS();
#endif
diff --git a/src/fs/DirectoryReader.hxx b/src/fs/DirectoryReader.hxx
index f77c0629f..ce27d2b9b 100644
--- a/src/fs/DirectoryReader.hxx
+++ b/src/fs/DirectoryReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,89 @@
#include "check.h"
#include "Path.hxx"
+#ifdef WIN32
+
+#include <windows.h>
+#include <tchar.h>
+
+/**
+ * Reader for directory entries.
+ */
+class DirectoryReader {
+ const HANDLE handle;
+ WIN32_FIND_DATA data;
+ bool first;
+
+ class MakeWildcardPath {
+ PathTraitsFS::pointer path;
+
+ public:
+ MakeWildcardPath(PathTraitsFS::const_pointer _path) {
+ auto l = _tcslen(_path);
+ path = new PathTraitsFS::value_type[l + 3];
+ _tcscpy(path, _path);
+ path[l] = _T('\\');
+ path[l + 1] = _T('*');
+ path[l + 2] = 0;
+ }
+
+ ~MakeWildcardPath() {
+ delete[] path;
+ }
+
+ operator PathTraitsFS::const_pointer() const {
+ return path;
+ }
+ };
+
+public:
+ /**
+ * Creates new directory reader for the specified #dir.
+ */
+ explicit DirectoryReader(Path dir)
+ :handle(FindFirstFile(MakeWildcardPath(dir.c_str()), &data)),
+ first(true) {}
+
+ DirectoryReader(const DirectoryReader &other) = delete;
+ DirectoryReader &operator=(const DirectoryReader &other) = delete;
+
+ /**
+ * Destroys this instance.
+ */
+ ~DirectoryReader() {
+ if (!HasFailed())
+ FindClose(handle);
+ }
+
+ /**
+ * Checks if directory failed to open.
+ */
+ bool HasFailed() const {
+ return handle == INVALID_HANDLE_VALUE;
+ }
+
+ /**
+ * Reads next directory entry.
+ */
+ bool ReadEntry() {
+ if (first) {
+ first = false;
+ return true;
+ }
+
+ return FindNextFile(handle, &data) != 0;
+ }
+
+ /**
+ * Extracts directory entry that was previously read by #ReadEntry.
+ */
+ Path GetEntry() const {
+ return Path::FromFS(data.cFileName);
+ }
+};
+
+#else
+
#include <dirent.h>
/**
@@ -85,3 +168,5 @@ public:
};
#endif
+
+#endif
diff --git a/src/fs/Domain.cxx b/src/fs/Domain.cxx
index 4f3129219..d278ba1bf 100644
--- a/src/fs/Domain.cxx
+++ b/src/fs/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/Domain.hxx b/src/fs/Domain.hxx
index 1fd17b37f..77ca64549 100644
--- a/src/fs/Domain.hxx
+++ b/src/fs/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/FileInfo.hxx b/src/fs/FileInfo.hxx
new file mode 100644
index 000000000..7b272568f
--- /dev/null
+++ b/src/fs/FileInfo.hxx
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FS_FILE_INFO_HXX
+#define MPD_FS_FILE_INFO_HXX
+
+#include "check.h"
+#include "Path.hxx"
+#include "util/Error.hxx"
+
+#include <stdint.h>
+
+#ifdef WIN32
+#include <fileapi.h>
+#else
+#include <sys/stat.h>
+#endif
+
+#ifdef WIN32
+
+static inline constexpr uint64_t
+ConstructUint64(DWORD lo, DWORD hi)
+{
+ return uint64_t(lo) | (uint64_t(hi) << 32);
+}
+
+static constexpr time_t
+FileTimeToTimeT(FILETIME ft)
+{
+ return (ConstructUint64(ft.dwLowDateTime, ft.dwHighDateTime)
+ - 116444736000000000) / 10000000;
+}
+
+#endif
+
+class FileInfo {
+ friend bool GetFileInfo(Path path, FileInfo &info,
+ bool follow_symlinks);
+ friend bool GetFileInfo(Path path, FileInfo &info,
+ Error &error);
+ friend class FileReader;
+
+#ifdef WIN32
+ WIN32_FILE_ATTRIBUTE_DATA data;
+#else
+ struct stat st;
+#endif
+
+public:
+ bool IsRegular() const {
+#ifdef WIN32
+ return (data.dwFileAttributes &
+ (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) == 0;
+#else
+ return S_ISREG(st.st_mode);
+#endif
+ }
+
+ bool IsDirectory() const {
+#ifdef WIN32
+ return data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+#else
+ return S_ISDIR(st.st_mode);
+#endif
+ }
+
+ uint64_t GetSize() const {
+#ifdef WIN32
+ return ConstructUint64(data.nFileSizeLow, data.nFileSizeHigh);
+#else
+ return st.st_size;
+#endif
+ }
+
+ time_t GetModificationTime() const {
+#ifdef WIN32
+ return FileTimeToTimeT(data.ftLastWriteTime);
+#else
+ return st.st_mtime;
+#endif
+ }
+
+#ifndef WIN32
+ uid_t GetUid() const {
+ return st.st_uid;
+ }
+
+ mode_t GetMode() const {
+ return st.st_mode;
+ }
+
+ dev_t GetDevice() const {
+ return st.st_dev;
+ }
+
+ ino_t GetInode() const {
+ return st.st_ino;
+ }
+#endif
+};
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, bool follow_symlinks=true)
+{
+#ifdef WIN32
+ (void)follow_symlinks;
+ return GetFileAttributesEx(path.c_str(), GetFileExInfoStandard,
+ &info.data);
+#else
+ int ret = follow_symlinks
+ ? stat(path.c_str(), &info.st)
+ : lstat(path.c_str(), &info.st);
+ return ret == 0;
+#endif
+}
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, bool follow_symlinks, Error &error)
+{
+ bool success = GetFileInfo(path, info, follow_symlinks);
+ if (!success) {
+ const auto path_utf8 = path.ToUTF8();
+#ifdef WIN32
+ error.FormatLastError("Failed to access %s",
+ path_utf8.c_str());
+#else
+ error.FormatErrno("Failed to access %s", path_utf8.c_str());
+#endif
+ }
+
+ return success;
+}
+
+inline bool
+GetFileInfo(Path path, FileInfo &info, Error &error)
+{
+ return GetFileInfo(path, info, true, error);
+}
+
+#endif
diff --git a/src/fs/FileSystem.cxx b/src/fs/FileSystem.cxx
index 4e7c87415..554915b61 100644
--- a/src/fs/FileSystem.cxx
+++ b/src/fs/FileSystem.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/FileSystem.hxx b/src/fs/FileSystem.hxx
index 4dbb064cb..309c0cdf6 100644
--- a/src/fs/FileSystem.hxx
+++ b/src/fs/FileSystem.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,42 +26,27 @@
#include "Path.hxx"
+#ifdef WIN32
+#include <fileapi.h>
+#endif
+
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
+
class AllocatedPath;
namespace FOpenMode {
/**
- * Open mode for reading text files.
- */
- constexpr PathTraitsFS::const_pointer ReadText = "r";
-
- /**
- * Open mode for reading binary files.
- */
- constexpr PathTraitsFS::const_pointer ReadBinary = "rb";
-
- /**
* Open mode for writing text files.
*/
- constexpr PathTraitsFS::const_pointer WriteText = "w";
-
- /**
- * Open mode for writing binary files.
- */
- constexpr PathTraitsFS::const_pointer WriteBinary = "wb";
+ constexpr PathTraitsFS::const_pointer WriteText = PATH_LITERAL("w");
/**
* Open mode for appending text files.
*/
- constexpr PathTraitsFS::const_pointer AppendText = "a";
-
- /**
- * Open mode for appending binary files.
- */
- constexpr PathTraitsFS::const_pointer AppendBinary = "ab";
+ constexpr PathTraitsFS::const_pointer AppendText = PATH_LITERAL("a");
}
/**
@@ -70,7 +55,11 @@ namespace FOpenMode {
static inline FILE *
FOpen(Path file, PathTraitsFS::const_pointer mode)
{
+#ifdef WIN32
+ return _tfopen(file.c_str(), mode);
+#else
return fopen(file.c_str(), mode);
+#endif
}
/**
@@ -79,7 +68,11 @@ FOpen(Path file, PathTraitsFS::const_pointer mode)
static inline int
OpenFile(Path file, int flags, int mode)
{
+#ifdef WIN32
+ return _topen(file.c_str(), flags, mode);
+#else
return open_cloexec(file.c_str(), flags, mode);
+#endif
}
/**
@@ -88,33 +81,40 @@ OpenFile(Path file, int flags, int mode)
static inline bool
RenameFile(Path oldpath, Path newpath)
{
+#ifdef WIN32
+ return _trename(oldpath.c_str(), newpath.c_str()) == 0;
+#else
return rename(oldpath.c_str(), newpath.c_str()) == 0;
+#endif
}
+#ifndef WIN32
+
/**
* Wrapper for stat() that uses #Path names.
*/
static inline bool
StatFile(Path file, struct stat &buf, bool follow_symlinks = true)
{
-#ifdef WIN32
- (void)follow_symlinks;
- return stat(file.c_str(), &buf) == 0;
-#else
int ret = follow_symlinks
? stat(file.c_str(), &buf)
: lstat(file.c_str(), &buf);
return ret == 0;
-#endif
}
+#endif
+
/**
* Wrapper for unlink() that uses #Path names.
*/
static inline bool
RemoveFile(Path file)
{
+#ifdef WIN32
+ return _tunlink(file.c_str()) == 0;
+#else
return unlink(file.c_str()) == 0;
+#endif
}
/**
@@ -143,27 +143,21 @@ CheckAccess(Path path, int mode)
#endif
/**
- * Checks is specified path exists and accessible.
- */
-static inline bool
-CheckAccess(Path path)
-{
-#ifdef WIN32
- struct stat buf;
- return StatFile(path, buf);
-#else
- return CheckAccess(path, F_OK);
-#endif
-}
-
-/**
* Checks if #Path exists and is a regular file.
*/
static inline bool
FileExists(Path path, bool follow_symlinks = true)
{
+#ifdef WIN32
+ (void)follow_symlinks;
+
+ const auto a = GetFileAttributes(path.c_str());
+ return a != INVALID_FILE_ATTRIBUTES &&
+ (a & (FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_DEVICE)) == 0;
+#else
struct stat buf;
return StatFile(path, buf, follow_symlinks) && S_ISREG(buf.st_mode);
+#endif
}
/**
@@ -172,18 +166,28 @@ FileExists(Path path, bool follow_symlinks = true)
static inline bool
DirectoryExists(Path path, bool follow_symlinks = true)
{
+#ifdef WIN32
+ (void)follow_symlinks;
+
+ const auto a = GetFileAttributes(path.c_str());
+ return a != INVALID_FILE_ATTRIBUTES && (a & FILE_ATTRIBUTE_DIRECTORY);
+#else
struct stat buf;
return StatFile(path, buf, follow_symlinks) && S_ISDIR(buf.st_mode);
+#endif
}
/**
* Checks if #Path exists.
*/
static inline bool
-PathExists(Path path, bool follow_symlinks = true)
+PathExists(Path path)
{
- struct stat buf;
- return StatFile(path, buf, follow_symlinks);
+#ifdef WIN32
+ return GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES;
+#else
+ return CheckAccess(path, F_OK);
+#endif
}
#endif
diff --git a/src/fs/Glob.hxx b/src/fs/Glob.hxx
new file mode 100644
index 000000000..822cc3fb4
--- /dev/null
+++ b/src/fs/Glob.hxx
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FS_GLOB_XX
+#define MPD_FS_GLOB_XX
+
+#include "check.h"
+
+#ifdef HAVE_FNMATCH
+#define HAVE_CLASS_GLOB
+#include <string>
+#include <fnmatch.h>
+#elif defined(WIN32)
+#define HAVE_CLASS_GLOB
+#include <string>
+#include <shlwapi.h>
+#endif
+
+#ifdef HAVE_CLASS_GLOB
+#include "Compiler.h"
+
+/**
+ * A pattern that matches file names. It may contain shell wildcards
+ * (asterisk and question mark).
+ */
+class Glob {
+#if defined(HAVE_FNMATCH) || defined(WIN32)
+ std::string pattern;
+#endif
+
+public:
+#if defined(HAVE_FNMATCH) || defined(WIN32)
+ explicit Glob(const char *_pattern)
+ :pattern(_pattern) {}
+
+ Glob(Glob &&other)
+ :pattern(std::move(other.pattern)) {}
+#endif
+
+ gcc_pure
+ bool Check(const char *name_fs) const {
+#ifdef HAVE_FNMATCH
+ return fnmatch(pattern.c_str(), name_fs, 0) == 0;
+#elif defined(WIN32)
+ return PathMatchSpecA(name_fs, pattern.c_str());
+#endif
+ }
+};
+
+#endif
+
+#endif
diff --git a/src/fs/Limits.hxx b/src/fs/Limits.hxx
index 432897a69..b574a9c9a 100644
--- a/src/fs/Limits.hxx
+++ b/src/fs/Limits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/NarrowPath.hxx b/src/fs/NarrowPath.hxx
new file mode 100644
index 000000000..433a9c1cd
--- /dev/null
+++ b/src/fs/NarrowPath.hxx
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FS_NARROW_PATH_HXX
+#define MPD_FS_NARROW_PATH_HXX
+
+#include "check.h"
+#include "Path.hxx"
+#include "util/Macros.hxx"
+
+#ifdef _UNICODE
+#include "lib/icu/Win32.hxx"
+#include "util/AllocatedString.hxx"
+#include <windows.h>
+#else
+#include "util/StringPointer.hxx"
+#endif
+
+/**
+ * A path name that uses the regular (narrow) "char". This is used to
+ * pass a #Path (which may be represented by wchar_t) to a library
+ * that accepts only "const char *".
+ */
+class NarrowPath {
+#ifdef _UNICODE
+ typedef AllocatedString<> Value;
+#else
+ typedef StringPointer<> Value;
+#endif
+ typedef typename Value::const_pointer const_pointer;
+
+ Value value;
+
+public:
+#ifdef _UNICODE
+ explicit NarrowPath(Path _path)
+ :value(WideCharToMultiByte(CP_ACP, _path.c_str())) {
+ if (value.IsNull())
+ /* fall back to empty string */
+ value = Value::Empty();
+ }
+#else
+ explicit NarrowPath(Path _path):value(_path.c_str()) {}
+#endif
+
+ operator const_pointer() const {
+ return c_str();
+ }
+
+ const_pointer c_str() const {
+ return value.c_str();
+ }
+};
+
+#endif
diff --git a/src/fs/Path.cxx b/src/fs/Path.cxx
index 8288a4fec..99a4ffb61 100644
--- a/src/fs/Path.cxx
+++ b/src/fs/Path.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,22 @@
#include "config.h"
#include "Path.hxx"
#include "Charset.hxx"
+#include "util/UriUtil.hxx"
+#include "util/StringUtil.hxx"
std::string
Path::ToUTF8() const
{
return ::PathToUTF8(c_str());
}
+
+Path::const_pointer
+Path::GetSuffix() const
+{
+ const auto base = GetBase().c_str();
+ const auto *dot = StringFindLast(base, '.');
+ if (dot == nullptr || dot == base)
+ return nullptr;
+
+ return dot + 1;
+}
diff --git a/src/fs/Path.hxx b/src/fs/Path.hxx
index 9e0fa5aeb..43818b2da 100644
--- a/src/fs/Path.hxx
+++ b/src/fs/Path.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,8 @@
#include <string>
#include <assert.h>
-#include <string.h>
+
+class AllocatedPath;
/**
* A path name in the native file system character set.
@@ -35,14 +36,10 @@
* This class manages a pointer to an existing path string. While an
* instance lives, the string must not be invalidated.
*/
-class Path {
- typedef PathTraitsFS::value_type value_type;
- typedef PathTraitsFS::pointer pointer;
- typedef PathTraitsFS::const_pointer const_pointer;
-
- const char *value;
+class Path : public PathTraitsFS::Pointer {
+ typedef PathTraitsFS::Pointer Base;
- constexpr Path(const_pointer _value):value(_value) {}
+ constexpr Path(const_pointer _value):Base(_value) {}
public:
/**
@@ -78,7 +75,7 @@ public:
* must not be used.
*/
bool IsNull() const {
- return value == nullptr;
+ return Base::IsNull();
}
/**
@@ -87,7 +84,7 @@ public:
* @see IsNull()
*/
void SetNull() {
- value = nullptr;
+ *this = nullptr;
}
/**
@@ -96,9 +93,9 @@ public:
*/
gcc_pure
size_t length() const {
- assert(value != nullptr);
+ assert(!IsNull());
- return strlen(value);
+ return PathTraitsFS::GetLength(c_str());
}
/**
@@ -108,7 +105,7 @@ public:
*/
gcc_pure
const_pointer c_str() const {
- return value;
+ return Base::c_str();
}
/**
@@ -117,7 +114,17 @@ public:
*/
gcc_pure
const_pointer data() const {
- return value;
+ return c_str();
+ }
+
+ /**
+ * Does the path contain a newline character? (Which is
+ * usually rejected by MPD because its protocol cannot
+ * transfer newline characters).
+ */
+ gcc_pure
+ bool HasNewline() const {
+ return PathTraitsFS::Find(c_str(), '\n') != nullptr;
}
/**
@@ -129,20 +136,39 @@ public:
std::string ToUTF8() const;
/**
+ * Determine the "base" file name.
+ * The return value points inside this object.
+ */
+ gcc_pure
+ Path GetBase() const {
+ return FromFS(PathTraitsFS::GetBase(c_str()));
+ }
+
+ /**
+ * Gets directory name of this path.
+ * Returns a "nulled" instance on error.
+ */
+ gcc_pure
+ AllocatedPath GetDirectoryName() const;
+
+ /**
* Determine the relative part of the given path to this
* object, not including the directory separator. Returns an
* empty string if the given path equals this object or
* nullptr on mismatch.
*/
gcc_pure
- const char *RelativeFS(const char *other_fs) const {
- return PathTraitsFS::Relative(value, other_fs);
+ const_pointer Relative(Path other_fs) const {
+ return PathTraitsFS::Relative(c_str(), other_fs.c_str());
}
gcc_pure
- bool IsAbsolute() {
+ bool IsAbsolute() const {
return PathTraitsFS::IsAbsolute(c_str());
}
+
+ gcc_pure
+ const_pointer GetSuffix() const;
};
#endif
diff --git a/src/fs/Path2.cxx b/src/fs/Path2.cxx
new file mode 100644
index 000000000..b85909f79
--- /dev/null
+++ b/src/fs/Path2.cxx
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Path.hxx"
+#include "AllocatedPath.hxx"
+
+AllocatedPath
+Path::GetDirectoryName() const
+{
+ return AllocatedPath::FromFS(PathTraitsFS::GetParent(c_str()));
+}
diff --git a/src/fs/StandardDirectory.cxx b/src/fs/StandardDirectory.cxx
index 7a836f906..38ea804a0 100644
--- a/src/fs/StandardDirectory.cxx
+++ b/src/fs/StandardDirectory.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -112,7 +112,7 @@ static inline AllocatedPath SafePathFromFS(PathTraitsFS::const_pointer dir)
#ifdef WIN32
static AllocatedPath GetStandardDir(int folder_id)
{
- std::array<char, MAX_PATH> dir;
+ std::array<PathTraitsFS::value_type, MAX_PATH> dir;
auto ret = SHGetFolderPath(nullptr, folder_id | CSIDL_FLAG_DONT_VERIFY,
nullptr, SHGFP_TYPE_CURRENT, dir.data());
if (FAILED(ret))
@@ -287,7 +287,7 @@ AllocatedPath GetSystemConfigDir()
AllocatedPath GetAppBaseDir()
{
- std::array<char, MAX_PATH> app;
+ std::array<PathTraitsFS::value_type, MAX_PATH> app;
auto ret = GetModuleFileName(nullptr, app.data(), app.size());
// Check for error
diff --git a/src/fs/StandardDirectory.hxx b/src/fs/StandardDirectory.hxx
index e3fba375a..d453d109d 100644
--- a/src/fs/StandardDirectory.hxx
+++ b/src/fs/StandardDirectory.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/Traits.cxx b/src/fs/Traits.cxx
index 166b31f4e..7eba0916a 100644
--- a/src/fs/Traits.cxx
+++ b/src/fs/Traits.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "Traits.hxx"
+#include "util/StringUtil.hxx"
#include <string.h>
@@ -74,7 +75,7 @@ GetParentPathImpl(typename Traits::const_pointer p)
typename Traits::const_pointer sep = Traits::FindLastSeparator(p);
if (sep == nullptr)
- return typename Traits::string(".");
+ return typename Traits::string(Traits::CURRENT_DIRECTORY);
if (sep == p)
return typename Traits::string(p, p + 1);
#ifdef WIN32
@@ -92,13 +93,12 @@ RelativePathImpl(typename Traits::const_pointer base,
assert(base != nullptr);
assert(other != nullptr);
- const auto base_length = Traits::GetLength(base);
- if (memcmp(base, other, base_length * sizeof(*base)) != 0)
+ other = StringAfterPrefix(other, base);
+ if (other == nullptr)
/* mismatch */
return nullptr;
- other += base_length;
- if (other != 0) {
+ if (*other != 0) {
if (!Traits::IsSeparator(*other))
/* mismatch */
return nullptr;
diff --git a/src/fs/Traits.hxx b/src/fs/Traits.hxx
index 1af8f8672..08d798f05 100644
--- a/src/fs/Traits.hxx
+++ b/src/fs/Traits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,24 +22,38 @@
#include "check.h"
#include "Compiler.h"
+#include "util/StringPointer.hxx"
+#include "util/StringAPI.hxx"
#ifdef WIN32
#include "util/CharUtil.hxx"
+#include <tchar.h>
#endif
#include <string>
-#include <string.h>
#include <assert.h>
+#ifdef WIN32
+#define PATH_LITERAL(s) _T(s)
+#else
+#define PATH_LITERAL(s) (s)
+#endif
+
/**
* This class describes the nature of a native filesystem path.
*/
struct PathTraitsFS {
+#ifdef WIN32
+ typedef std::wstring string;
+#else
typedef std::string string;
- typedef char value_type;
- typedef value_type *pointer;
- typedef const value_type *const_pointer;
+#endif
+ typedef string::traits_type char_traits;
+ typedef char_traits::char_type value_type;
+ typedef StringPointer<value_type> Pointer;
+ typedef Pointer::pointer pointer;
+ typedef Pointer::const_pointer const_pointer;
#ifdef WIN32
static constexpr value_type SEPARATOR = '\\';
@@ -47,6 +61,8 @@ struct PathTraitsFS {
static constexpr value_type SEPARATOR = '/';
#endif
+ static constexpr const_pointer CURRENT_DIRECTORY = PATH_LITERAL(".");
+
static constexpr bool IsSeparator(value_type ch) {
return
#ifdef WIN32
@@ -68,7 +84,7 @@ struct PathTraitsFS {
--pos;
return IsSeparator(*pos) ? pos : nullptr;
#else
- return strrchr(p, SEPARATOR);
+ return StringFindLast(p, SEPARATOR);
#endif
}
@@ -95,7 +111,12 @@ struct PathTraitsFS {
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) {
- return strlen(p);
+ return StringLength(p);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static const_pointer Find(const_pointer p, value_type ch) {
+ return StringFind(p, ch);
}
/**
@@ -143,12 +164,15 @@ struct PathTraitsFS {
*/
struct PathTraitsUTF8 {
typedef std::string string;
- typedef char value_type;
+ typedef string::traits_type char_traits;
+ typedef char_traits::char_type value_type;
typedef value_type *pointer;
typedef const value_type *const_pointer;
static constexpr value_type SEPARATOR = '/';
+ static constexpr const_pointer CURRENT_DIRECTORY = ".";
+
static constexpr bool IsSeparator(value_type ch) {
return ch == SEPARATOR;
}
@@ -186,7 +210,12 @@ struct PathTraitsUTF8 {
gcc_pure gcc_nonnull_all
static size_t GetLength(const_pointer p) {
- return strlen(p);
+ return StringLength(p);
+ }
+
+ gcc_pure gcc_nonnull_all
+ static const_pointer Find(const_pointer p, value_type ch) {
+ return StringFind(p, ch);
}
/**
diff --git a/src/fs/io/AutoGunzipReader.cxx b/src/fs/io/AutoGunzipReader.cxx
index 2552f7b99..b6d30dfd7 100644
--- a/src/fs/io/AutoGunzipReader.cxx
+++ b/src/fs/io/AutoGunzipReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/AutoGunzipReader.hxx b/src/fs/io/AutoGunzipReader.hxx
index 9f031e0f5..29a794aed 100644
--- a/src/fs/io/AutoGunzipReader.hxx
+++ b/src/fs/io/AutoGunzipReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/BufferedOutputStream.cxx b/src/fs/io/BufferedOutputStream.cxx
index 088a3e279..2268eb50c 100644
--- a/src/fs/io/BufferedOutputStream.cxx
+++ b/src/fs/io/BufferedOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,17 +41,22 @@ bool
BufferedOutputStream::Write(const void *data, size_t size)
{
if (gcc_unlikely(last_error.IsDefined()))
+ /* the stream has already failed */
return false;
+ /* try to append to the current buffer */
if (AppendToBuffer(data, size))
return true;
+ /* not enough room in the buffer - flush it */
if (!Flush())
return false;
+ /* see if there's now enough room */
if (AppendToBuffer(data, size))
return true;
+ /* too large for the buffer: direct write */
return os.Write(data, size, last_error);
}
diff --git a/src/fs/io/BufferedOutputStream.hxx b/src/fs/io/BufferedOutputStream.hxx
index f2de758a2..63a3f4aee 100644
--- a/src/fs/io/BufferedOutputStream.hxx
+++ b/src/fs/io/BufferedOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,6 +30,14 @@
class OutputStream;
class Error;
+/**
+ * An #OutputStream wrapper that buffers its output to reduce the
+ * number of OutputStream::Write() calls.
+ *
+ * It simplifies error handling by managing an #Error attribute.
+ * Invoke any number of writes, and check for errors in the end using
+ * Check().
+ */
class BufferedOutputStream {
OutputStream &os;
@@ -47,11 +55,18 @@ public:
gcc_printf(2,3)
bool Format(const char *fmt, ...);
+ /**
+ * Returns false if an error has occurred.
+ */
gcc_pure
bool Check() const {
return !last_error.IsDefined();
}
+ /**
+ * Returns false if an error has occurred. In that case, a
+ * copy of the #Error is returned.
+ */
bool Check(Error &error) const {
if (last_error.IsDefined()) {
error.Set(last_error);
@@ -60,6 +75,9 @@ public:
return true;
}
+ /**
+ * Write buffer contents to the #OutputStream.
+ */
bool Flush();
bool Flush(Error &error);
diff --git a/src/fs/io/BufferedReader.cxx b/src/fs/io/BufferedReader.cxx
index ba2f17dcf..9a296d815 100644
--- a/src/fs/io/BufferedReader.cxx
+++ b/src/fs/io/BufferedReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -59,8 +59,10 @@ BufferedReader::ReadLine()
{
do {
char *line = ReadBufferedLine(buffer);
- if (line != nullptr)
+ if (line != nullptr) {
+ ++line_number;
return line;
+ }
} while (Fill(true));
if (last_error.IsDefined() || !eof || buffer.IsEmpty())
@@ -78,5 +80,6 @@ BufferedReader::ReadLine()
char *line = buffer.Read().data;
buffer.Clear();
+ ++line_number;
return line;
}
diff --git a/src/fs/io/BufferedReader.hxx b/src/fs/io/BufferedReader.hxx
index 61cc8df83..a0c42d23c 100644
--- a/src/fs/io/BufferedReader.hxx
+++ b/src/fs/io/BufferedReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,9 +41,12 @@ class BufferedReader {
bool eof;
+ unsigned line_number;
+
public:
BufferedReader(Reader &_reader)
- :reader(_reader), buffer(4096), eof(false) {}
+ :reader(_reader), buffer(4096), eof(false),
+ line_number(0) {}
gcc_pure
bool Check() const {
@@ -70,6 +73,10 @@ public:
}
char *ReadLine();
+
+ unsigned GetLineNumber() const {
+ return line_number;
+ }
};
#endif
diff --git a/src/fs/io/FileOutputStream.cxx b/src/fs/io/FileOutputStream.cxx
index 0eff8b5f0..a4ef8f6b4 100644
--- a/src/fs/io/FileOutputStream.cxx
+++ b/src/fs/io/FileOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,36 +20,61 @@
#include "config.h"
#include "FileOutputStream.hxx"
#include "fs/FileSystem.hxx"
-#include "system/fd_util.h"
#include "util/Error.hxx"
+FileOutputStream *
+FileOutputStream::Create(Path path, Error &error)
+{
+ FileOutputStream *f = new FileOutputStream(path, error);
+ if (!f->IsDefined()) {
+ delete f;
+ f = nullptr;
+ }
+
+ return f;
+}
+
#ifdef WIN32
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path),
- handle(CreateFile(path.c_str(), GENERIC_WRITE, 0, nullptr,
- TRUNCATE_EXISTING,
- FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
- nullptr))
+ :BaseFileOutputStream(_path)
{
- if (handle == INVALID_HANDLE_VALUE)
- error.FormatLastError("Failed to create %s", path.c_str());
+ SetHandle(CreateFile(_path.c_str(), GENERIC_WRITE, 0, nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+ nullptr));
+ if (!IsDefined())
+ error.FormatLastError("Failed to create %s",
+ GetPath().ToUTF8().c_str());
+}
+
+uint64_t
+BaseFileOutputStream::Tell() const
+{
+ LONG high = 0;
+ DWORD low = SetFilePointer(handle, 0, &high, FILE_CURRENT);
+ if (low == 0xffffffff)
+ return 0;
+
+ return uint64_t(high) << 32 | uint64_t(low);
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
DWORD nbytes;
if (!WriteFile(handle, data, size, &nbytes, nullptr)) {
- error.FormatLastError("Failed to write to %s", path.c_str());
+ error.FormatLastError("Failed to write to %s",
+ path.ToUTF8().c_str());
return false;
}
if (size_t(nbytes) != size) {
error.FormatLastError(ERROR_DISK_FULL,
- "Failed to write to %s", path.c_str());
+ "Failed to write to %s",
+ path.ToUTF8().c_str());
return false;
}
@@ -61,8 +86,7 @@ FileOutputStream::Commit(gcc_unused Error &error)
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
+ Close();
return true;
}
@@ -71,9 +95,8 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- CloseHandle(handle);
- handle = INVALID_HANDLE_VALUE;
- RemoveFile(path);
+ Close();
+ RemoveFile(GetPath());
}
#else
@@ -82,28 +105,66 @@ FileOutputStream::Cancel()
#include <unistd.h>
#include <errno.h>
+#ifdef HAVE_LINKAT
+#ifndef O_TMPFILE
+/* supported since Linux 3.11 */
+#define __O_TMPFILE 020000000
+#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
+#include <stdio.h>
+#endif
+
+/**
+ * Open a file using Linux's O_TMPFILE for writing the given file.
+ */
+static bool
+OpenTempFile(FileDescriptor &fd, Path path)
+{
+ const auto directory = path.GetDirectoryName();
+ if (directory.IsNull())
+ return false;
+
+ return fd.Open(directory.c_str(), O_TMPFILE|O_WRONLY, 0666);
+}
+
+#endif /* HAVE_LINKAT */
+
FileOutputStream::FileOutputStream(Path _path, Error &error)
- :path(_path),
- fd(open_cloexec(path.c_str(),
- O_WRONLY|O_CREAT|O_TRUNC,
- 0666))
+ :BaseFileOutputStream(_path)
+{
+#ifdef HAVE_LINKAT
+ /* try Linux's O_TMPFILE first */
+ is_tmpfile = OpenTempFile(SetFD(), GetPath());
+ if (!is_tmpfile) {
+#endif
+ /* fall back to plain POSIX */
+ if (!SetFD().Open(GetPath().c_str(),
+ O_WRONLY|O_CREAT|O_TRUNC,
+ 0666))
+ error.FormatErrno("Failed to create %s",
+ GetPath().c_str());
+#ifdef HAVE_LINKAT
+ }
+#endif
+}
+
+uint64_t
+BaseFileOutputStream::Tell() const
{
- if (fd < 0)
- error.FormatErrno("Failed to create %s", path.c_str());
+ return fd.Tell();
}
bool
-FileOutputStream::Write(const void *data, size_t size, Error &error)
+BaseFileOutputStream::Write(const void *data, size_t size, Error &error)
{
assert(IsDefined());
- ssize_t nbytes = write(fd, data, size);
+ ssize_t nbytes = fd.Write(data, size);
if (nbytes < 0) {
- error.FormatErrno("Failed to write to %s", path.c_str());
+ error.FormatErrno("Failed to write to %s", GetPath().c_str());
return false;
} else if ((size_t)nbytes < size) {
error.FormatErrno(ENOSPC,
- "Failed to write to %s", path.c_str());
+ "Failed to write to %s", GetPath().c_str());
return false;
}
@@ -115,10 +176,27 @@ FileOutputStream::Commit(Error &error)
{
assert(IsDefined());
- bool success = close(fd) == 0;
- fd = -1;
+#if HAVE_LINKAT
+ if (is_tmpfile) {
+ RemoveFile(GetPath());
+
+ /* hard-link the temporary file to the final path */
+ char fd_path[64];
+ snprintf(fd_path, sizeof(fd_path), "/proc/self/fd/%d",
+ GetFD().Get());
+ if (linkat(AT_FDCWD, fd_path, AT_FDCWD, GetPath().c_str(),
+ AT_SYMLINK_FOLLOW) < 0) {
+ error.FormatErrno("Failed to commit %s",
+ GetPath().c_str());
+ Close();
+ return false;
+ }
+ }
+#endif
+
+ bool success = Close();
if (!success)
- error.FormatErrno("Failed to commit %s", path.c_str());
+ error.FormatErrno("Failed to commit %s", GetPath().c_str());
return success;
}
@@ -128,10 +206,53 @@ FileOutputStream::Cancel()
{
assert(IsDefined());
- close(fd);
- fd = -1;
+ Close();
+
+#ifdef HAVE_LINKAT
+ if (!is_tmpfile)
+#endif
+ RemoveFile(GetPath());
+}
+
+#endif
+
+AppendFileOutputStream::AppendFileOutputStream(Path _path, Error &error)
+ :BaseFileOutputStream(_path)
+{
+#ifdef WIN32
+ SetHandle(CreateFile(GetPath().c_str(), GENERIC_WRITE, 0, nullptr,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_WRITE_THROUGH,
+ nullptr));
+ if (!IsDefined())
+ error.FormatLastError("Failed to append to %s",
+ GetPath().ToUTF8().c_str());
- RemoveFile(path);
+ if (!SeekEOF()) {
+ error.FormatLastError("Failed seek end-of-file of %s",
+ GetPath().ToUTF8().c_str());
+ Close();
+ }
+#else
+ if (!SetFD().Open(GetPath().c_str(),
+ O_WRONLY|O_APPEND))
+ error.FormatErrno("Failed to append to %s",
+ GetPath().c_str());
+#endif
}
+bool
+AppendFileOutputStream::Commit(gcc_unused Error &error)
+{
+ assert(IsDefined());
+
+#ifdef WIN32
+ return Close();
+#else
+ bool success = Close();
+ if (!success)
+ error.FormatErrno("Failed to commit %s", GetPath().c_str());
+
+ return success;
#endif
+}
diff --git a/src/fs/io/FileOutputStream.hxx b/src/fs/io/FileOutputStream.hxx
index 5b6309957..b182fd03f 100644
--- a/src/fs/io/FileOutputStream.hxx
+++ b/src/fs/io/FileOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,10 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
+#ifndef WIN32
+#include "system/FileDescriptor.hxx"
+#endif
+
#include <assert.h>
#ifdef WIN32
@@ -33,37 +37,124 @@
class Path;
-class FileOutputStream final : public OutputStream {
- AllocatedPath path;
+class BaseFileOutputStream : public OutputStream {
+ const AllocatedPath path;
#ifdef WIN32
HANDLE handle;
#else
- int fd;
+ FileDescriptor fd;
#endif
-public:
- FileOutputStream(Path _path, Error &error);
+protected:
+#ifdef WIN32
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ handle(INVALID_HANDLE_VALUE) {}
+#else
+ template<typename P>
+ BaseFileOutputStream(P &&_path)
+ :path(std::forward<P>(_path)),
+ fd(FileDescriptor::Undefined()) {}
+#endif
- ~FileOutputStream() {
- if (IsDefined())
- Cancel();
+ ~BaseFileOutputStream() {
+ assert(!IsDefined());
}
+#ifdef WIN32
+ void SetHandle(HANDLE _handle) {
+ assert(!IsDefined());
+
+ handle = _handle;
+
+ assert(IsDefined());
+ }
+#else
+ FileDescriptor &SetFD() {
+ assert(!IsDefined());
+
+ return fd;
+ }
+
+ const FileDescriptor &GetFD() const {
+ return fd;
+ }
+#endif
+
+ bool Close() {
+ assert(IsDefined());
+
+#ifdef WIN32
+ CloseHandle(handle);
+ handle = INVALID_HANDLE_VALUE;
+ return true;
+#else
+ return fd.Close();
+#endif
+ }
+
+#ifdef WIN32
+ bool SeekEOF() {
+ return SetFilePointer(handle, 0, nullptr,
+ FILE_END) != 0xffffffff;
+ }
+#endif
+public:
bool IsDefined() const {
#ifdef WIN32
return handle != INVALID_HANDLE_VALUE;
#else
- return fd >= 0;
+ return fd.IsDefined();
#endif
}
- bool Commit(Error &error);
- void Cancel();
+ Path GetPath() const {
+ return path;
+ }
+
+ gcc_pure
+ uint64_t Tell() const;
/* virtual methods from class OutputStream */
bool Write(const void *data, size_t size, Error &error) override;
};
+class FileOutputStream final : public BaseFileOutputStream {
+#ifdef HAVE_LINKAT
+ /**
+ * Was O_TMPFILE used? If yes, then linkat() must be used to
+ * create a link to this file.
+ */
+ bool is_tmpfile;
+#endif
+
+public:
+ FileOutputStream(Path _path, Error &error);
+
+ ~FileOutputStream() {
+ if (IsDefined())
+ Cancel();
+ }
+
+ static FileOutputStream *Create(Path path, Error &error);
+
+ bool Commit(Error &error);
+ void Cancel();
+};
+
+class AppendFileOutputStream final : public BaseFileOutputStream {
+public:
+ AppendFileOutputStream(Path _path, Error &error);
+
+ ~AppendFileOutputStream() {
+ if (IsDefined())
+ Close();
+ }
+
+ bool Commit(Error &error);
+};
+
#endif
diff --git a/src/fs/io/FileReader.cxx b/src/fs/io/FileReader.cxx
index d63cd8ab0..e54f6f3a8 100644
--- a/src/fs/io/FileReader.cxx
+++ b/src/fs/io/FileReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "FileReader.hxx"
-#include "system/fd_util.h"
+#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
#ifdef WIN32
@@ -30,8 +30,18 @@ FileReader::FileReader(Path _path, Error &error)
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
nullptr))
{
- if (handle == INVALID_HANDLE_VALUE)
- error.FormatLastError("Failed to open %s", path.c_str());
+ if (handle == INVALID_HANDLE_VALUE) {
+ const auto path_utf8 = path.ToUTF8();
+ error.FormatLastError("Failed to open %s", path_utf8.c_str());
+ }
+}
+
+bool
+FileReader::GetFileInfo(FileInfo &info, Error &error) const
+{
+ assert(IsDefined());
+
+ return ::GetFileInfo(path, info, error);
}
size_t
@@ -41,13 +51,28 @@ FileReader::Read(void *data, size_t size, Error &error)
DWORD nbytes;
if (!ReadFile(handle, data, size, &nbytes, nullptr)) {
- error.FormatLastError("Failed to read from %s", path.c_str());
+ const auto path_utf8 = path.ToUTF8();
+ error.FormatLastError("Failed to read from %s",
+ path_utf8.c_str());
nbytes = 0;
}
return nbytes;
}
+bool
+FileReader::Seek(off_t offset, Error &error)
+{
+ assert(IsDefined());
+
+ auto result = SetFilePointer(handle, offset, nullptr, FILE_BEGIN);
+ const bool success = result != INVALID_SET_FILE_POINTER;
+ if (!success)
+ error.SetLastError("Failed to seek");
+
+ return success;
+}
+
void
FileReader::Close()
{
@@ -58,26 +83,33 @@ FileReader::Close()
#else
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-
FileReader::FileReader(Path _path, Error &error)
- :path(_path),
- fd(open_cloexec(path.c_str(),
- O_RDONLY,
- 0))
+ :path(_path)
{
- if (fd < 0)
+ fd.OpenReadOnly(path.c_str());
+ if (!fd.IsDefined())
error.FormatErrno("Failed to open %s", path.c_str());
}
+bool
+FileReader::GetFileInfo(FileInfo &info, Error &error) const
+{
+ assert(IsDefined());
+
+ const bool success = fstat(fd.Get(), &info.st) == 0;
+ if (!success)
+ error.FormatErrno("Failed to access %s",
+ path.ToUTF8().c_str());
+
+ return success;
+}
+
size_t
FileReader::Read(void *data, size_t size, Error &error)
{
assert(IsDefined());
- ssize_t nbytes = read(fd, data, size);
+ ssize_t nbytes = fd.Read(data, size);
if (nbytes < 0) {
error.FormatErrno("Failed to read from %s", path.c_str());
nbytes = 0;
@@ -86,13 +118,25 @@ FileReader::Read(void *data, size_t size, Error &error)
return nbytes;
}
+bool
+FileReader::Seek(off_t offset, Error &error)
+{
+ assert(IsDefined());
+
+ auto result = fd.Seek(offset);
+ const bool success = result >= 0;
+ if (!success)
+ error.SetErrno("Failed to seek");
+
+ return success;
+}
+
void
FileReader::Close()
{
assert(IsDefined());
- close(fd);
- fd = -1;
+ fd.Close();
}
#endif
diff --git a/src/fs/io/FileReader.hxx b/src/fs/io/FileReader.hxx
index 9f459aee2..642fc5ed1 100644
--- a/src/fs/io/FileReader.hxx
+++ b/src/fs/io/FileReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,10 @@
#include "fs/AllocatedPath.hxx"
#include "Compiler.h"
+#ifndef WIN32
+#include "system/FileDescriptor.hxx"
+#endif
+
#include <assert.h>
#ifdef WIN32
@@ -32,6 +36,7 @@
#endif
class Path;
+class FileInfo;
class FileReader final : public Reader {
AllocatedPath path;
@@ -39,12 +44,26 @@ class FileReader final : public Reader {
#ifdef WIN32
HANDLE handle;
#else
- int fd;
+ FileDescriptor fd;
#endif
public:
FileReader(Path _path, Error &error);
+#ifdef WIN32
+ FileReader(FileReader &&other)
+ :path(std::move(other.path)),
+ handle(other.handle) {
+ other.handle = INVALID_HANDLE_VALUE;
+ }
+#else
+ FileReader(FileReader &&other)
+ :path(std::move(other.path)),
+ fd(other.fd) {
+ other.fd.SetUndefined();
+ }
+#endif
+
~FileReader() {
if (IsDefined())
Close();
@@ -55,12 +74,22 @@ public:
#ifdef WIN32
return handle != INVALID_HANDLE_VALUE;
#else
- return fd >= 0;
+ return fd.IsDefined();
#endif
}
+#ifndef WIN32
+ FileDescriptor GetFD() const {
+ return fd;
+ }
+#endif
+
void Close();
+ bool GetFileInfo(FileInfo &info, Error &error) const;
+
+ bool Seek(off_t offset, Error &error);
+
/* virtual methods from class Reader */
size_t Read(void *data, size_t size, Error &error) override;
};
diff --git a/src/fs/io/GunzipReader.cxx b/src/fs/io/GunzipReader.cxx
index ad5e41784..78f5b2c69 100644
--- a/src/fs/io/GunzipReader.cxx
+++ b/src/fs/io/GunzipReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/GunzipReader.hxx b/src/fs/io/GunzipReader.hxx
index 06c44bad6..381d1af5e 100644
--- a/src/fs/io/GunzipReader.hxx
+++ b/src/fs/io/GunzipReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/GzipOutputStream.cxx b/src/fs/io/GzipOutputStream.cxx
index 27ae6b2ad..d2a693b87 100644
--- a/src/fs/io/GzipOutputStream.cxx
+++ b/src/fs/io/GzipOutputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/GzipOutputStream.hxx b/src/fs/io/GzipOutputStream.hxx
index 27ee2dd24..fdab7bca4 100644
--- a/src/fs/io/GzipOutputStream.hxx
+++ b/src/fs/io/GzipOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/OutputStream.hxx b/src/fs/io/OutputStream.hxx
index 71311c71f..f7d101180 100644
--- a/src/fs/io/OutputStream.hxx
+++ b/src/fs/io/OutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/PeekReader.cxx b/src/fs/io/PeekReader.cxx
index 2e8042ab6..ec9520a37 100644
--- a/src/fs/io/PeekReader.cxx
+++ b/src/fs/io/PeekReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/PeekReader.hxx b/src/fs/io/PeekReader.hxx
index 32180b0a8..c00ed66be 100644
--- a/src/fs/io/PeekReader.hxx
+++ b/src/fs/io/PeekReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/Reader.hxx b/src/fs/io/Reader.hxx
index d41e92dd0..657f96ac2 100644
--- a/src/fs/io/Reader.hxx
+++ b/src/fs/io/Reader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/StdioOutputStream.hxx b/src/fs/io/StdioOutputStream.hxx
index c1c0a00bd..88dbe6f00 100644
--- a/src/fs/io/StdioOutputStream.hxx
+++ b/src/fs/io/StdioOutputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/fs/io/TextFile.cxx b/src/fs/io/TextFile.cxx
index 28d6dabcb..9866da08a 100644
--- a/src/fs/io/TextFile.cxx
+++ b/src/fs/io/TextFile.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,14 +28,14 @@
TextFile::TextFile(Path path_fs, Error &error)
:file_reader(new FileReader(path_fs, error)),
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
gunzip_reader(file_reader->IsDefined()
? new AutoGunzipReader(*file_reader)
: nullptr),
#endif
buffered_reader(file_reader->IsDefined()
? new BufferedReader(*
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
gunzip_reader
#else
file_reader
@@ -48,7 +48,7 @@ TextFile::TextFile(Path path_fs, Error &error)
TextFile::~TextFile()
{
delete buffered_reader;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
delete gunzip_reader;
#endif
delete file_reader;
diff --git a/src/fs/io/TextFile.hxx b/src/fs/io/TextFile.hxx
index 5577363e7..bee9e8c23 100644
--- a/src/fs/io/TextFile.hxx
+++ b/src/fs/io/TextFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@ class BufferedReader;
class TextFile {
FileReader *const file_reader;
-#ifdef HAVE_ZLIB
+#ifdef ENABLE_ZLIB
AutoGunzipReader *const gunzip_reader;
#endif
@@ -59,7 +59,6 @@ public:
* Use Check() after nullptr has been returned to check
* whether an error occurred or end-of-file has been reached.
*
- * @param file the source file, opened in text mode
* @return a pointer to the line, or nullptr on end-of-file or error
*/
char *ReadLine();
diff --git a/src/haiku/App_MusicPD b/src/haiku/App_MusicPD
new file mode 100644
index 000000000..4d341fdbf
--- /dev/null
+++ b/src/haiku/App_MusicPD
Binary files differ
diff --git a/src/haiku/mpd.rdef b/src/haiku/mpd.rdef
new file mode 100644
index 000000000..6f1aca2d9
--- /dev/null
+++ b/src/haiku/mpd.rdef
@@ -0,0 +1,69 @@
+resource app_signature "application/x-vnd.MusicPD";
+
+resource app_flags B_BACKGROUND_APP;
+
+// TODO: resource app_version {};
+
+resource vector_icon {
+ $"6E6369661F050102031604BEE29BBEC5403EC540BEE29B4A10004A10000001C6"
+ $"70D073FFFF020116033EB0000000000000003EB000482000482000BE4B0084FF"
+ $"32020316023CAF103CF749BCF7493CAF104A07A44A1DB7A143FFFF02031602BC"
+ $"AB8FBCFA713CFA71BCAB8F4A05E34A004BAB08FFFF03010000020016023CC7EE"
+ $"389BC0BA16573E39B04977C842ADC700FFFFD3020006023C529D3753A2B8966F"
+ $"3D9D084B6044496AAF00474747FFA5A0A002001602BC4E76BC411B3C90DABCA0"
+ $"0D47587D4ABA850090FFD40200160238313C3B5CF0BFCD963C7AAC4C13943FCA"
+ $"F901ECFFC3054B04017E020106023E1C1538010FB7C32B3DF5E649B8BE48DD4A"
+ $"000593DCFF00337F020006023879063B8224BE2CC83B10DB4A1F6F49B894FF9A"
+ $"9A9A00242222020006033C69A60000000000003E186148800049800058F3F3F3"
+ $"00D4CECEFFD9D9D9038DFF06050002001602B2E4F7386B91BA78F7B4F4FD49FB"
+ $"A94AE12500CEFF6603010000020006023C55B638309FBA16573E39B049E9FF43"
+ $"840A008B8787FF161515020016023C57B5364381B785863DA4F54B27C349B7BB"
+ $"0010FF4C02001602BC4E76BC411B3C90DABCA00D47587D4ABA850060FF500200"
+ $"160238313C3B5CF0BFCD963C7AAC4C13943FCAF90174FF22055C04017E020016"
+ $"023879063B8224BE2CC83B10DB4A1F6F49B894FF59001E020016033C3DA60000"
+ $"000000003E186148AC0049800058AD0076FA800333C805020106023A40000000"
+ $"000000003980004A300048400000767676FC403E3E020106023E1C1538010FB7"
+ $"C32B3DF5E649B8BE48DD4A000593DCFF00337F05002102044022C65922B92622"
+ $"224022B92622C659405EB9265EC6595E5E405EC6595EB9260A062E262E4B4C5A"
+ $"5650562C38220A064C5C545C604FCA1BC4875C4A58480A042E264C32562C3822"
+ $"0A044C324C5A5650562C0A042E262E4B4C5A4C320A044934494E3043302A0A04"
+ $"BA29C0283043302ABA31B7540A04494B494E304332C0270A044934494B3241BA"
+ $"31B7540A043E25432252264D2A08043E2543225226522C0A034D2A5226522C08"
+ $"02464F47C5ED0A043246324A4453444E0A04344834494250424E08025436503A"
+ $"0A06262E264C485E5252523430280A04262E483C523430280A04483C485E5252"
+ $"52340A04262E264C485E483C0A04443D4456284928320A04B6F9C28C28492832"
+ $"B701BA840A044454445728492AC28B0A04443D44542A47B701BA840A04382B3D"
+ $"284E2D49310804382B3D284E2D4E330A0349304E2C4E320802425843C9830A06"
+ $"486054606052CA1BC5B95C4D524802044530C2D730C0A430403540BAB540BC06"
+ $"4538C0A438C2D7384A354ABC064ABAB50803452145335B250A044934494B3241"
+ $"BA31B754240A0B0102023EF45B0000000000003EF45B487749B685270A05010B"
+ $"1A3EF45B0000000000003EF45B487749B6852715FF01178400040A09010A0A3E"
+ $"F45B0000000000003EF45B487749B6852715FF0A0A010C023EF45B0000000000"
+ $"003EF45B487749B685270A050101123EF45B0000000000003EF45B487749B685"
+ $"2701178400040A060103023EF45B0000000000003EF45B487749B685270A0701"
+ $"04023EF45B0000000000003EF45B487749B685270A08020506023EF45B000000"
+ $"0000003EF45B487749B685270A0C0109023EF45B0000000000003EF45B487749"
+ $"B685270A0D01070A3EF45B0000000000003EF45B487749B6852715FF0A0E0108"
+ $"0A3EF45B0000000000003EF45B487749B6852715FF0A0F010D1A3EF45B000000"
+ $"0000003EF45B487749B6852715FF01178220040A0A010E0A3EF45B0000000000"
+ $"003EF45B487749B6852715FF0A11010F0A3EF45B0000000000003EF45B487749"
+ $"B6852715FF0A0B01000A3D43F93C2B26BD304E3DF9DE48FCA544AB2E15FF0A00"
+ $"0100123CF8FE3C832FBCE7163E4DA3480D86C5C7B501178400040A010100023C"
+ $"F8FE3C832FBCE7163E4DA3480D86C5C7B50A020100023AC6433A584EBAB58C3C"
+ $"265448124D45D0400A0301001A3CB1A73C46E3BCA16C3E165C480E5DC4720015"
+ $"FF01178200040A0401001A3C808E3C1D64BC71B33DE0FC480EF2C30DBC15FF01"
+ $"178200040A18011D023EAAAA0000000000003EAAAA47155548B0480A12011A1A"
+ $"3EAAAA0000000000003EAAAA47155548B04815FF01178400040A1601190A3EAA"
+ $"AA0000000000003EAAAA47155548B04815FF0A17011B0A3EAAAA000000000000"
+ $"3EAAAA47155548B04815FF0A120111123EAAAA0000000000003EAAAA47155548"
+ $"B04801178400040A130112023EAAAA0000000000003EAAAA47155548B0480A14"
+ $"0113023EAAAA0000000000003EAAAA47155548B0480A15021415023EAAAA0000"
+ $"000000003EAAAA47155548B0480A1D01180A3EAAAA0000000000003EAAAA4715"
+ $"5548B04815FF0A1D01180A3EAAAA0000000000003EAAAA47155548B04800150A"
+ $"1901160A3EAAAA0000000000003EAAAA47155548B04815FF0A1A01170A3EAAAA"
+ $"0000000000003EAAAA47155548B04815FF0A1B011C1A3EAAAA0000000000003E"
+ $"AAAA47155548B04815FF01178220040A1C011E023EAAAA0000000000003EAAAA"
+ $"47155548B0480A12011F1A3EAAAA0000000000003EAAAA47155548B04815FF01"
+ $"178222040A12011F1A3EAAAA0000000000003EAAAA47155548B0480015011784"
+ $"2204"
+};
diff --git a/src/input/AsyncInputStream.cxx b/src/input/AsyncInputStream.cxx
index 5795ecead..68cb8ff68 100644
--- a/src/input/AsyncInputStream.cxx
+++ b/src/input/AsyncInputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/AsyncInputStream.hxx b/src/input/AsyncInputStream.hxx
index d1f0c3b9d..64f566a97 100644
--- a/src/input/AsyncInputStream.hxx
+++ b/src/input/AsyncInputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -62,6 +62,10 @@ protected:
Error postponed_error;
public:
+ /**
+ * @param _buffer a buffer allocated with HugeAllocate(); the
+ * destructor will free it using HugeFree()
+ */
AsyncInputStream(const char *_url,
Mutex &_mutex, Cond &_cond,
void *_buffer, size_t _buffer_size,
diff --git a/src/input/Domain.cxx b/src/input/Domain.cxx
index 26ae298a4..12417af34 100644
--- a/src/input/Domain.cxx
+++ b/src/input/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/Domain.hxx b/src/input/Domain.hxx
index 16fa5e0f1..a18a26426 100644
--- a/src/input/Domain.hxx
+++ b/src/input/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/IcyInputStream.cxx b/src/input/IcyInputStream.cxx
index fb82cdec6..5344a71ec 100644
--- a/src/input/IcyInputStream.cxx
+++ b/src/input/IcyInputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/IcyInputStream.hxx b/src/input/IcyInputStream.hxx
index d8968a741..4fca11eb3 100644
--- a/src/input/IcyInputStream.hxx
+++ b/src/input/IcyInputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/Init.cxx b/src/input/Init.cxx
index 0ee87c4d8..4ed44f100 100644
--- a/src/input/Init.cxx
+++ b/src/input/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include "util/Error.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "Log.hxx"
#include <assert.h>
@@ -33,7 +33,7 @@
bool
input_stream_global_init(Error &error)
{
- const config_param empty;
+ const ConfigBlock empty;
for (unsigned i = 0; input_plugins[i] != nullptr; ++i) {
const InputPlugin *plugin = input_plugins[i];
@@ -42,16 +42,17 @@ input_stream_global_init(Error &error)
assert(*plugin->name != 0);
assert(plugin->open != nullptr);
- const struct config_param *param =
- config_find_block(CONF_INPUT, "plugin", plugin->name);
- if (param == nullptr) {
- param = &empty;
- } else if (!param->GetBlockValue("enabled", true))
+ const auto *block =
+ config_find_block(ConfigBlockOption::INPUT, "plugin",
+ plugin->name);
+ if (block == nullptr) {
+ block = &empty;
+ } else if (!block->GetBlockValue("enabled", true))
/* the plugin is disabled in mpd.conf */
continue;
InputPlugin::InitResult result = plugin->init != nullptr
- ? plugin->init(*param, error)
+ ? plugin->init(*block, error)
: InputPlugin::InitResult::SUCCESS;
switch (result) {
diff --git a/src/input/Init.hxx b/src/input/Init.hxx
index 875fdce7c..eb4f8b1b2 100644
--- a/src/input/Init.hxx
+++ b/src/input/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,14 +23,15 @@
class Error;
/**
- * Initializes this library and all input_stream implementations.
+ * Initializes this library and all #InputStream implementations.
*/
bool
input_stream_global_init(Error &error);
/**
- * Deinitializes this library and all input_stream implementations.
+ * Deinitializes this library and all #InputStream implementations.
*/
-void input_stream_global_finish(void);
+void
+input_stream_global_finish();
#endif
diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx
index c2adb419c..a7c19bef3 100644
--- a/src/input/InputPlugin.hxx
+++ b/src/input/InputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#endif
#endif
-struct config_param;
+struct ConfigBlock;
class InputStream;
class Error;
struct Tag;
@@ -69,13 +69,13 @@ struct InputPlugin {
* @return true on success, false if the plugin should be
* disabled
*/
- InitResult (*init)(const config_param &param, Error &error);
+ InitResult (*init)(const ConfigBlock &block, Error &error);
/**
* Global deinitialization. Called once before MPD shuts
* down (only if init() has returned true).
*/
- void (*finish)(void);
+ void (*finish)();
InputStream *(*open)(const char *uri,
Mutex &mutex, Cond &cond,
diff --git a/src/input/InputStream.cxx b/src/input/InputStream.cxx
index 44f726a62..bf6fd198e 100644
--- a/src/input/InputStream.cxx
+++ b/src/input/InputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -133,9 +133,38 @@ InputStream::LockRead(void *ptr, size_t _size, Error &error)
}
bool
+InputStream::ReadFull(void *_ptr, size_t _size, Error &error)
+{
+ uint8_t *ptr = (uint8_t *)_ptr;
+
+ size_t nbytes_total = 0;
+ while (_size > 0) {
+ size_t nbytes = Read(ptr + nbytes_total, _size, error);
+ if (nbytes == 0)
+ return false;
+
+ nbytes_total += nbytes;
+ _size -= nbytes;
+ }
+ return true;
+}
+
+bool
+InputStream::LockReadFull(void *ptr, size_t _size, Error &error)
+{
+#if !CLANG_CHECK_VERSION(3,6)
+ /* disabled on clang due to -Wtautological-pointer-compare */
+ assert(ptr != nullptr);
+#endif
+ assert(_size > 0);
+
+ const ScopeLock protect(mutex);
+ return ReadFull(ptr, _size, error);
+}
+
+bool
InputStream::LockIsEOF()
{
const ScopeLock protect(mutex);
return IsEOF();
}
-
diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx
index 81b903ba2..bf628ea64 100644
--- a/src/input/InputStream.hxx
+++ b/src/input/InputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -217,13 +217,6 @@ public:
mime = std::move(_mime);
}
- gcc_nonnull_all
- void OverrideMimeType(const char *_mime) {
- assert(ready);
-
- mime = _mime;
- }
-
gcc_pure
bool KnownSize() const {
assert(ready);
@@ -350,7 +343,6 @@ public:
*
* The caller must lock the mutex.
*
- * @param is the InputStream object
* @param ptr the buffer to read into
* @param size the maximum number of bytes to read
* @return the number of bytes read
@@ -364,6 +356,25 @@ public:
*/
gcc_nonnull_all
size_t LockRead(void *ptr, size_t size, Error &error);
+
+ /**
+ * Reads the whole data from the stream into the caller-supplied buffer.
+ *
+ * The caller must lock the mutex.
+ *
+ * @param ptr the buffer to read into
+ * @param size the number of bytes to read
+ * @return true if the whole data was read, false otherwise.
+ */
+ gcc_nonnull_all
+ bool ReadFull(void *ptr, size_t size, Error &error);
+
+ /**
+ * Wrapper for ReadFull() which locks and unlocks the mutex;
+ * the caller must not be holding it already.
+ */
+ gcc_nonnull_all
+ bool LockReadFull(void *ptr, size_t size, Error &error);
};
#endif
diff --git a/src/input/LocalOpen.cxx b/src/input/LocalOpen.cxx
index ad8eba8ce..25644bae1 100644
--- a/src/input/LocalOpen.cxx
+++ b/src/input/LocalOpen.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/LocalOpen.hxx b/src/input/LocalOpen.hxx
index cf1b2b632..6f4ef2a2c 100644
--- a/src/input/LocalOpen.hxx
+++ b/src/input/LocalOpen.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/Offset.hxx b/src/input/Offset.hxx
index 552397904..fbda933ba 100644
--- a/src/input/Offset.hxx
+++ b/src/input/Offset.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/Open.cxx b/src/input/Open.cxx
index 66ccdce74..6bcca0b84 100644
--- a/src/input/Open.cxx
+++ b/src/input/Open.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include "plugins/RewindInputPlugin.hxx"
#include "fs/Traits.hxx"
#include "fs/Path.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -34,10 +35,14 @@ InputStream::Open(const char *url,
Mutex &mutex, Cond &cond,
Error &error)
{
- if (PathTraitsFS::IsAbsolute(url))
- /* TODO: the parameter is UTF-8, not filesystem charset */
- return OpenLocalInputStream(Path::FromFS(url),
+ if (PathTraitsUTF8::IsAbsolute(url)) {
+ const auto path = AllocatedPath::FromUTF8(url, error);
+ if (path.IsNull())
+ return nullptr;
+
+ return OpenLocalInputStream(path,
mutex, cond, error);
+ }
input_plugins_for_each_enabled(plugin) {
InputStream *is;
diff --git a/src/input/ProxyInputStream.cxx b/src/input/ProxyInputStream.cxx
index 74a272f6a..013d880d8 100644
--- a/src/input/ProxyInputStream.cxx
+++ b/src/input/ProxyInputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/ProxyInputStream.hxx b/src/input/ProxyInputStream.hxx
index 727ae5917..c91c1a952 100644
--- a/src/input/ProxyInputStream.hxx
+++ b/src/input/ProxyInputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/Registry.cxx b/src/input/Registry.cxx
index 748c18ca8..e33e51bb9 100644
--- a/src/input/Registry.cxx
+++ b/src/input/Registry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
#include "util/Macros.hxx"
#include "plugins/FileInputPlugin.hxx"
-#ifdef HAVE_ALSA
+#ifdef ENABLE_ALSA
#include "plugins/AlsaInputPlugin.hxx"
#endif
@@ -34,7 +34,7 @@
#include "plugins/CurlInputPlugin.hxx"
#endif
-#ifdef HAVE_FFMPEG
+#ifdef ENABLE_FFMPEG
#include "plugins/FfmpegInputPlugin.hxx"
#endif
@@ -56,7 +56,7 @@
const InputPlugin *const input_plugins[] = {
&input_plugin_file,
-#ifdef HAVE_ALSA
+#ifdef ENABLE_ALSA
&input_plugin_alsa,
#endif
#ifdef ENABLE_ARCHIVE
@@ -65,7 +65,7 @@ const InputPlugin *const input_plugins[] = {
#ifdef ENABLE_CURL
&input_plugin_curl,
#endif
-#ifdef HAVE_FFMPEG
+#ifdef ENABLE_FFMPEG
&input_plugin_ffmpeg,
#endif
#ifdef ENABLE_SMBCLIENT
diff --git a/src/input/Registry.hxx b/src/input/Registry.hxx
index 1b81f8f06..af1b3be8b 100644
--- a/src/input/Registry.hxx
+++ b/src/input/Registry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/TextInputStream.cxx b/src/input/TextInputStream.cxx
index 5a8dcc065..897b2b472 100644
--- a/src/input/TextInputStream.cxx
+++ b/src/input/TextInputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/TextInputStream.hxx b/src/input/TextInputStream.hxx
index 6f39d22cf..d0b5d5f40 100644
--- a/src/input/TextInputStream.hxx
+++ b/src/input/TextInputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -30,10 +30,10 @@ class TextInputStream {
public:
/**
- * Wraps an existing #input_stream object into a #TextInputStream,
+ * Wraps an existing #InputStream object into a #TextInputStream,
* to read its contents as text lines.
*
- * @param _is an open #input_stream object
+ * @param _is an open #InputStream object
*/
explicit TextInputStream(InputStream &_is)
:is(_is) {}
diff --git a/src/input/ThreadInputStream.cxx b/src/input/ThreadInputStream.cxx
index 235ed2b01..061d5cbfe 100644
--- a/src/input/ThreadInputStream.cxx
+++ b/src/input/ThreadInputStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/ThreadInputStream.hxx b/src/input/ThreadInputStream.hxx
index c6ac7669c..6fc3e2e7b 100644
--- a/src/input/ThreadInputStream.hxx
+++ b/src/input/ThreadInputStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx
index f03f745c6..d2be734b5 100644
--- a/src/input/plugins/AlsaInputPlugin.cxx
+++ b/src/input/plugins/AlsaInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/AlsaInputPlugin.hxx b/src/input/plugins/AlsaInputPlugin.hxx
index dddf7dfd7..eb50ec8d6 100644
--- a/src/input/plugins/AlsaInputPlugin.hxx
+++ b/src/input/plugins/AlsaInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/ArchiveInputPlugin.cxx b/src/input/plugins/ArchiveInputPlugin.cxx
index da3d7ca71..b6472e00a 100644
--- a/src/input/plugins/ArchiveInputPlugin.cxx
+++ b/src/input/plugins/ArchiveInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/ArchiveInputPlugin.hxx b/src/input/plugins/ArchiveInputPlugin.hxx
index b6158684a..79331cd5a 100644
--- a/src/input/plugins/ArchiveInputPlugin.hxx
+++ b/src/input/plugins/ArchiveInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx
index f847b35c1..dda5cb83f 100644
--- a/src/input/plugins/CdioParanoiaInputPlugin.cxx
+++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -31,7 +31,7 @@
#include "system/ByteOrder.hxx"
#include "fs/AllocatedPath.hxx"
#include "Log.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "config/ConfigError.hxx"
#include <stdio.h>
@@ -39,7 +39,6 @@
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
-#include <glib.h>
#include <assert.h>
#ifdef HAVE_CDIO_PARANOIA_PARANOIA_H
@@ -107,9 +106,9 @@ static constexpr Domain cdio_domain("cdio");
static bool default_reverse_endian;
static InputPlugin::InitResult
-input_cdio_init(const config_param &param, Error &error)
+input_cdio_init(const ConfigBlock &block, Error &error)
{
- const char *value = param.GetBlockValue("default_byte_order");
+ const char *value = block.GetBlockValue("default_byte_order");
if (value != nullptr) {
if (strcmp(value, "little_endian") == 0)
default_reverse_endian = IsBigEndian();
@@ -149,7 +148,7 @@ parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error)
const char *slash = strrchr(src, '/');
if (slash == nullptr) {
/* play the whole CD in the specified drive */
- g_strlcpy(dest->device, src, sizeof(dest->device));
+ CopyString(dest->device, src, sizeof(dest->device));
dest->track = -1;
return true;
}
diff --git a/src/input/plugins/CdioParanoiaInputPlugin.hxx b/src/input/plugins/CdioParanoiaInputPlugin.hxx
index e2804e8c7..a51b43827 100644
--- a/src/input/plugins/CdioParanoiaInputPlugin.hxx
+++ b/src/input/plugins/CdioParanoiaInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx
index 3aa3b0018..814fe7a32 100644
--- a/src/input/plugins/CurlInputPlugin.cxx
+++ b/src/input/plugins/CurlInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,7 @@
#include "../IcyInputStream.hxx"
#include "../InputPlugin.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "tag/Tag.hxx"
#include "tag/TagBuilder.hxx"
#include "event/SocketMonitor.hxx"
@@ -537,7 +537,7 @@ CurlMulti::OnTimeout()
*/
static InputPlugin::InitResult
-input_curl_init(const config_param &param, Error &error)
+input_curl_init(const ConfigBlock &block, Error &error)
{
CURLcode code = curl_global_init(CURL_GLOBAL_ALL);
if (code != CURLE_OK) {
@@ -559,22 +559,22 @@ input_curl_init(const config_param &param, Error &error)
http_200_aliases = curl_slist_append(http_200_aliases, "ICY 200 OK");
- proxy = param.GetBlockValue("proxy");
- proxy_port = param.GetBlockValue("proxy_port", 0u);
- proxy_user = param.GetBlockValue("proxy_user");
- proxy_password = param.GetBlockValue("proxy_password");
+ proxy = block.GetBlockValue("proxy");
+ proxy_port = block.GetBlockValue("proxy_port", 0u);
+ proxy_user = block.GetBlockValue("proxy_user");
+ proxy_password = block.GetBlockValue("proxy_password");
if (proxy == nullptr) {
/* deprecated proxy configuration */
- proxy = config_get_string(CONF_HTTP_PROXY_HOST, nullptr);
- proxy_port = config_get_positive(CONF_HTTP_PROXY_PORT, 0);
- proxy_user = config_get_string(CONF_HTTP_PROXY_USER, nullptr);
- proxy_password = config_get_string(CONF_HTTP_PROXY_PASSWORD,
+ proxy = config_get_string(ConfigOption::HTTP_PROXY_HOST);
+ proxy_port = config_get_positive(ConfigOption::HTTP_PROXY_PORT, 0);
+ proxy_user = config_get_string(ConfigOption::HTTP_PROXY_USER);
+ proxy_password = config_get_string(ConfigOption::HTTP_PROXY_PASSWORD,
"");
}
- verify_peer = param.GetBlockValue("verify_peer", true);
- verify_host = param.GetBlockValue("verify_host", true);
+ verify_peer = block.GetBlockValue("verify_peer", true);
+ verify_host = block.GetBlockValue("verify_host", true);
CURLM *multi = curl_multi_init();
if (multi == nullptr) {
@@ -651,7 +651,10 @@ CurlInputStream::HeaderReceived(const char *name, std::string &&value)
return;
size_t icy_metaint = ParseUint64(value.c_str());
+#ifndef WIN32
+ /* Windows doesn't know "%z" */
FormatDebug(curl_domain, "icy-metaint=%zu", icy_metaint);
+#endif
if (icy_metaint > 0) {
icy->Enable(icy_metaint);
diff --git a/src/input/plugins/CurlInputPlugin.hxx b/src/input/plugins/CurlInputPlugin.hxx
index 4acb18bfc..57bbe714b 100644
--- a/src/input/plugins/CurlInputPlugin.hxx
+++ b/src/input/plugins/CurlInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx
index 669f8d403..444273d90 100644
--- a/src/input/plugins/FfmpegInputPlugin.cxx
+++ b/src/input/plugins/FfmpegInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,7 @@
#include "config.h"
#include "FfmpegInputPlugin.hxx"
+#include "lib/ffmpeg/Init.hxx"
#include "lib/ffmpeg/Domain.hxx"
#include "lib/ffmpeg/Error.hxx"
#include "../InputStream.hxx"
@@ -31,7 +32,6 @@
extern "C" {
#include <libavformat/avio.h>
-#include <libavformat/avformat.h>
}
struct FfmpegInputStream final : public InputStream {
@@ -72,10 +72,10 @@ input_ffmpeg_supported(void)
}
static InputPlugin::InitResult
-input_ffmpeg_init(gcc_unused const config_param &param,
+input_ffmpeg_init(gcc_unused const ConfigBlock &block,
Error &error)
{
- av_register_all();
+ FfmpegInit();
/* disable this plugin if there's no registered protocol */
if (!input_ffmpeg_supported()) {
diff --git a/src/input/plugins/FfmpegInputPlugin.hxx b/src/input/plugins/FfmpegInputPlugin.hxx
index 43f829e89..40a834bdc 100644
--- a/src/input/plugins/FfmpegInputPlugin.hxx
+++ b/src/input/plugins/FfmpegInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx
index 867b5722d..aa4676470 100644
--- a/src/input/plugins/FileInputPlugin.cxx
+++ b/src/input/plugins/FileInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,34 +23,30 @@
#include "../InputPlugin.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
-#include "fs/FileSystem.hxx"
#include "fs/Path.hxx"
-#include "system/fd_util.h"
-#include "open.h"
+#include "fs/FileInfo.hxx"
+#include "fs/io/FileReader.hxx"
+#include "system/FileDescriptor.hxx"
#include <sys/stat.h>
-#include <unistd.h>
+#include <fcntl.h>
#include <errno.h>
static constexpr Domain file_domain("file");
class FileInputStream final : public InputStream {
- const int fd;
+ FileReader reader;
public:
- FileInputStream(const char *path, int _fd, off_t _size,
+ FileInputStream(const char *path, FileReader &&_reader, off_t _size,
Mutex &_mutex, Cond &_cond)
:InputStream(path, _mutex, _cond),
- fd(_fd) {
+ reader(std::move(_reader)) {
size = _size;
seekable = true;
SetReady();
}
- ~FileInputStream() {
- close(fd);
- }
-
/* virtual methods from InputStream */
bool IsEOF() override {
@@ -66,32 +62,28 @@ OpenFileInputStream(Path path,
Mutex &mutex, Cond &cond,
Error &error)
{
- const int fd = OpenFile(path, O_RDONLY|O_BINARY, 0);
- if (fd < 0) {
- error.FormatErrno("Failed to open \"%s\"",
- path.c_str());
+ FileReader reader(path, error);
+ if (!reader.IsDefined())
return nullptr;
- }
- struct stat st;
- if (fstat(fd, &st) < 0) {
- error.FormatErrno("Failed to stat \"%s\"", path.c_str());
- close(fd);
+ FileInfo info;
+ if (!reader.GetFileInfo(info, error))
return nullptr;
- }
- if (!S_ISREG(st.st_mode)) {
+ if (!info.IsRegular()) {
error.Format(file_domain, "Not a regular file: %s",
path.c_str());
- close(fd);
return nullptr;
}
#ifdef POSIX_FADV_SEQUENTIAL
- posix_fadvise(fd, (off_t)0, st.st_size, POSIX_FADV_SEQUENTIAL);
+ posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(),
+ POSIX_FADV_SEQUENTIAL);
#endif
- return new FileInputStream(path.c_str(), fd, st.st_size, mutex, cond);
+ return new FileInputStream(path.ToUTF8().c_str(),
+ std::move(reader), info.GetSize(),
+ mutex, cond);
}
static InputStream *
@@ -107,24 +99,19 @@ input_file_open(gcc_unused const char *filename,
bool
FileInputStream::Seek(offset_type new_offset, Error &error)
{
- auto result = lseek(fd, (off_t)new_offset, SEEK_SET);
- if (result < 0) {
- error.SetErrno("Failed to seek");
+ if (!reader.Seek((off_t)new_offset, error))
return false;
- }
- offset = (offset_type)result;
+ offset = new_offset;
return true;
}
size_t
FileInputStream::Read(void *ptr, size_t read_size, Error &error)
{
- ssize_t nbytes = read(fd, ptr, read_size);
- if (nbytes < 0) {
- error.SetErrno("Failed to read");
+ ssize_t nbytes = reader.Read(ptr, read_size, error);
+ if (nbytes < 0)
return 0;
- }
offset += nbytes;
return (size_t)nbytes;
diff --git a/src/input/plugins/FileInputPlugin.hxx b/src/input/plugins/FileInputPlugin.hxx
index ee194ec34..a00401c53 100644
--- a/src/input/plugins/FileInputPlugin.hxx
+++ b/src/input/plugins/FileInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx
index d01cff3b3..244dfd945 100644
--- a/src/input/plugins/MmsInputPlugin.cxx
+++ b/src/input/plugins/MmsInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/MmsInputPlugin.hxx b/src/input/plugins/MmsInputPlugin.hxx
index b4017ffd6..cf1b9ba65 100644
--- a/src/input/plugins/MmsInputPlugin.hxx
+++ b/src/input/plugins/MmsInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx
index c6c0970b9..077362c18 100644
--- a/src/input/plugins/NfsInputPlugin.cxx
+++ b/src/input/plugins/NfsInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,6 @@
#include "util/StringUtil.hxx"
#include "util/Error.hxx"
-extern "C" {
-#include <nfsc/libnfs.h>
-}
-
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
@@ -225,7 +221,7 @@ NfsInputStream::OnNfsFileError(Error &&error)
*/
static InputPlugin::InitResult
-input_nfs_init(const config_param &, Error &)
+input_nfs_init(const ConfigBlock &, Error &)
{
nfs_init();
return InputPlugin::InitResult::SUCCESS;
diff --git a/src/input/plugins/NfsInputPlugin.hxx b/src/input/plugins/NfsInputPlugin.hxx
index d2cc87549..5420ec967 100644
--- a/src/input/plugins/NfsInputPlugin.hxx
+++ b/src/input/plugins/NfsInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/RewindInputPlugin.cxx b/src/input/plugins/RewindInputPlugin.cxx
index 95f604044..cd027299c 100644
--- a/src/input/plugins/RewindInputPlugin.cxx
+++ b/src/input/plugins/RewindInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/RewindInputPlugin.hxx b/src/input/plugins/RewindInputPlugin.hxx
index 56b01b585..099921e7a 100644
--- a/src/input/plugins/RewindInputPlugin.hxx
+++ b/src/input/plugins/RewindInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx
index 399613720..ec6857c19 100644
--- a/src/input/plugins/SmbclientInputPlugin.cxx
+++ b/src/input/plugins/SmbclientInputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -66,14 +66,14 @@ public:
*/
static InputPlugin::InitResult
-input_smbclient_init(gcc_unused const config_param &param, Error &error)
+input_smbclient_init(gcc_unused const ConfigBlock &block, Error &error)
{
if (!SmbclientInit(error))
return InputPlugin::InitResult::UNAVAILABLE;
// TODO: create one global SMBCCTX here?
- // TODO: evaluate config_param, call smbc_setOption*()
+ // TODO: evaluate ConfigBlock, call smbc_setOption*()
return InputPlugin::InitResult::SUCCESS;
}
diff --git a/src/input/plugins/SmbclientInputPlugin.hxx b/src/input/plugins/SmbclientInputPlugin.hxx
index a0539d020..31c55196c 100644
--- a/src/input/plugins/SmbclientInputPlugin.hxx
+++ b/src/input/plugins/SmbclientInputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/expat/ExpatParser.cxx b/src/lib/expat/ExpatParser.cxx
index c6b1abe76..7d9f1d587 100644
--- a/src/lib/expat/ExpatParser.cxx
+++ b/src/lib/expat/ExpatParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/expat/ExpatParser.hxx b/src/lib/expat/ExpatParser.hxx
index 9d2ac65e5..5f2626dda 100644
--- a/src/lib/expat/ExpatParser.hxx
+++ b/src/lib/expat/ExpatParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,6 +41,9 @@ public:
XML_ParserFree(parser);
}
+ ExpatParser(const ExpatParser &) = delete;
+ ExpatParser &operator=(const ExpatParser &) = delete;
+
void SetElementHandler(XML_StartElementHandler start,
XML_EndElementHandler end) {
XML_SetElementHandler(parser, start, end);
diff --git a/src/lib/ffmpeg/Buffer.hxx b/src/lib/ffmpeg/Buffer.hxx
new file mode 100644
index 000000000..2463ce197
--- /dev/null
+++ b/src/lib/ffmpeg/Buffer.hxx
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_BUFFER_HXX
+#define MPD_FFMPEG_BUFFER_HXX
+
+extern "C" {
+#include <libavutil/mem.h>
+
+#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 18, 0)
+#define HAVE_AV_FAST_MALLOC
+#else
+#include <libavcodec/avcodec.h>
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 25, 0)
+#define HAVE_AV_FAST_MALLOC
+#endif
+#endif
+}
+
+#include <stddef.h>
+
+/* suppress the ffmpeg compatibility macro */
+#ifdef SampleFormat
+#undef SampleFormat
+#endif
+
+class FfmpegBuffer {
+ void *data;
+ unsigned size;
+
+public:
+ FfmpegBuffer():data(nullptr), size(0) {}
+
+ ~FfmpegBuffer() {
+ av_free(data);
+ }
+
+ gcc_malloc
+ void *Get(size_t min_size) {
+#ifdef HAVE_AV_FAST_MALLOC
+ av_fast_malloc(&data, &size, min_size);
+#else
+ void *new_data = av_fast_realloc(data, &size, min_size);
+ if (new_data == nullptr)
+ return AVERROR(ENOMEM);
+ data = new_data;
+#endif
+ return data;
+ }
+
+ template<typename T>
+ T *GetT(size_t n) {
+ return (T *)Get(n * sizeof(T));
+ }
+};
+
+#endif
diff --git a/src/lib/ffmpeg/Domain.cxx b/src/lib/ffmpeg/Domain.cxx
index 78db30bae..08b3c6b43 100644
--- a/src/lib/ffmpeg/Domain.cxx
+++ b/src/lib/ffmpeg/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/ffmpeg/Domain.hxx b/src/lib/ffmpeg/Domain.hxx
index f21498a32..c6d82f800 100644
--- a/src/lib/ffmpeg/Domain.hxx
+++ b/src/lib/ffmpeg/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/ffmpeg/Error.cxx b/src/lib/ffmpeg/Error.cxx
index bcc12fb1d..53f4d65f5 100644
--- a/src/lib/ffmpeg/Error.cxx
+++ b/src/lib/ffmpeg/Error.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/ffmpeg/Error.hxx b/src/lib/ffmpeg/Error.hxx
index 943dca6ce..a92394b2c 100644
--- a/src/lib/ffmpeg/Error.hxx
+++ b/src/lib/ffmpeg/Error.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/ffmpeg/Init.cxx b/src/lib/ffmpeg/Init.cxx
new file mode 100644
index 000000000..44c641f89
--- /dev/null
+++ b/src/lib/ffmpeg/Init.cxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "Init.hxx"
+#include "LogCallback.hxx"
+
+extern "C" {
+#include <libavformat/avformat.h>
+}
+
+void
+FfmpegInit()
+{
+ av_log_set_callback(FfmpegLogCallback);
+
+ av_register_all();
+}
+
diff --git a/src/tag/TagSettings.c b/src/lib/ffmpeg/Init.hxx
index e0c577c2b..ca5f9d691 100644
--- a/src/tag/TagSettings.c
+++ b/src/lib/ffmpeg/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,9 +17,10 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include "TagSettings.h"
+#ifndef MPD_FFMPEG_INIT_HXX
+#define MPD_FFMPEG_INIT_HXX
-bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES] = {
- /* ignore comments by default */
- [TAG_COMMENT] = true,
-};
+void
+FfmpegInit();
+
+#endif
diff --git a/src/lib/ffmpeg/LogCallback.cxx b/src/lib/ffmpeg/LogCallback.cxx
new file mode 100644
index 000000000..ce2caeabb
--- /dev/null
+++ b/src/lib/ffmpeg/LogCallback.cxx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* necessary because libavutil/common.h uses UINT64_C */
+#define __STDC_CONSTANT_MACROS
+
+#include "config.h"
+#include "LogCallback.hxx"
+#include "Domain.hxx"
+#include "LogV.hxx"
+#include "util/Domain.hxx"
+
+extern "C" {
+#include <libavutil/log.h>
+}
+
+#include <stdio.h>
+
+gcc_const
+static LogLevel
+FfmpegImportLogLevel(int level)
+{
+ if (level <= AV_LOG_FATAL)
+ return LogLevel::ERROR;
+
+ if (level <= AV_LOG_WARNING)
+ return LogLevel::WARNING;
+
+ if (level <= AV_LOG_INFO)
+ return LogLevel::INFO;
+
+ return LogLevel::DEBUG;
+}
+
+void
+FfmpegLogCallback(gcc_unused void *ptr, int level, const char *fmt, va_list vl)
+{
+ const AVClass * cls = nullptr;
+
+ if (ptr != nullptr)
+ 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 Domain d(domain);
+ LogFormatV(d, FfmpegImportLogLevel(level), fmt, vl);
+ }
+}
diff --git a/src/lib/ffmpeg/LogCallback.hxx b/src/lib/ffmpeg/LogCallback.hxx
new file mode 100644
index 000000000..f1b114366
--- /dev/null
+++ b/src/lib/ffmpeg/LogCallback.hxx
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_LOG_CALLBACK_HXX
+#define MPD_FFMPEG_LOG_CALLBACK_HXX
+
+#include "check.h"
+
+#include <stdarg.h>
+
+void
+FfmpegLogCallback(void *ptr, int level, const char *fmt, va_list vl);
+
+#endif
diff --git a/src/lib/ffmpeg/LogError.cxx b/src/lib/ffmpeg/LogError.cxx
new file mode 100644
index 000000000..8a0675a1c
--- /dev/null
+++ b/src/lib/ffmpeg/LogError.cxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "LogError.hxx"
+#include "Domain.hxx"
+#include "Log.hxx"
+
+#include <cstdint> /* needed due to libavutil bug */
+
+extern "C" {
+#include <libavutil/error.h>
+}
+
+void
+LogFfmpegError(int errnum)
+{
+ char msg[256];
+ av_strerror(errnum, msg, sizeof(msg));
+ LogError(ffmpeg_domain, msg);
+}
+
+void
+LogFfmpegError(int errnum, const char *prefix)
+{
+ char msg[256];
+ av_strerror(errnum, msg, sizeof(msg));
+ FormatError(ffmpeg_domain, "%s: %s", prefix, msg);
+}
diff --git a/src/lib/ffmpeg/LogError.hxx b/src/lib/ffmpeg/LogError.hxx
new file mode 100644
index 000000000..e6d96988d
--- /dev/null
+++ b/src/lib/ffmpeg/LogError.hxx
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_LOG_ERROR_HXX
+#define MPD_FFMPEG_LOG_ERROR_HXX
+
+void
+LogFfmpegError(int errnum);
+
+void
+LogFfmpegError(int errnum, const char *prefix);
+
+#endif
diff --git a/src/lib/ffmpeg/Time.hxx b/src/lib/ffmpeg/Time.hxx
new file mode 100644
index 000000000..92c076d0d
--- /dev/null
+++ b/src/lib/ffmpeg/Time.hxx
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FFMPEG_TIME_HXX
+#define MPD_FFMPEG_TIME_HXX
+
+#include "Chrono.hxx"
+#include "Compiler.h"
+
+extern "C" {
+#include <libavutil/avutil.h>
+#include <libavutil/mathematics.h>
+}
+
+#include <assert.h>
+#include <stdint.h>
+
+/* suppress the ffmpeg compatibility macro */
+#ifdef SampleFormat
+#undef SampleFormat
+#endif
+
+/**
+ * Convert a FFmpeg time stamp to a floating point value (in seconds).
+ */
+gcc_const
+static inline double
+FfmpegTimeToDouble(int64_t t, const AVRational time_base)
+{
+ assert(t != (int64_t)AV_NOPTS_VALUE);
+
+ return (double)av_rescale_q(t, time_base, (AVRational){1, 1024})
+ / (double)1024;
+}
+
+/**
+ * Convert a std::ratio to a #AVRational.
+ */
+template<typename Ratio>
+static inline constexpr AVRational
+RatioToAVRational()
+{
+ return { Ratio::num, Ratio::den };
+}
+
+/**
+ * Convert a FFmpeg time stamp to a #SongTime.
+ */
+gcc_const
+static inline SongTime
+FromFfmpegTime(int64_t t, const AVRational time_base)
+{
+ assert(t != (int64_t)AV_NOPTS_VALUE);
+
+ return SongTime::FromMS(av_rescale_q(t, time_base,
+ (AVRational){1, 1000}));
+}
+
+/**
+ * Convert a FFmpeg time stamp to a #SignedSongTime.
+ */
+gcc_const
+static inline SignedSongTime
+FromFfmpegTimeChecked(int64_t t, const AVRational time_base)
+{
+ return t != (int64_t)AV_NOPTS_VALUE
+ ? SignedSongTime(FromFfmpegTime(t, time_base))
+ : SignedSongTime::Negative();
+}
+
+/**
+ * Convert a #SongTime to a FFmpeg time stamp with the given base.
+ */
+gcc_const
+static inline int64_t
+ToFfmpegTime(SongTime t, const AVRational time_base)
+{
+ return av_rescale_q(t.count(),
+ RatioToAVRational<SongTime::period>(),
+ time_base);
+}
+
+/**
+ * Replace #AV_NOPTS_VALUE with the given fallback.
+ */
+static constexpr int64_t
+FfmpegTimestampFallback(int64_t t, int64_t fallback)
+{
+ return gcc_likely(t != int64_t(AV_NOPTS_VALUE))
+ ? t
+ : fallback;
+}
+
+#endif
diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx
index 17b536b37..dc8598a7a 100644
--- a/src/lib/icu/Collate.cxx
+++ b/src/lib/icu/Collate.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,8 +19,10 @@
#include "config.h"
#include "Collate.hxx"
+#include "util/AllocatedString.hxx"
#ifdef HAVE_ICU
+#include "Util.hxx"
#include "Error.hxx"
#include "util/WritableBuffer.hxx"
#include "util/ConstBuffer.hxx"
@@ -29,13 +31,17 @@
#include <unicode/ucol.h>
#include <unicode/ustring.h>
-#elif defined(HAVE_GLIB)
-#include <glib.h>
#else
#include <algorithm>
#include <ctype.h>
#endif
+#ifdef WIN32
+#include "Win32.hxx"
+#include "util/AllocatedString.hxx"
+#include <windows.h>
+#endif
+
#include <assert.h>
#include <string.h>
#include <strings.h>
@@ -71,50 +77,6 @@ IcuCollateFinish()
ucol_close(collator);
}
-static WritableBuffer<UChar>
-UCharFromUTF8(const char *src)
-{
- assert(src != nullptr);
-
- const size_t src_length = strlen(src);
- const size_t dest_capacity = src_length;
- UChar *dest = new UChar[dest_capacity];
-
- UErrorCode error_code = U_ZERO_ERROR;
- int32_t dest_length;
- u_strFromUTF8(dest, dest_capacity, &dest_length,
- src, src_length,
- &error_code);
- if (U_FAILURE(error_code)) {
- delete[] dest;
- return nullptr;
- }
-
- return { dest, size_t(dest_length) };
-}
-
-static WritableBuffer<char>
-UCharToUTF8(ConstBuffer<UChar> src)
-{
- assert(!src.IsNull());
-
- /* worst-case estimate */
- size_t dest_capacity = 4 * src.size;
-
- char *dest = new char[dest_capacity];
-
- UErrorCode error_code = U_ZERO_ERROR;
- int32_t dest_length;
- u_strToUTF8(dest, dest_capacity, &dest_length, src.data, src.size,
- &error_code);
- if (U_FAILURE(error_code)) {
- delete[] dest;
- return nullptr;
- }
-
- return { dest, size_t(dest_length) };
-}
-
#endif
gcc_pure
@@ -150,14 +112,32 @@ IcuCollate(const char *a, const char *b)
return result;
#endif
-#elif defined(HAVE_GLIB)
- return g_utf8_collate(a, b);
+#elif defined(WIN32)
+ const auto wa = MultiByteToWideChar(CP_UTF8, a);
+ const auto wb = MultiByteToWideChar(CP_UTF8, b);
+ if (wa.IsNull())
+ return wb.IsNull() ? 0 : -1;
+ else if (wb.IsNull())
+ return 1;
+
+ auto result = CompareStringEx(LOCALE_NAME_INVARIANT,
+ LINGUISTIC_IGNORECASE,
+ wa.c_str(), -1,
+ wb.c_str(), -1,
+ nullptr, nullptr, 0);
+ if (result != 0)
+ /* "To maintain the C runtime convention of comparing
+ strings, the value 2 can be subtracted from a
+ nonzero return value." */
+ result -= 2;
+
+ return result;
#else
- return strcasecmp(a, b);
+ return strcoll(a, b);
#endif
}
-std::string
+AllocatedString<>
IcuCaseFold(const char *src)
{
#ifdef HAVE_ICU
@@ -169,37 +149,70 @@ IcuCaseFold(const char *src)
const auto u = UCharFromUTF8(src);
if (u.IsNull())
- return std::string(src);
+ return AllocatedString<>::Duplicate(src);
size_t folded_capacity = u.size * 2u;
UChar *folded = new UChar[folded_capacity];
UErrorCode error_code = U_ZERO_ERROR;
size_t folded_length = u_strFoldCase(folded, folded_capacity,
- u.data, u.size,
- U_FOLD_CASE_DEFAULT,
- &error_code);
+ u.data, u.size,
+ U_FOLD_CASE_DEFAULT,
+ &error_code);
delete[] u.data;
if (folded_length == 0 || error_code != U_ZERO_ERROR) {
delete[] folded;
- return std::string(src);
+ return AllocatedString<>::Duplicate(src);
}
- auto result2 = UCharToUTF8({folded, folded_length});
+ auto result = UCharToUTF8({folded, folded_length});
delete[] folded;
- if (result2.IsNull())
- return std::string(src);
-
- std::string result(result2.data, result2.size);
- delete[] result2.data;
-#elif defined(HAVE_GLIB)
- char *tmp = g_utf8_casefold(src, -1);
- std::string result(tmp);
- g_free(tmp);
+ return result;
+
+#elif defined(WIN32)
+ const auto u = MultiByteToWideChar(CP_UTF8, src);
+ if (u.IsNull())
+ return AllocatedString<>::Duplicate(src);
+
+ const int size = LCMapStringEx(LOCALE_NAME_INVARIANT,
+ LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
+ u.c_str(), -1, nullptr, 0,
+ nullptr, nullptr, 0);
+ if (size <= 0)
+ return AllocatedString<>::Duplicate(src);
+
+ auto buffer = new wchar_t[size];
+ if (LCMapStringEx(LOCALE_NAME_INVARIANT,
+ LCMAP_SORTKEY|LINGUISTIC_IGNORECASE,
+ u.c_str(), -1, buffer, size,
+ nullptr, nullptr, 0) <= 0) {
+ delete[] buffer;
+ return AllocatedString<>::Duplicate(src);
+ }
+
+ auto result = WideCharToMultiByte(CP_UTF8, buffer);
+ delete[] buffer;
+ if (result.IsNull())
+ return AllocatedString<>::Duplicate(src);
+
+ return result;
+
#else
- std::string result(src);
- std::transform(result.begin(), result.end(), result.begin(), tolower);
+ size_t size = strlen(src) + 1;
+ auto buffer = new char[size];
+ size_t nbytes = strxfrm(buffer, src, size);
+ if (nbytes >= size) {
+ /* buffer too small - reallocate and try again */
+ delete[] buffer;
+ size = nbytes + 1;
+ buffer = new char[size];
+ nbytes = strxfrm(buffer, src, size);
+ }
+
+ assert(nbytes < size);
+ assert(buffer[nbytes] == 0);
+
+ return AllocatedString<>::Donate(buffer);
#endif
- return result;
}
diff --git a/src/lib/icu/Collate.hxx b/src/lib/icu/Collate.hxx
index 8ae8de46a..0ad3b24ff 100644
--- a/src/lib/icu/Collate.hxx
+++ b/src/lib/icu/Collate.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include <string>
class Error;
+template<typename T> class AllocatedString;
bool
IcuCollateInit(Error &error);
@@ -38,7 +39,7 @@ int
IcuCollate(const char *a, const char *b);
gcc_pure gcc_nonnull_all
-std::string
+AllocatedString<char>
IcuCaseFold(const char *src);
#endif
diff --git a/src/lib/icu/Converter.cxx b/src/lib/icu/Converter.cxx
new file mode 100644
index 000000000..61c0cbdd5
--- /dev/null
+++ b/src/lib/icu/Converter.cxx
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Converter.hxx"
+#include "Error.hxx"
+#include "util/Error.hxx"
+#include "util/Macros.hxx"
+#include "util/AllocatedString.hxx"
+#include "util/WritableBuffer.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <string.h>
+
+#ifdef HAVE_ICU
+#include "Util.hxx"
+#include <unicode/ucnv.h>
+#elif defined(HAVE_ICONV)
+#include "util/Domain.hxx"
+static constexpr Domain iconv_domain("iconv");
+#endif
+
+#ifdef HAVE_ICU
+
+IcuConverter::~IcuConverter()
+{
+ ucnv_close(converter);
+}
+
+#endif
+
+#ifdef HAVE_ICU_CONVERTER
+
+IcuConverter *
+IcuConverter::Create(const char *charset, Error &error)
+{
+#ifdef HAVE_ICU
+ UErrorCode code = U_ZERO_ERROR;
+ UConverter *converter = ucnv_open(charset, &code);
+ if (converter == nullptr) {
+ error.Format(icu_domain, int(code),
+ "Failed to initialize charset '%s': %s",
+ charset, u_errorName(code));
+ return nullptr;
+ }
+
+ return new IcuConverter(converter);
+#elif defined(HAVE_ICONV)
+ iconv_t to = iconv_open("utf-8", charset);
+ iconv_t from = iconv_open(charset, "utf-8");
+ if (to == (iconv_t)-1 || from == (iconv_t)-1) {
+ error.FormatErrno("Failed to initialize charset '%s'",
+ charset);
+ if (to != (iconv_t)-1)
+ iconv_close(to);
+ if (from != (iconv_t)-1)
+ iconv_close(from);
+ return nullptr;
+ }
+
+ return new IcuConverter(to, from);
+#endif
+}
+
+#ifdef HAVE_ICU
+#elif defined(HAVE_ICONV)
+
+static AllocatedString<char>
+DoConvert(iconv_t conv, const char *src)
+{
+ // TODO: dynamic buffer?
+ char buffer[4096];
+ char *in = const_cast<char *>(src);
+ char *out = buffer;
+ size_t in_left = strlen(src);
+ size_t out_left = sizeof(buffer);
+
+ size_t n = iconv(conv, &in, &in_left, &out, &out_left);
+
+ if (n == static_cast<size_t>(-1) || in_left > 0)
+ return nullptr;
+
+ return AllocatedString<>::Duplicate(buffer, sizeof(buffer) - out_left);
+}
+
+#endif
+
+AllocatedString<char>
+IcuConverter::ToUTF8(const char *s) const
+{
+#ifdef HAVE_ICU
+ const ScopeLock protect(mutex);
+
+ ucnv_resetToUnicode(converter);
+
+ // TODO: dynamic buffer?
+ UChar buffer[4096], *target = buffer;
+ const char *source = s;
+
+ UErrorCode code = U_ZERO_ERROR;
+
+ ucnv_toUnicode(converter, &target, buffer + ARRAY_SIZE(buffer),
+ &source, source + strlen(source),
+ nullptr, true, &code);
+ if (code != U_ZERO_ERROR)
+ return nullptr;
+
+ const size_t target_length = target - buffer;
+ return UCharToUTF8({buffer, target_length});
+#elif defined(HAVE_ICONV)
+ return DoConvert(to_utf8, s);
+#endif
+}
+
+AllocatedString<char>
+IcuConverter::FromUTF8(const char *s) const
+{
+#ifdef HAVE_ICU
+ const ScopeLock protect(mutex);
+
+ const auto u = UCharFromUTF8(s);
+ if (u.IsNull())
+ return nullptr;
+
+ ucnv_resetFromUnicode(converter);
+
+ // TODO: dynamic buffer?
+ char buffer[4096], *target = buffer;
+ const UChar *source = u.data;
+ UErrorCode code = U_ZERO_ERROR;
+
+ ucnv_fromUnicode(converter, &target, buffer + ARRAY_SIZE(buffer),
+ &source, u.end(),
+ nullptr, true, &code);
+ delete[] u.data;
+
+ if (code != U_ZERO_ERROR)
+ return nullptr;
+
+ return AllocatedString<>::Duplicate(buffer, target);
+
+#elif defined(HAVE_ICONV)
+ return DoConvert(from_utf8, s);
+#endif
+}
+
+#endif
diff --git a/src/lib/icu/Converter.hxx b/src/lib/icu/Converter.hxx
new file mode 100644
index 000000000..edb092d8f
--- /dev/null
+++ b/src/lib/icu/Converter.hxx
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ICU_CONVERTER_HXX
+#define MPD_ICU_CONVERTER_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#ifdef HAVE_ICU
+#include "thread/Mutex.hxx"
+#define HAVE_ICU_CONVERTER
+#elif defined(HAVE_ICONV)
+#include <iconv.h>
+#define HAVE_ICU_CONVERTER
+#endif
+
+#ifdef HAVE_ICU_CONVERTER
+
+class Error;
+
+#ifdef HAVE_ICU
+struct UConverter;
+#endif
+
+template<typename T> class AllocatedString;
+
+/**
+ * This class can convert strings with a certain character set to and
+ * from UTF-8.
+ */
+class IcuConverter {
+#ifdef HAVE_ICU
+ /**
+ * ICU's UConverter class is not thread-safe. This mutex
+ * serializes simultaneous calls.
+ */
+ mutable Mutex mutex;
+
+ UConverter *const converter;
+
+ IcuConverter(UConverter *_converter):converter(_converter) {}
+#elif defined(HAVE_ICONV)
+ const iconv_t to_utf8, from_utf8;
+
+ IcuConverter(iconv_t _to, iconv_t _from)
+ :to_utf8(_to), from_utf8(_from) {}
+#endif
+
+public:
+#ifdef HAVE_ICU
+ ~IcuConverter();
+#elif defined(HAVE_ICONV)
+ ~IcuConverter() {
+ iconv_close(to_utf8);
+ iconv_close(from_utf8);
+ }
+#endif
+
+ static IcuConverter *Create(const char *charset, Error &error);
+
+ /**
+ * Convert the string to UTF-8.
+ *
+ * Returns AllocatedString::Null() on error.
+ */
+ gcc_pure gcc_nonnull_all
+ AllocatedString<char> ToUTF8(const char *s) const;
+
+ /**
+ * Convert the string from UTF-8.
+ *
+ * Returns AllocatedString::Null() on error.
+ */
+ gcc_pure gcc_nonnull_all
+ AllocatedString<char> FromUTF8(const char *s) const;
+};
+
+#endif
+
+#endif
diff --git a/src/lib/icu/Error.cxx b/src/lib/icu/Error.cxx
index 1fef078ac..f49ede352 100644
--- a/src/lib/icu/Error.cxx
+++ b/src/lib/icu/Error.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Error.hxx b/src/lib/icu/Error.hxx
index e96667f57..37cdb12fe 100644
--- a/src/lib/icu/Error.hxx
+++ b/src/lib/icu/Error.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Init.cxx b/src/lib/icu/Init.cxx
index 1d0ad0777..6b70d60ee 100644
--- a/src/lib/icu/Init.cxx
+++ b/src/lib/icu/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Init.hxx b/src/lib/icu/Init.hxx
index 9f585e2bd..402e7b957 100644
--- a/src/lib/icu/Init.hxx
+++ b/src/lib/icu/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/icu/Util.cxx b/src/lib/icu/Util.cxx
new file mode 100644
index 000000000..92f1de5aa
--- /dev/null
+++ b/src/lib/icu/Util.cxx
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Util.hxx"
+#include "util/AllocatedString.hxx"
+#include "util/WritableBuffer.hxx"
+#include "util/ConstBuffer.hxx"
+
+#include <unicode/ustring.h>
+
+#include <assert.h>
+#include <string.h>
+
+WritableBuffer<UChar>
+UCharFromUTF8(const char *src)
+{
+ assert(src != nullptr);
+
+ const size_t src_length = strlen(src);
+ const size_t dest_capacity = src_length;
+ UChar *dest = new UChar[dest_capacity];
+
+ UErrorCode error_code = U_ZERO_ERROR;
+ int32_t dest_length;
+ u_strFromUTF8(dest, dest_capacity, &dest_length,
+ src, src_length,
+ &error_code);
+ if (U_FAILURE(error_code)) {
+ delete[] dest;
+ return nullptr;
+ }
+
+ return { dest, size_t(dest_length) };
+}
+
+AllocatedString<>
+UCharToUTF8(ConstBuffer<UChar> src)
+{
+ assert(!src.IsNull());
+
+ /* worst-case estimate */
+ size_t dest_capacity = 4 * src.size;
+
+ char *dest = new char[dest_capacity + 1];
+
+ UErrorCode error_code = U_ZERO_ERROR;
+ int32_t dest_length;
+ u_strToUTF8(dest, dest_capacity, &dest_length, src.data, src.size,
+ &error_code);
+ if (U_FAILURE(error_code)) {
+ delete[] dest;
+ return nullptr;
+ }
+
+ dest[dest_length] = 0;
+ return AllocatedString<>::Donate(dest);
+}
diff --git a/src/lib/icu/Util.hxx b/src/lib/icu/Util.hxx
new file mode 100644
index 000000000..f2d99d0e6
--- /dev/null
+++ b/src/lib/icu/Util.hxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ICU_UTIL_HXX
+#define MPD_ICU_UTIL_HXX
+
+#include "check.h"
+
+#include <unicode/utypes.h>
+
+template<typename T> struct WritableBuffer;
+template<typename T> struct ConstBuffer;
+template<typename T> class AllocatedString;
+
+/**
+ * Wrapper for u_strFromUTF8(). The returned pointer must be freed
+ * with delete[].
+ */
+WritableBuffer<UChar>
+UCharFromUTF8(const char *src);
+
+/**
+ * Wrapper for u_strToUTF8(). The returned pointer must be freed with
+ * delete[].
+ */
+AllocatedString<char>
+UCharToUTF8(ConstBuffer<UChar> src);
+
+#endif
diff --git a/src/lib/icu/Win32.cxx b/src/lib/icu/Win32.cxx
new file mode 100644
index 000000000..6f190c924
--- /dev/null
+++ b/src/lib/icu/Win32.cxx
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Win32.hxx"
+#include "util/AllocatedString.hxx"
+
+#include <windows.h>
+
+AllocatedString<char>
+WideCharToMultiByte(unsigned code_page, const wchar_t *src)
+{
+ int length = WideCharToMultiByte(code_page, 0, src, -1, nullptr, 0,
+ nullptr, nullptr);
+ if (length <= 0)
+ return nullptr;
+
+ char *buffer = new char[length];
+ length = WideCharToMultiByte(code_page, 0, src, -1, buffer, length,
+ nullptr, nullptr);
+ if (length <= 0) {
+ delete[] buffer;
+ return nullptr;
+ }
+
+ return AllocatedString<char>::Donate(buffer);
+}
+
+AllocatedString<wchar_t>
+MultiByteToWideChar(unsigned code_page, const char *src)
+{
+ int length = MultiByteToWideChar(code_page, 0, src, -1, nullptr, 0);
+ if (length <= 0)
+ return nullptr;
+
+ wchar_t *buffer = new wchar_t[length];
+ length = MultiByteToWideChar(code_page, 0, src, -1, buffer, length);
+ if (length <= 0) {
+ delete[] buffer;
+ return nullptr;
+ }
+
+ return AllocatedString<wchar_t>::Donate(buffer);
+}
diff --git a/src/lib/icu/Win32.hxx b/src/lib/icu/Win32.hxx
new file mode 100644
index 000000000..253fe169a
--- /dev/null
+++ b/src/lib/icu/Win32.hxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_ICU_WIN32_HXX
+#define MPD_ICU_WIN32_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#include <wchar.h>
+
+template<typename T> class AllocatedString;
+
+gcc_pure gcc_nonnull_all
+AllocatedString<char>
+WideCharToMultiByte(unsigned code_page, const wchar_t *src);
+
+gcc_pure gcc_nonnull_all
+AllocatedString<wchar_t>
+MultiByteToWideChar(unsigned code_page, const char *src);
+
+#endif
diff --git a/src/lib/nfs/Base.cxx b/src/lib/nfs/Base.cxx
index 3004cd11b..588176ef6 100644
--- a/src/lib/nfs/Base.cxx
+++ b/src/lib/nfs/Base.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Base.hxx b/src/lib/nfs/Base.hxx
index 3a92a86d3..e007bfbd2 100644
--- a/src/lib/nfs/Base.hxx
+++ b/src/lib/nfs/Base.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Blocking.cxx b/src/lib/nfs/Blocking.cxx
index 58eaf6af2..7bccfa532 100644
--- a/src/lib/nfs/Blocking.cxx
+++ b/src/lib/nfs/Blocking.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Blocking.hxx b/src/lib/nfs/Blocking.hxx
index eb16dfb8c..47721363c 100644
--- a/src/lib/nfs/Blocking.hxx
+++ b/src/lib/nfs/Blocking.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Callback.hxx b/src/lib/nfs/Callback.hxx
index ae82ecc3c..849fbfbb9 100644
--- a/src/lib/nfs/Callback.hxx
+++ b/src/lib/nfs/Callback.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Cancellable.hxx b/src/lib/nfs/Cancellable.hxx
index 151be0528..6c207d9b2 100644
--- a/src/lib/nfs/Cancellable.hxx
+++ b/src/lib/nfs/Cancellable.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Connection.cxx b/src/lib/nfs/Connection.cxx
index 6e9f77345..3b3358be0 100644
--- a/src/lib/nfs/Connection.cxx
+++ b/src/lib/nfs/Connection.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Connection.hxx b/src/lib/nfs/Connection.hxx
index 3969a7e8f..3402116b7 100644
--- a/src/lib/nfs/Connection.hxx
+++ b/src/lib/nfs/Connection.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Domain.cxx b/src/lib/nfs/Domain.cxx
index fefe0dbf3..af79e45a8 100644
--- a/src/lib/nfs/Domain.cxx
+++ b/src/lib/nfs/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Domain.hxx b/src/lib/nfs/Domain.hxx
index 6730b92e1..15856657f 100644
--- a/src/lib/nfs/Domain.hxx
+++ b/src/lib/nfs/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/FileReader.cxx b/src/lib/nfs/FileReader.cxx
index 1b80f2c86..97522321b 100644
--- a/src/lib/nfs/FileReader.cxx
+++ b/src/lib/nfs/FileReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/FileReader.hxx b/src/lib/nfs/FileReader.hxx
index 1495a2832..5e3b5221f 100644
--- a/src/lib/nfs/FileReader.hxx
+++ b/src/lib/nfs/FileReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Glue.cxx b/src/lib/nfs/Glue.cxx
index 6e1e0f99b..fa894f59a 100644
--- a/src/lib/nfs/Glue.cxx
+++ b/src/lib/nfs/Glue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Glue.hxx b/src/lib/nfs/Glue.hxx
index 6da8957cb..d661b3fe0 100644
--- a/src/lib/nfs/Glue.hxx
+++ b/src/lib/nfs/Glue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Lease.hxx b/src/lib/nfs/Lease.hxx
index 6f88acf53..3276cfc31 100644
--- a/src/lib/nfs/Lease.hxx
+++ b/src/lib/nfs/Lease.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx
index 6d50cce18..1cbf18ff1 100644
--- a/src/lib/nfs/Manager.cxx
+++ b/src/lib/nfs/Manager.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "Manager.hxx"
#include "event/Loop.hxx"
#include "Log.hxx"
+#include "util/DeleteDisposer.hxx"
#include <string.h>
@@ -65,9 +66,7 @@ NfsManager::~NfsManager()
CollectGarbage();
- connections.clear_and_dispose([](ManagedConnection *c){
- delete c;
- });
+ connections.clear_and_dispose(DeleteDisposer());
}
NfsConnection &
@@ -95,9 +94,7 @@ NfsManager::CollectGarbage()
{
assert(GetEventLoop().IsInside());
- garbage.clear_and_dispose([](ManagedConnection *c){
- delete c;
- });
+ garbage.clear_and_dispose(DeleteDisposer());
}
void
diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx
index 130c81aca..1eb01590a 100644
--- a/src/lib/nfs/Manager.hxx
+++ b/src/lib/nfs/Manager.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/pulse/Domain.cxx b/src/lib/pulse/Domain.cxx
new file mode 100644
index 000000000..ac4821cae
--- /dev/null
+++ b/src/lib/pulse/Domain.cxx
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Domain.hxx"
+#include "util/Domain.hxx"
+
+const Domain pulse_domain("pulse");
diff --git a/src/tag/TagSettings.h b/src/lib/pulse/Domain.hxx
index 33f89d4be..bacf8b7eb 100644
--- a/src/tag/TagSettings.h
+++ b/src/lib/pulse/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,13 +17,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef MPD_TAG_SETTINGS_H
-#define MPD_TAG_SETTINGS_H
+#ifndef MPD_PULSE_DOMAIN_HXX
+#define MPD_PULSE_DOMAIN_HXX
-#include "TagType.h"
+class Domain;
-#include <stdbool.h>
-
-extern bool ignore_tag_items[TAG_NUM_OF_ITEM_TYPES];
+extern const Domain pulse_domain;
#endif
diff --git a/src/lib/pulse/Error.cxx b/src/lib/pulse/Error.cxx
new file mode 100644
index 000000000..60ca0198a
--- /dev/null
+++ b/src/lib/pulse/Error.cxx
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Error.hxx"
+#include "Domain.hxx"
+#include "util/Error.hxx"
+
+#include <pulse/context.h>
+#include <pulse/error.h>
+
+void
+SetPulseError(Error &error, pa_context *context, const char *prefix)
+{
+ const int e = pa_context_errno(context);
+ error.Format(pulse_domain, e, "%s: %s", prefix, pa_strerror(e));
+}
diff --git a/src/lib/pulse/Error.hxx b/src/lib/pulse/Error.hxx
new file mode 100644
index 000000000..c9225a7c2
--- /dev/null
+++ b/src/lib/pulse/Error.hxx
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PULSE_ERROR_HXX
+#define MPD_PULSE_ERROR_HXX
+
+class Error;
+struct pa_context;
+
+void
+SetPulseError(Error &error, pa_context *context, const char *prefix);
+
+#endif
diff --git a/src/lib/pulse/LogError.cxx b/src/lib/pulse/LogError.cxx
new file mode 100644
index 000000000..a322e7e75
--- /dev/null
+++ b/src/lib/pulse/LogError.cxx
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "LogError.hxx"
+#include "Domain.hxx"
+#include "Log.hxx"
+
+#include <pulse/context.h>
+#include <pulse/error.h>
+
+void
+LogPulseError(pa_context *context, const char *prefix)
+{
+ const int e = pa_context_errno(context);
+ FormatError(pulse_domain, "%s: %s", prefix, pa_strerror(e));
+}
diff --git a/src/lib/pulse/LogError.hxx b/src/lib/pulse/LogError.hxx
new file mode 100644
index 000000000..2e0859366
--- /dev/null
+++ b/src/lib/pulse/LogError.hxx
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PULSE_LOG_ERROR_HXX
+#define MPD_PULSE_LOG_ERROR_HXX
+
+struct pa_context;
+
+void
+LogPulseError(pa_context *context, const char *prefix);
+
+#endif
diff --git a/src/lib/smbclient/Domain.cxx b/src/lib/smbclient/Domain.cxx
index 00f5ee6c1..c6f6b143d 100644
--- a/src/lib/smbclient/Domain.cxx
+++ b/src/lib/smbclient/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/smbclient/Domain.hxx b/src/lib/smbclient/Domain.hxx
index 3b21c4e60..dc9812fed 100644
--- a/src/lib/smbclient/Domain.hxx
+++ b/src/lib/smbclient/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/smbclient/Init.cxx b/src/lib/smbclient/Init.cxx
index a7f2da4dd..999e60fcd 100644
--- a/src/lib/smbclient/Init.cxx
+++ b/src/lib/smbclient/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/smbclient/Init.hxx b/src/lib/smbclient/Init.hxx
index 21014ec8d..1ccaec033 100644
--- a/src/lib/smbclient/Init.hxx
+++ b/src/lib/smbclient/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/smbclient/Mutex.cxx b/src/lib/smbclient/Mutex.cxx
index 4dfc5a9d3..fd78e9948 100644
--- a/src/lib/smbclient/Mutex.cxx
+++ b/src/lib/smbclient/Mutex.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/smbclient/Mutex.hxx b/src/lib/smbclient/Mutex.hxx
index dc7372e6e..893f6204d 100644
--- a/src/lib/smbclient/Mutex.hxx
+++ b/src/lib/smbclient/Mutex.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/sqlite/Domain.cxx b/src/lib/sqlite/Domain.cxx
new file mode 100644
index 000000000..4f6fe4c45
--- /dev/null
+++ b/src/lib/sqlite/Domain.cxx
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Domain.hxx"
+#include "util/Domain.hxx"
+
+const Domain sqlite_domain("sqlite");
diff --git a/src/lib/sqlite/Domain.hxx b/src/lib/sqlite/Domain.hxx
new file mode 100644
index 000000000..0b9965025
--- /dev/null
+++ b/src/lib/sqlite/Domain.hxx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_SQLITE_DOMAIN_HXX
+#define MPD_SQLITE_DOMAIN_HXX
+
+class Domain;
+
+extern const Domain sqlite_domain;
+
+#endif
diff --git a/src/lib/sqlite/Util.hxx b/src/lib/sqlite/Util.hxx
new file mode 100644
index 000000000..151eac6c2
--- /dev/null
+++ b/src/lib/sqlite/Util.hxx
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_SQLITE_UTIL_HXX
+#define MPD_SQLITE_UTIL_HXX
+
+#include "Domain.hxx"
+#include "util/Error.hxx"
+
+#include <sqlite3.h>
+
+#include <assert.h>
+
+static void
+SetError(Error &error, sqlite3 *db, int code, const char *msg)
+{
+ error.Format(sqlite_domain, code, "%s: %s",
+ msg, sqlite3_errmsg(db));
+}
+
+static void
+SetError(Error &error, sqlite3_stmt *stmt, int code, const char *msg)
+{
+ SetError(error, sqlite3_db_handle(stmt), code, msg);
+}
+
+static bool
+Bind(sqlite3_stmt *stmt, unsigned i, const char *value, Error &error)
+{
+ int result = sqlite3_bind_text(stmt, i, value, -1, nullptr);
+ if (result != SQLITE_OK) {
+ SetError(error, stmt, result, "sqlite3_bind_text() failed");
+ return false;
+ }
+
+ return true;
+}
+
+template<typename... Args>
+static bool
+BindAll2(gcc_unused Error &error, gcc_unused sqlite3_stmt *stmt,
+ gcc_unused unsigned i)
+{
+ assert(int(i - 1) == sqlite3_bind_parameter_count(stmt));
+
+ return true;
+}
+
+template<typename... Args>
+static bool
+BindAll2(Error &error, sqlite3_stmt *stmt, unsigned i,
+ const char *value, Args&&... args)
+{
+ return Bind(stmt, i, value, error) &&
+ BindAll2(error, stmt, i + 1, std::forward<Args>(args)...);
+}
+
+template<typename... Args>
+static bool
+BindAll(Error &error, sqlite3_stmt *stmt, Args&&... args)
+{
+ assert(int(sizeof...(args)) == sqlite3_bind_parameter_count(stmt));
+
+ return BindAll2(error, stmt, 1, std::forward<Args>(args)...);
+}
+
+/**
+ * Wrapper for BindAll() that returns the specified sqlite3_stmt* on
+ * success and nullptr on error.
+ */
+template<typename... Args>
+static sqlite3_stmt *
+BindAllOrNull(Error &error, sqlite3_stmt *stmt, Args&&... args)
+{
+ return BindAll(error, stmt, std::forward<Args>(args)...)
+ ? stmt
+ : nullptr;
+}
+
+/**
+ * Call sqlite3_stmt() repepatedly until something other than
+ * SQLITE_BUSY is returned.
+ */
+static int
+ExecuteBusy(sqlite3_stmt *stmt)
+{
+ int result;
+ do {
+ result = sqlite3_step(stmt);
+ } while (result == SQLITE_BUSY);
+
+ return result;
+}
+
+/**
+ * Wrapper for ExecuteBusy() that returns true on SQLITE_ROW.
+ */
+static bool
+ExecuteRow(sqlite3_stmt *stmt, Error &error)
+{
+ int result = ExecuteBusy(stmt);
+ if (result == SQLITE_ROW)
+ return true;
+
+ if (result != SQLITE_DONE)
+ SetError(error, stmt, result, "sqlite3_step() failed");
+
+ return false;
+}
+
+/**
+ * Wrapper for ExecuteBusy() that interprets everything other than
+ * SQLITE_DONE as error.
+ */
+static bool
+ExecuteCommand(sqlite3_stmt *stmt, Error &error)
+{
+ int result = ExecuteBusy(stmt);
+ if (result != SQLITE_DONE) {
+ SetError(error, stmt, result, "sqlite3_step() failed");
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Wrapper for ExecuteCommand() that returns the number of rows
+ * modified via sqlite3_changes(). Returns -1 on error.
+ */
+static inline int
+ExecuteChanges(sqlite3_stmt *stmt, Error &error)
+{
+ if (!ExecuteCommand(stmt, error))
+ return -1;
+
+ return sqlite3_changes(sqlite3_db_handle(stmt));
+}
+
+/**
+ * Wrapper for ExecuteChanges() that returns true if at least one row
+ * was modified. Returns false if nothing was modified or if an error
+ * occurred.
+ */
+static inline bool
+ExecuteModified(sqlite3_stmt *stmt, Error &error)
+{
+ return ExecuteChanges(stmt, error) > 0;
+}
+
+template<typename F>
+static inline bool
+ExecuteForEach(sqlite3_stmt *stmt, Error &error, F &&f)
+{
+ while (true) {
+ int result = ExecuteBusy(stmt);
+ switch (result) {
+ case SQLITE_ROW:
+ f();
+ break;
+
+ case SQLITE_DONE:
+ return true;
+
+ default:
+ SetError(error, stmt, result, "sqlite3_step() failed");
+ return false;
+ }
+ }
+}
+
+#endif
diff --git a/src/lib/upnp/Action.hxx b/src/lib/upnp/Action.hxx
index 28c88be92..bad398e1a 100644
--- a/src/lib/upnp/Action.hxx
+++ b/src/lib/upnp/Action.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Callback.hxx b/src/lib/upnp/Callback.hxx
index 85daf0a7e..4d86c0b53 100644
--- a/src/lib/upnp/Callback.hxx
+++ b/src/lib/upnp/Callback.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/ClientInit.cxx b/src/lib/upnp/ClientInit.cxx
index 77d9cf03d..50fcbdb16 100644
--- a/src/lib/upnp/ClientInit.cxx
+++ b/src/lib/upnp/ClientInit.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/ClientInit.hxx b/src/lib/upnp/ClientInit.hxx
index 645e64ca6..f49f255ee 100644
--- a/src/lib/upnp/ClientInit.hxx
+++ b/src/lib/upnp/ClientInit.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/ContentDirectoryService.cxx b/src/lib/upnp/ContentDirectoryService.cxx
index 0e5d2d955..0636505ab 100644
--- a/src/lib/upnp/ContentDirectoryService.cxx
+++ b/src/lib/upnp/ContentDirectoryService.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/ContentDirectoryService.hxx b/src/lib/upnp/ContentDirectoryService.hxx
index 0b03df2e7..bf6ab913a 100644
--- a/src/lib/upnp/ContentDirectoryService.hxx
+++ b/src/lib/upnp/ContentDirectoryService.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -62,7 +62,8 @@ public:
/**
* Construct by copying data from device and service objects.
*
- * The discovery service does this: use getDirServices()
+ * The discovery service does this: use
+ * UPnPDeviceDirectory::GetDirectories()
*/
ContentDirectoryService(const UPnPDevice &device,
const UPnPService &service);
diff --git a/src/lib/upnp/Device.cxx b/src/lib/upnp/Device.cxx
index 26bffd0f0..402a39166 100644
--- a/src/lib/upnp/Device.cxx
+++ b/src/lib/upnp/Device.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Device.hxx b/src/lib/upnp/Device.hxx
index dd7ecac2d..cdb065434 100644
--- a/src/lib/upnp/Device.hxx
+++ b/src/lib/upnp/Device.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Discovery.cxx b/src/lib/upnp/Discovery.cxx
index 1539e1512..f6a3ba122 100644
--- a/src/lib/upnp/Discovery.cxx
+++ b/src/lib/upnp/Discovery.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -107,12 +107,12 @@ UPnPDeviceDirectory::LockRemove(const std::string &id)
}
inline void
-UPnPDeviceDirectory::discoExplorer()
+UPnPDeviceDirectory::Explore()
{
for (;;) {
DiscoveredTask *tsk = 0;
- if (!discoveredQueue.take(tsk)) {
- discoveredQueue.workerExit();
+ if (!queue.take(tsk)) {
+ queue.workerExit();
return;
}
@@ -128,7 +128,7 @@ UPnPDeviceDirectory::discoExplorer()
}
// Update or insert the device
- ContentDirectoryDescriptor d(std::move(tsk->deviceId),
+ ContentDirectoryDescriptor d(std::move(tsk->device_id),
MonotonicClockS(), tsk->expires);
{
@@ -148,10 +148,10 @@ UPnPDeviceDirectory::discoExplorer()
}
void *
-UPnPDeviceDirectory::discoExplorer(void *ctx)
+UPnPDeviceDirectory::Explore(void *ctx)
{
UPnPDeviceDirectory &directory = *(UPnPDeviceDirectory *)ctx;
- directory.discoExplorer();
+ directory.Explore();
return (void*)1;
}
@@ -161,7 +161,7 @@ UPnPDeviceDirectory::OnAlive(Upnp_Discovery *disco)
if (isMSDevice(disco->DeviceType) ||
isCDService(disco->ServiceType)) {
DiscoveredTask *tp = new DiscoveredTask(disco);
- if (discoveredQueue.put(tp))
+ if (queue.put(tp))
return UPNP_E_FINISH;
}
@@ -210,9 +210,8 @@ UPnPDeviceDirectory::Invoke(Upnp_EventType et, void *evp)
}
bool
-UPnPDeviceDirectory::expireDevices(Error &error)
+UPnPDeviceDirectory::ExpireDevices(Error &error)
{
- const ScopeLock protect(mutex);
const unsigned now = MonotonicClockS();
bool didsomething = false;
@@ -227,7 +226,7 @@ UPnPDeviceDirectory::expireDevices(Error &error)
}
if (didsomething)
- return search(error);
+ return Search(error);
return true;
}
@@ -236,8 +235,8 @@ UPnPDeviceDirectory::UPnPDeviceDirectory(UpnpClient_Handle _handle,
UPnPDiscoveryListener *_listener)
:handle(_handle),
listener(_listener),
- discoveredQueue("DiscoveredQueue"),
- m_searchTimeout(2), m_lastSearch(0)
+ queue("DiscoveredQueue"),
+ search_timeout(2), last_search(0)
{
}
@@ -249,24 +248,24 @@ UPnPDeviceDirectory::~UPnPDeviceDirectory()
bool
UPnPDeviceDirectory::Start(Error &error)
{
- if (!discoveredQueue.start(1, discoExplorer, this)) {
+ if (!queue.start(1, Explore, this)) {
error.Set(upnp_domain, "Discover work queue start failed");
return false;
}
- return search(error);
+ return Search(error);
}
bool
-UPnPDeviceDirectory::search(Error &error)
+UPnPDeviceDirectory::Search(Error &error)
{
const unsigned now = MonotonicClockS();
- if (now - m_lastSearch < 10)
+ if (now - last_search < 10)
return true;
- m_lastSearch = now;
+ last_search = now;
// We search both for device and service just in case.
- int code = UpnpSearchAsync(handle, m_searchTimeout,
+ int code = UpnpSearchAsync(handle, search_timeout,
ContentDirectorySType, GetUpnpCookie());
if (code != UPNP_E_SUCCESS) {
error.Format(upnp_domain, code,
@@ -275,7 +274,7 @@ UPnPDeviceDirectory::search(Error &error)
return false;
}
- code = UpnpSearchAsync(handle, m_searchTimeout,
+ code = UpnpSearchAsync(handle, search_timeout,
MediaServerDType, GetUpnpCookie());
if (code != UPNP_E_SUCCESS) {
error.Format(upnp_domain, code,
@@ -288,15 +287,14 @@ UPnPDeviceDirectory::search(Error &error)
}
bool
-UPnPDeviceDirectory::getDirServices(std::vector<ContentDirectoryService> &out,
+UPnPDeviceDirectory::GetDirectories(std::vector<ContentDirectoryService> &out,
Error &error)
{
- // Has locking, do it before our own lock
- if (!expireDevices(error))
- return false;
-
const ScopeLock protect(mutex);
+ if (!ExpireDevices(error))
+ return false;
+
for (auto dit = directories.begin();
dit != directories.end(); dit++) {
for (const auto &service : dit->device.services) {
@@ -310,20 +308,19 @@ UPnPDeviceDirectory::getDirServices(std::vector<ContentDirectoryService> &out,
}
bool
-UPnPDeviceDirectory::getServer(const char *friendlyName,
+UPnPDeviceDirectory::GetServer(const char *friendly_name,
ContentDirectoryService &server,
Error &error)
{
- // Has locking, do it before our own lock
- if (!expireDevices(error))
- return false;
-
const ScopeLock protect(mutex);
+ if (!ExpireDevices(error))
+ return false;
+
for (const auto &i : directories) {
const auto &device = i.device;
- if (device.friendlyName != friendlyName)
+ if (device.friendlyName != friendly_name)
continue;
for (const auto &service : device.services) {
diff --git a/src/lib/upnp/Discovery.hxx b/src/lib/upnp/Discovery.hxx
index 767811840..1cf82b77e 100644
--- a/src/lib/upnp/Discovery.hxx
+++ b/src/lib/upnp/Discovery.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -55,13 +55,13 @@ class UPnPDeviceDirectory final : UpnpCallback {
*/
struct DiscoveredTask {
std::string url;
- std::string deviceId;
+ std::string device_id;
unsigned expires; // Seconds valid
DiscoveredTask(const Upnp_Discovery *disco)
:url(disco->Location),
- deviceId(disco->DeviceId),
- expires(disco->Expires) {}
+ device_id(disco->DeviceId),
+ expires(disco->Expires) {}
};
/**
@@ -97,19 +97,19 @@ class UPnPDeviceDirectory final : UpnpCallback {
Mutex mutex;
std::list<ContentDirectoryDescriptor> directories;
- WorkQueue<DiscoveredTask *> discoveredQueue;
+ WorkQueue<DiscoveredTask *> queue;
/**
* The UPnP device search timeout, which should actually be
* called delay because it's the base of a random delay that
* the devices apply to avoid responding all at the same time.
*/
- int m_searchTimeout;
+ int search_timeout;
/**
* The MonotonicClockS() time stamp of the last search.
*/
- unsigned m_lastSearch;
+ unsigned last_search;
public:
UPnPDeviceDirectory(UpnpClient_Handle _handle,
@@ -122,24 +122,26 @@ public:
bool Start(Error &error);
/** Retrieve the directory services currently seen on the network */
- bool getDirServices(std::vector<ContentDirectoryService> &, Error &);
+ bool GetDirectories(std::vector<ContentDirectoryService> &, Error &);
/**
* Get server by friendly name.
*/
- bool getServer(const char *friendlyName,
+ bool GetServer(const char *friendly_name,
ContentDirectoryService &server,
Error &error);
private:
- bool search(Error &error);
+ bool Search(Error &error);
/**
* Look at the devices and get rid of those which have not
* been seen for too long. We do this when listing the top
* directory.
+ *
+ * Caller must lock #mutex.
*/
- bool expireDevices(Error &error);
+ bool ExpireDevices(Error &error);
void LockAdd(ContentDirectoryDescriptor &&d);
void LockRemove(const std::string &id);
@@ -149,12 +151,11 @@ private:
* devices appearing and disappearing, and update the
* directory pool accordingly.
*/
- static void *discoExplorer(void *);
- void discoExplorer();
+ static void *Explore(void *);
+ void Explore();
int OnAlive(Upnp_Discovery *disco);
int OnByeBye(Upnp_Discovery *disco);
- int cluCallBack(Upnp_EventType et, void *evp);
/* virtual methods from class UpnpCallback */
virtual int Invoke(Upnp_EventType et, void *evp) override;
diff --git a/src/lib/upnp/Domain.cxx b/src/lib/upnp/Domain.cxx
index 010d4c7c2..d7700a067 100644
--- a/src/lib/upnp/Domain.cxx
+++ b/src/lib/upnp/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Domain.hxx b/src/lib/upnp/Domain.hxx
index ec01ef735..ff0cd9b85 100644
--- a/src/lib/upnp/Domain.hxx
+++ b/src/lib/upnp/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Init.cxx b/src/lib/upnp/Init.cxx
index 4fc606de9..1b471f53d 100644
--- a/src/lib/upnp/Init.cxx
+++ b/src/lib/upnp/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Init.hxx b/src/lib/upnp/Init.hxx
index b23f8e2ab..796251862 100644
--- a/src/lib/upnp/Init.hxx
+++ b/src/lib/upnp/Init.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Util.cxx b/src/lib/upnp/Util.cxx
index 79cfb111c..912d993b4 100644
--- a/src/lib/upnp/Util.cxx
+++ b/src/lib/upnp/Util.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/Util.hxx b/src/lib/upnp/Util.hxx
index a59f23521..d3b0b049f 100644
--- a/src/lib/upnp/Util.hxx
+++ b/src/lib/upnp/Util.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/upnp/WorkQueue.hxx b/src/lib/upnp/WorkQueue.hxx
index fe8ce53f9..cd6b1161d 100644
--- a/src/lib/upnp/WorkQueue.hxx
+++ b/src/lib/upnp/WorkQueue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -66,10 +66,7 @@ class WorkQueue {
public:
/** Create a WorkQueue
- * @param name for message printing
- * @param hi number of tasks on queue before clients blocks. Default 0
- * meaning no limit. hi == -1 means that the queue is disabled.
- * @param lo minimum count of tasks before worker starts. Default 1.
+ * @param _name for message printing
*/
WorkQueue(const char *_name)
:name(_name),
@@ -86,7 +83,7 @@ public:
/** Start the worker threads.
*
* @param nworkers number of threads copies to start.
- * @param start_routine thread function. It should loop
+ * @param workproc thread function. It should loop
* taking (QueueWorker::take()) and executing tasks.
* @param arg initial parameter to thread function.
* @return true if ok.
diff --git a/src/lib/zlib/Domain.cxx b/src/lib/zlib/Domain.cxx
index 96aad1350..b94076053 100644
--- a/src/lib/zlib/Domain.cxx
+++ b/src/lib/zlib/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/lib/zlib/Domain.hxx b/src/lib/zlib/Domain.hxx
index 653ac0209..9f0b9c5b0 100644
--- a/src/lib/zlib/Domain.hxx
+++ b/src/lib/zlib/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/ls.cxx b/src/ls.cxx
index 6ab68b6ab..41bd4ba97 100644
--- a/src/ls.cxx
+++ b/src/ls.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,9 @@
#include "config.h"
#include "ls.hxx"
+#include "client/Response.hxx"
#include "util/StringUtil.hxx"
#include "util/UriUtil.hxx"
-#include "client/Client.hxx"
#include <assert.h>
@@ -30,7 +30,7 @@
* is detected at runtime and displayed as a urlhandler if the client is
* connected by IPC socket.
*/
-static const char *remoteUrlPrefixes[] = {
+static const char *const remoteUrlPrefixes[] = {
#if defined(ENABLE_CURL)
"http://",
"https://",
@@ -41,7 +41,7 @@ static const char *remoteUrlPrefixes[] = {
"mmst://",
"mmsu://",
#endif
-#ifdef HAVE_FFMPEG
+#ifdef ENABLE_FFMPEG
"gopher://",
"rtp://",
"rtsp://",
@@ -58,7 +58,7 @@ static const char *remoteUrlPrefixes[] = {
#ifdef ENABLE_CDIO_PARANOIA
"cdda://",
#endif
-#ifdef HAVE_ALSA
+#ifdef ENABLE_ALSA
"alsa://",
#endif
NULL
@@ -66,7 +66,7 @@ static const char *remoteUrlPrefixes[] = {
void print_supported_uri_schemes_to_fp(FILE *fp)
{
- const char **prefixes = remoteUrlPrefixes;
+ const char *const*prefixes = remoteUrlPrefixes;
#ifdef HAVE_UN
fprintf(fp, " file://");
@@ -78,19 +78,20 @@ void print_supported_uri_schemes_to_fp(FILE *fp)
fprintf(fp,"\n");
}
-void print_supported_uri_schemes(Client &client)
+void
+print_supported_uri_schemes(Response &r)
{
- const char **prefixes = remoteUrlPrefixes;
+ const char *const *prefixes = remoteUrlPrefixes;
while (*prefixes) {
- client_printf(client, "handler: %s\n", *prefixes);
+ r.Format("handler: %s\n", *prefixes);
prefixes++;
}
}
bool uri_supported_scheme(const char *uri)
{
- const char **urlPrefixes = remoteUrlPrefixes;
+ const char *const*urlPrefixes = remoteUrlPrefixes;
assert(uri_has_scheme(uri));
diff --git a/src/ls.hxx b/src/ls.hxx
index f4b9be967..f34e3c6ab 100644
--- a/src/ls.hxx
+++ b/src/ls.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include <stdio.h>
-class Client;
+class Response;
/**
* Checks whether the scheme of the specified URI is supported by MPD.
@@ -38,7 +38,7 @@ bool uri_supported_scheme(const char *url);
* Send a list of supported URI schemes to the client. This is the
* response to the "urlhandlers" command.
*/
-void print_supported_uri_schemes(Client &client);
+void print_supported_uri_schemes(Response &r);
/**
* Send a list of supported URI schemes to a file pointer.
diff --git a/src/mixer/Listener.hxx b/src/mixer/Listener.hxx
index 6f48fbd4d..c65934dd8 100644
--- a/src/mixer/Listener.hxx
+++ b/src/mixer/Listener.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/MixerAll.cxx b/src/mixer/MixerAll.cxx
index 91891e870..835cf4eec 100644
--- a/src/mixer/MixerAll.cxx
+++ b/src/mixer/MixerAll.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -146,7 +146,8 @@ MultipleOutputs::SetSoftwareVolume(unsigned volume)
const auto mixer = ao->mixer;
if (mixer != nullptr &&
- &mixer->plugin == &software_mixer_plugin)
+ (&mixer->plugin == &software_mixer_plugin ||
+ &mixer->plugin == &null_mixer_plugin))
mixer_set_volume(mixer, volume, IgnoreError());
}
}
diff --git a/src/mixer/MixerControl.cxx b/src/mixer/MixerControl.cxx
index 6d08140db..9de7809ec 100644
--- a/src/mixer/MixerControl.cxx
+++ b/src/mixer/MixerControl.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,10 @@ Mixer *
mixer_new(EventLoop &event_loop,
const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error)
{
- Mixer *mixer = plugin.init(event_loop, ao, listener, param, error);
+ Mixer *mixer = plugin.init(event_loop, ao, listener, block, error);
assert(mixer == nullptr || mixer->IsPlugin(plugin));
diff --git a/src/mixer/MixerControl.hxx b/src/mixer/MixerControl.hxx
index 75255d98c..700c720ba 100644
--- a/src/mixer/MixerControl.hxx
+++ b/src/mixer/MixerControl.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
/** \file
*
- * Functions which manipulate a #mixer object.
+ * Functions which manipulate a #Mixer object.
*/
#ifndef MPD_MIXER_CONTROL_HXX
@@ -31,12 +31,12 @@ class EventLoop;
struct AudioOutput;
struct MixerPlugin;
class MixerListener;
-struct config_param;
+struct ConfigBlock;
Mixer *
mixer_new(EventLoop &event_loop, const MixerPlugin &plugin, AudioOutput &ao,
MixerListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
void
diff --git a/src/mixer/MixerInternal.hxx b/src/mixer/MixerInternal.hxx
index 7b2cf2b32..02e06d85d 100644
--- a/src/mixer/MixerInternal.hxx
+++ b/src/mixer/MixerInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/MixerList.hxx b/src/mixer/MixerList.hxx
index e75b2e6ff..f2aa2e61c 100644
--- a/src/mixer/MixerList.hxx
+++ b/src/mixer/MixerList.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,8 +27,10 @@
struct MixerPlugin;
+extern const MixerPlugin null_mixer_plugin;
extern const MixerPlugin software_mixer_plugin;
extern const MixerPlugin alsa_mixer_plugin;
+extern const MixerPlugin haiku_mixer_plugin;
extern const MixerPlugin oss_mixer_plugin;
extern const MixerPlugin roar_mixer_plugin;
extern const MixerPlugin pulse_mixer_plugin;
diff --git a/src/mixer/MixerPlugin.hxx b/src/mixer/MixerPlugin.hxx
index 02bae844e..a40b4bb95 100644
--- a/src/mixer/MixerPlugin.hxx
+++ b/src/mixer/MixerPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#ifndef MPD_MIXER_PLUGIN_HXX
#define MPD_MIXER_PLUGIN_HXX
-struct config_param;
+struct ConfigBlock;
struct AudioOutput;
class Mixer;
class MixerListener;
@@ -46,7 +46,7 @@ struct MixerPlugin {
*/
Mixer *(*init)(EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
/**
diff --git a/src/mixer/MixerType.cxx b/src/mixer/MixerType.cxx
index cd45db0d9..23ca3f08a 100644
--- a/src/mixer/MixerType.cxx
+++ b/src/mixer/MixerType.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,17 +23,19 @@
#include <assert.h>
#include <string.h>
-enum mixer_type
+MixerType
mixer_type_parse(const char *input)
{
assert(input != NULL);
if (strcmp(input, "none") == 0 || strcmp(input, "disabled") == 0)
- return MIXER_TYPE_NONE;
+ return MixerType::NONE;
else if (strcmp(input, "hardware") == 0)
- return MIXER_TYPE_HARDWARE;
+ return MixerType::HARDWARE;
else if (strcmp(input, "software") == 0)
- return MIXER_TYPE_SOFTWARE;
+ return MixerType::SOFTWARE;
+ else if (strcmp(input, "null") == 0)
+ return MixerType::NULL_;
else
- return MIXER_TYPE_UNKNOWN;
+ return MixerType::UNKNOWN;
}
diff --git a/src/mixer/MixerType.hxx b/src/mixer/MixerType.hxx
index bfa2637b7..86037787f 100644
--- a/src/mixer/MixerType.hxx
+++ b/src/mixer/MixerType.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,28 +20,31 @@
#ifndef MPD_MIXER_TYPE_HXX
#define MPD_MIXER_TYPE_HXX
-enum mixer_type {
+enum class MixerType {
/** parser error */
- MIXER_TYPE_UNKNOWN,
+ UNKNOWN,
/** mixer disabled */
- MIXER_TYPE_NONE,
+ NONE,
+
+ /** "null" mixer (virtual fake) */
+ NULL_,
/** software mixer with pcm_volume() */
- MIXER_TYPE_SOFTWARE,
+ SOFTWARE,
/** hardware mixer (output's plugin) */
- MIXER_TYPE_HARDWARE,
+ HARDWARE,
};
/**
- * Parses a "mixer_type" setting from the configuration file.
+ * Parses a #MixerType setting from the configuration file.
*
- * @param input the configured string value; must not be NULL
- * @return a #mixer_type value; MIXER_TYPE_UNKNOWN means #input could
- * not be parsed
+ * @param input the configured string value; must not be NULL @return
+ * a #MixerType value; #MixerType::UNKNOWN means #input could not be
+ * parsed
*/
-enum mixer_type
+MixerType
mixer_type_parse(const char *input);
#endif
diff --git a/src/mixer/Volume.cxx b/src/mixer/Volume.cxx
index abb01fb40..8bc8d879d 100644
--- a/src/mixer/Volume.cxx
+++ b/src/mixer/Volume.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/Volume.hxx b/src/mixer/Volume.hxx
index d787a6415..8c693bfc7 100644
--- a/src/mixer/Volume.hxx
+++ b/src/mixer/Volume.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -49,6 +49,6 @@ save_sw_volume_state(BufferedOutputStream &os);
*/
gcc_pure
unsigned
-sw_volume_state_get_hash(void);
+sw_volume_state_get_hash();
#endif
diff --git a/src/mixer/plugins/AlsaMixerPlugin.cxx b/src/mixer/plugins/AlsaMixerPlugin.cxx
index cd787182a..2b89f24e1 100644
--- a/src/mixer/plugins/AlsaMixerPlugin.cxx
+++ b/src/mixer/plugins/AlsaMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -82,7 +82,7 @@ public:
virtual ~AlsaMixer();
- void Configure(const config_param &param);
+ void Configure(const ConfigBlock &block);
bool Setup(Error &error);
/* virtual methods from class Mixer */
@@ -162,24 +162,24 @@ alsa_mixer_elem_callback(snd_mixer_elem_t *elem, unsigned mask)
*/
inline void
-AlsaMixer::Configure(const config_param &param)
+AlsaMixer::Configure(const ConfigBlock &block)
{
- device = param.GetBlockValue("mixer_device",
+ device = block.GetBlockValue("mixer_device",
VOLUME_MIXER_ALSA_DEFAULT);
- control = param.GetBlockValue("mixer_control",
+ control = block.GetBlockValue("mixer_control",
VOLUME_MIXER_ALSA_CONTROL_DEFAULT);
- index = param.GetBlockValue("mixer_index",
+ index = block.GetBlockValue("mixer_index",
VOLUME_MIXER_ALSA_INDEX_DEFAULT);
}
static Mixer *
alsa_mixer_init(EventLoop &event_loop, gcc_unused AudioOutput &ao,
MixerListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
gcc_unused Error &error)
{
AlsaMixer *am = new AlsaMixer(event_loop, listener);
- am->Configure(param);
+ am->Configure(block);
return am;
}
diff --git a/src/mixer/plugins/HaikuMixerPlugin.cxx b/src/mixer/plugins/HaikuMixerPlugin.cxx
new file mode 100644
index 000000000..d6dfb663d
--- /dev/null
+++ b/src/mixer/plugins/HaikuMixerPlugin.cxx
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
+ * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
+ * Copyright (C) 2014-2015 François 'mmu_man' Revol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "config.h"
+#include "mixer/MixerInternal.hxx"
+#include "output/plugins/HaikuOutputPlugin.hxx"
+#include "Compiler.h"
+
+class HaikuMixer final : public Mixer {
+ /** the base mixer class */
+ HaikuOutput &self;
+
+public:
+ HaikuMixer(HaikuOutput &_output, MixerListener &_listener)
+ :Mixer(haiku_mixer_plugin, _listener),
+ self(_output) {}
+
+ /* virtual methods from class Mixer */
+ virtual bool Open(gcc_unused Error &error) override {
+ return true;
+ }
+
+ virtual void Close() override {
+ }
+
+ virtual int GetVolume(Error &error) override;
+ virtual bool SetVolume(unsigned volume, Error &error) override;
+};
+
+static Mixer *
+haiku_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
+ MixerListener &listener,
+ gcc_unused const ConfigBlock &block,
+ gcc_unused Error &error)
+{
+ return new HaikuMixer((HaikuOutput &)ao, listener);
+}
+
+int
+HaikuMixer::GetVolume(gcc_unused Error &error)
+{
+ return haiku_output_get_volume(self);
+}
+
+bool
+HaikuMixer::SetVolume(unsigned volume, gcc_unused Error &error)
+{
+ return haiku_output_set_volume(self, volume);
+}
+
+const MixerPlugin haiku_mixer_plugin = {
+ haiku_mixer_init,
+ false,
+};
diff --git a/src/mixer/plugins/NullMixerPlugin.cxx b/src/mixer/plugins/NullMixerPlugin.cxx
new file mode 100644
index 000000000..d846a6be1
--- /dev/null
+++ b/src/mixer/plugins/NullMixerPlugin.cxx
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "mixer/MixerInternal.hxx"
+
+class NullMixer final : public Mixer {
+ /**
+ * The current volume in percent (0..100).
+ */
+ unsigned volume;
+
+public:
+ NullMixer(MixerListener &_listener)
+ :Mixer(null_mixer_plugin, _listener),
+ volume(100)
+ {
+ }
+
+ /* virtual methods from class Mixer */
+ bool Open(gcc_unused Error &error) override {
+ return true;
+ }
+
+ void Close() override {
+ }
+
+ int GetVolume(gcc_unused Error &error) override {
+ return volume;
+ }
+
+ bool SetVolume(unsigned _volume, gcc_unused Error &error) override {
+ volume = _volume;
+ return true;
+ }
+};
+
+static Mixer *
+null_mixer_init(gcc_unused EventLoop &event_loop,
+ gcc_unused AudioOutput &ao,
+ MixerListener &listener,
+ gcc_unused const ConfigBlock &block,
+ gcc_unused Error &error)
+{
+ return new NullMixer(listener);
+}
+
+const MixerPlugin null_mixer_plugin = {
+ null_mixer_init,
+ true,
+};
diff --git a/src/mixer/plugins/OssMixerPlugin.cxx b/src/mixer/plugins/OssMixerPlugin.cxx
index 6615c7022..ae198492c 100644
--- a/src/mixer/plugins/OssMixerPlugin.cxx
+++ b/src/mixer/plugins/OssMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "mixer/MixerInternal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "system/fd_util.h"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
@@ -52,7 +52,7 @@ public:
OssMixer(MixerListener &_listener)
:Mixer(oss_mixer_plugin, _listener) {}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class Mixer */
virtual bool Open(Error &error) override;
@@ -79,10 +79,10 @@ oss_find_mixer(const char *name)
}
inline bool
-OssMixer::Configure(const config_param &param, Error &error)
+OssMixer::Configure(const ConfigBlock &block, Error &error)
{
- device = param.GetBlockValue("mixer_device", VOLUME_MIXER_OSS_DEFAULT);
- control = param.GetBlockValue("mixer_control");
+ device = block.GetBlockValue("mixer_device", VOLUME_MIXER_OSS_DEFAULT);
+ control = block.GetBlockValue("mixer_control");
if (control != NULL) {
volume_control = oss_find_mixer(control);
@@ -100,12 +100,12 @@ OssMixer::Configure(const config_param &param, Error &error)
static Mixer *
oss_mixer_init(gcc_unused EventLoop &event_loop, gcc_unused AudioOutput &ao,
MixerListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error)
{
OssMixer *om = new OssMixer(listener);
- if (!om->Configure(param, error)) {
+ if (!om->Configure(block, error)) {
delete om;
return nullptr;
}
diff --git a/src/mixer/plugins/PulseMixerPlugin.cxx b/src/mixer/plugins/PulseMixerPlugin.cxx
index c5f20723b..f2b17a75a 100644
--- a/src/mixer/plugins/PulseMixerPlugin.cxx
+++ b/src/mixer/plugins/PulseMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,18 +19,18 @@
#include "config.h"
#include "PulseMixerPlugin.hxx"
+#include "lib/pulse/Domain.hxx"
+#include "lib/pulse/LogError.hxx"
#include "mixer/MixerInternal.hxx"
#include "mixer/Listener.hxx"
#include "output/plugins/PulseOutputPlugin.hxx"
#include "util/Error.hxx"
-#include "util/Domain.hxx"
#include "Log.hxx"
#include <pulse/context.h>
#include <pulse/introspect.h>
#include <pulse/stream.h>
#include <pulse/subscribe.h>
-#include <pulse/error.h>
#include <assert.h>
@@ -55,19 +55,17 @@ public:
int GetVolumeInternal(Error &error);
/* virtual methods from class Mixer */
- virtual bool Open(gcc_unused Error &error) override {
+ bool Open(gcc_unused Error &error) override {
return true;
}
- virtual void Close() override {
+ void Close() override {
}
- virtual int GetVolume(Error &error) override;
- virtual bool SetVolume(unsigned volume, Error &error) override;
+ int GetVolume(Error &error) override;
+ bool SetVolume(unsigned volume, Error &error) override;
};
-static constexpr Domain pulse_mixer_domain("pulse_mixer");
-
void
PulseMixer::Offline()
{
@@ -120,9 +118,8 @@ PulseMixer::Update(pa_context *context, pa_stream *stream)
pa_stream_get_index(stream),
pulse_mixer_volume_cb, this);
if (o == nullptr) {
- FormatError(pulse_mixer_domain,
- "pa_context_get_sink_input_info() failed: %s",
- pa_strerror(pa_context_errno(context)));
+ LogPulseError(context,
+ "pa_context_get_sink_input_info() failed");
Offline();
return;
}
@@ -142,9 +139,8 @@ pulse_mixer_on_connect(gcc_unused PulseMixer &pm,
(pa_subscription_mask_t)PA_SUBSCRIPTION_MASK_SINK_INPUT,
nullptr, nullptr);
if (o == nullptr) {
- FormatError(pulse_mixer_domain,
- "pa_context_subscribe() failed: %s",
- pa_strerror(pa_context_errno(context)));
+ LogPulseError(context,
+ "pa_context_subscribe() failed");
return;
}
@@ -167,7 +163,7 @@ pulse_mixer_on_change(PulseMixer &pm,
static Mixer *
pulse_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
PulseOutput &po = (PulseOutput &)ao;
@@ -212,7 +208,7 @@ PulseMixer::SetVolume(unsigned new_volume, Error &error)
if (!online) {
pulse_output_unlock(output);
- error.Set(pulse_mixer_domain, "disconnected");
+ error.Set(pulse_domain, "disconnected");
return false;
}
diff --git a/src/mixer/plugins/PulseMixerPlugin.hxx b/src/mixer/plugins/PulseMixerPlugin.hxx
index 9b3a6daf1..64605ea8d 100644
--- a/src/mixer/plugins/PulseMixerPlugin.hxx
+++ b/src/mixer/plugins/PulseMixerPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/plugins/RoarMixerPlugin.cxx b/src/mixer/plugins/RoarMixerPlugin.cxx
index 8e198478d..9123762f2 100644
--- a/src/mixer/plugins/RoarMixerPlugin.cxx
+++ b/src/mixer/plugins/RoarMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
* Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
*
@@ -48,7 +48,7 @@ public:
static Mixer *
roar_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new RoarMixer((RoarOutput &)ao, listener);
diff --git a/src/mixer/plugins/SoftwareMixerPlugin.cxx b/src/mixer/plugins/SoftwareMixerPlugin.cxx
index f14766002..d35e7f469 100644
--- a/src/mixer/plugins/SoftwareMixerPlugin.cxx
+++ b/src/mixer/plugins/SoftwareMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
#include "filter/FilterInternal.hxx"
#include "filter/plugins/VolumeFilterPlugin.hxx"
#include "pcm/Volume.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "util/Error.hxx"
#include <assert.h>
@@ -34,7 +34,7 @@
static Filter *
CreateVolumeFilter()
{
- return filter_new(&volume_filter_plugin, config_param(),
+ return filter_new(&volume_filter_plugin, ConfigBlock(),
IgnoreError());
}
@@ -90,7 +90,7 @@ static Mixer *
software_mixer_init(gcc_unused EventLoop &event_loop,
gcc_unused AudioOutput &ao,
MixerListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new SoftwareMixer(listener);
diff --git a/src/mixer/plugins/SoftwareMixerPlugin.hxx b/src/mixer/plugins/SoftwareMixerPlugin.hxx
index 581d2ac17..f9be1d9d9 100644
--- a/src/mixer/plugins/SoftwareMixerPlugin.hxx
+++ b/src/mixer/plugins/SoftwareMixerPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/mixer/plugins/WinmmMixerPlugin.cxx b/src/mixer/plugins/WinmmMixerPlugin.cxx
index e0436011a..51d8092f9 100644
--- a/src/mixer/plugins/WinmmMixerPlugin.cxx
+++ b/src/mixer/plugins/WinmmMixerPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -69,7 +69,7 @@ winmm_volume_encode(int volume)
static Mixer *
winmm_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
MixerListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new WinmmMixer((WinmmOutput &)ao, listener);
diff --git a/src/neighbor/Explorer.hxx b/src/neighbor/Explorer.hxx
index 84a54840c..abf426cd9 100644
--- a/src/neighbor/Explorer.hxx
+++ b/src/neighbor/Explorer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/Glue.cxx b/src/neighbor/Glue.cxx
index fbf25cc8d..4d5d7b4b0 100644
--- a/src/neighbor/Glue.cxx
+++ b/src/neighbor/Glue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,8 +24,8 @@
#include "NeighborPlugin.hxx"
#include "Info.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
#include "config/ConfigError.hxx"
+#include "config/Block.hxx"
#include "util/Error.hxx"
NeighborGlue::Explorer::~Explorer()
@@ -37,9 +37,9 @@ NeighborGlue::~NeighborGlue() {}
static NeighborExplorer *
CreateNeighborExplorer(EventLoop &loop, NeighborListener &listener,
- const config_param &param, Error &error)
+ const ConfigBlock &block, Error &error)
{
- const char *plugin_name = param.GetBlockValue("plugin");
+ const char *plugin_name = block.GetBlockValue("plugin");
if (plugin_name == nullptr) {
error.Set(config_domain,
"Missing \"plugin\" configuration");
@@ -53,18 +53,18 @@ CreateNeighborExplorer(EventLoop &loop, NeighborListener &listener,
return nullptr;
}
- return plugin->create(loop, listener, param, error);
+ return plugin->create(loop, listener, block, error);
}
bool
NeighborGlue::Init(EventLoop &loop, NeighborListener &listener, Error &error)
{
- for (const config_param *param = config_get_param(CONF_NEIGHBORS);
- param != nullptr; param = param->next) {
+ for (const auto *block = config_get_block(ConfigBlockOption::NEIGHBORS);
+ block != nullptr; block = block->next) {
NeighborExplorer *explorer =
- CreateNeighborExplorer(loop, listener, *param, error);
+ CreateNeighborExplorer(loop, listener, *block, error);
if (explorer == nullptr) {
- error.FormatPrefix("Line %i: ", param->line);
+ error.FormatPrefix("Line %i: ", block->line);
return false;
}
diff --git a/src/neighbor/Glue.hxx b/src/neighbor/Glue.hxx
index 92c612d22..fc1778d05 100644
--- a/src/neighbor/Glue.hxx
+++ b/src/neighbor/Glue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/Info.hxx b/src/neighbor/Info.hxx
index ac4806f14..a9e629213 100644
--- a/src/neighbor/Info.hxx
+++ b/src/neighbor/Info.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/Listener.hxx b/src/neighbor/Listener.hxx
index 20295f5a9..dcf6cafff 100644
--- a/src/neighbor/Listener.hxx
+++ b/src/neighbor/Listener.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/NeighborPlugin.hxx b/src/neighbor/NeighborPlugin.hxx
index 0d4ebaa7b..116f47c50 100644
--- a/src/neighbor/NeighborPlugin.hxx
+++ b/src/neighbor/NeighborPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#ifndef MPD_NEIGHBOR_PLUGIN_HXX
#define MPD_NEIGHBOR_PLUGIN_HXX
-struct config_param;
+struct ConfigBlock;
class Error;
class EventLoop;
class NeighborListener;
@@ -33,7 +33,7 @@ struct NeighborPlugin {
* Allocates and configures a #NeighborExplorer instance.
*/
NeighborExplorer *(*create)(EventLoop &loop, NeighborListener &listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
};
diff --git a/src/neighbor/Registry.cxx b/src/neighbor/Registry.cxx
index f6d1f97b3..d58e3b974 100644
--- a/src/neighbor/Registry.cxx
+++ b/src/neighbor/Registry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@ const NeighborPlugin *const neighbor_plugins[] = {
#ifdef ENABLE_SMBCLIENT
&smbclient_neighbor_plugin,
#endif
-#ifdef HAVE_LIBUPNP
+#ifdef ENABLE_UPNP
&upnp_neighbor_plugin,
#endif
nullptr
diff --git a/src/neighbor/Registry.hxx b/src/neighbor/Registry.hxx
index 0b89e537d..59c9f1fb2 100644
--- a/src/neighbor/Registry.hxx
+++ b/src/neighbor/Registry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/plugins/SmbclientNeighborPlugin.cxx b/src/neighbor/plugins/SmbclientNeighborPlugin.cxx
index 2701b0ccd..d4c73f9a8 100644
--- a/src/neighbor/plugins/SmbclientNeighborPlugin.cxx
+++ b/src/neighbor/plugins/SmbclientNeighborPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -216,7 +216,7 @@ SmbclientNeighborExplorer::Run()
prev = i;
} else {
/* can't see it anymore: move to "lost" */
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
lost.splice_after(lost.before_begin(), list, prev);
#else
/* the forward_list::splice_after() lvalue
@@ -273,7 +273,7 @@ SmbclientNeighborExplorer::ThreadFunc(void *ctx)
static NeighborExplorer *
smbclient_neighbor_create(gcc_unused EventLoop &loop,
NeighborListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
if (!SmbclientInit(error))
diff --git a/src/neighbor/plugins/SmbclientNeighborPlugin.hxx b/src/neighbor/plugins/SmbclientNeighborPlugin.hxx
index 12ec9c0cd..be5560eee 100644
--- a/src/neighbor/plugins/SmbclientNeighborPlugin.hxx
+++ b/src/neighbor/plugins/SmbclientNeighborPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/neighbor/plugins/UpnpNeighborPlugin.cxx b/src/neighbor/plugins/UpnpNeighborPlugin.cxx
index 253e4c13b..3c0cb8843 100644
--- a/src/neighbor/plugins/UpnpNeighborPlugin.cxx
+++ b/src/neighbor/plugins/UpnpNeighborPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -100,7 +100,7 @@ UpnpNeighborExplorer::GetList() const
{
Error error;
- if (!discovery->getDirServices(tmp, error))
+ if (!discovery->GetDirectories(tmp, error))
LogError(error);
}
@@ -127,7 +127,7 @@ UpnpNeighborExplorer::LostUPnP(const ContentDirectoryService &service)
static NeighborExplorer *
upnp_neighbor_create(gcc_unused EventLoop &loop,
NeighborListener &listener,
- gcc_unused const config_param &param,
+ gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
return new UpnpNeighborExplorer(listener);
diff --git a/src/neighbor/plugins/UpnpNeighborPlugin.hxx b/src/neighbor/plugins/UpnpNeighborPlugin.hxx
index 78e4ccf13..abda3addd 100644
--- a/src/neighbor/plugins/UpnpNeighborPlugin.hxx
+++ b/src/neighbor/plugins/UpnpNeighborPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/net/AllocatedSocketAddress.cxx b/src/net/AllocatedSocketAddress.cxx
new file mode 100644
index 000000000..61615a72b
--- /dev/null
+++ b/src/net/AllocatedSocketAddress.cxx
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "config.h"
+#include "AllocatedSocketAddress.hxx"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef HAVE_UN
+#include <sys/un.h>
+#endif
+
+AllocatedSocketAddress &
+AllocatedSocketAddress::operator=(SocketAddress src)
+{
+ if (src.IsNull()) {
+ Clear();
+ } else {
+ SetSize(src.GetSize());
+ memcpy(address, src.GetAddress(), size);
+ }
+
+ return *this;
+}
+
+void
+AllocatedSocketAddress::SetSize(size_type new_size)
+{
+ if (size == new_size)
+ return;
+
+ free(address);
+ size = new_size;
+ address = (struct sockaddr *)malloc(size);
+}
+
+#ifdef HAVE_UN
+
+void
+AllocatedSocketAddress::SetLocal(const char *path)
+{
+ const bool is_abstract = *path == '@';
+
+ /* sun_path must be null-terminated unless it's an abstract
+ socket */
+ const size_t path_length = strlen(path) + !is_abstract;
+
+ struct sockaddr_un *sun;
+ SetSize(sizeof(*sun) - sizeof(sun->sun_path) + path_length);
+ sun = (struct sockaddr_un *)address;
+ sun->sun_family = AF_UNIX;
+ memcpy(sun->sun_path, path, path_length);
+
+ if (is_abstract)
+ sun->sun_path[0] = 0;
+}
+
+#endif
diff --git a/src/net/AllocatedSocketAddress.hxx b/src/net/AllocatedSocketAddress.hxx
new file mode 100644
index 000000000..db02488df
--- /dev/null
+++ b/src/net/AllocatedSocketAddress.hxx
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 ALLOCATED_SOCKET_ADDRESS_HPP
+#define ALLOCATED_SOCKET_ADDRESS_HPP
+
+#include "SocketAddress.hxx"
+#include "Features.hxx"
+#include "Compiler.h"
+
+#include <algorithm>
+
+#include <stdlib.h>
+
+struct sockaddr;
+class Error;
+
+class AllocatedSocketAddress {
+public:
+ typedef SocketAddress::size_type size_type;
+
+private:
+ struct sockaddr *address;
+ size_type size;
+
+ AllocatedSocketAddress(struct sockaddr *_address,
+ size_type _size)
+ :address(_address), size(_size) {}
+
+public:
+ AllocatedSocketAddress():address(nullptr), size(0) {}
+
+ explicit AllocatedSocketAddress(SocketAddress src)
+ :address(nullptr), size(0) {
+ *this = src;
+ }
+
+ AllocatedSocketAddress(const AllocatedSocketAddress &) = delete;
+
+ AllocatedSocketAddress(AllocatedSocketAddress &&src)
+ :address(src.address), size(src.size) {
+ src.address = nullptr;
+ src.size = 0;
+ }
+
+ ~AllocatedSocketAddress() {
+ free(address);
+ }
+
+ AllocatedSocketAddress &operator=(SocketAddress src);
+
+ AllocatedSocketAddress &operator=(const AllocatedSocketAddress &) = delete;
+
+ AllocatedSocketAddress &operator=(AllocatedSocketAddress &&src) {
+ std::swap(address, src.address);
+ std::swap(size, src.size);
+ return *this;
+ }
+
+ gcc_pure
+ bool operator==(SocketAddress other) const {
+ return (SocketAddress)*this == other;
+ }
+
+ bool operator!=(SocketAddress &other) const {
+ return !(*this == other);
+ }
+
+ gcc_const
+ static AllocatedSocketAddress Null() {
+ return AllocatedSocketAddress(nullptr, 0);
+ }
+
+ bool IsNull() const {
+ return address == nullptr;
+ }
+
+ size_type GetSize() const {
+ return size;
+ }
+
+ const struct sockaddr *GetAddress() const {
+ return address;
+ }
+
+ operator SocketAddress() const {
+ return SocketAddress(address, size);
+ }
+
+ operator const struct sockaddr *() const {
+ return address;
+ }
+
+ int GetFamily() const {
+ return address->sa_family;
+ }
+
+ /**
+ * Does the object have a well-defined address? Check !IsNull()
+ * before calling this method.
+ */
+ bool IsDefined() const {
+ return GetFamily() != AF_UNSPEC;
+ }
+
+ void Clear() {
+ free(address);
+ address = nullptr;
+ size = 0;
+ }
+
+#ifdef HAVE_UN
+ /**
+ * Make this a "local" address (UNIX domain socket). If the path
+ * begins with a '@', then the rest specifies an "abstract" local
+ * address.
+ */
+ void SetLocal(const char *path);
+#endif
+
+private:
+ void SetSize(size_type new_size);
+};
+
+#endif
diff --git a/src/net/Features.hxx b/src/net/Features.hxx
new file mode 100644
index 000000000..05dcc5659
--- /dev/null
+++ b/src/net/Features.hxx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef NET_FEATURES_HXX
+#define NET_FEATURES_HXX
+
+/* feature macros are defined in config.h, and this header verifies
+ that it has been included earlier */
+#include "check.h"
+
+#endif
diff --git a/src/system/Resolver.cxx b/src/net/Resolver.cxx
index a94217bac..189c5bc9c 100644
--- a/src/system/Resolver.cxx
+++ b/src/net/Resolver.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,22 +19,16 @@
#include "config.h"
#include "Resolver.hxx"
+#include "SocketAddress.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
-#ifndef WIN32
-#include <sys/socket.h>
-#include <netdb.h>
-#ifdef HAVE_TCP
-#include <netinet/in.h>
-#endif
-#else
-#include <ws2tcpip.h>
-#include <winsock.h>
-#endif
+#include <string>
-#ifdef HAVE_UN
-#include <sys/un.h>
+#ifdef WIN32
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
#endif
#include <string.h>
@@ -42,64 +36,6 @@
const Domain resolver_domain("resolver");
-std::string
-sockaddr_to_string(const struct sockaddr *sa, size_t length)
-{
-#ifdef HAVE_UN
- if (sa->sa_family == AF_UNIX) {
- /* return path of UNIX domain sockets */
- const sockaddr_un &s_un = *(const sockaddr_un *)sa;
- if (length < sizeof(s_un) || s_un.sun_path[0] == 0)
- return "local";
-
- return s_un.sun_path;
- }
-#endif
-
-#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
- const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)sa;
- struct sockaddr_in a4;
-#endif
- int ret;
- char host[NI_MAXHOST], serv[NI_MAXSERV];
-
-#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
- if (sa->sa_family == AF_INET6 &&
- IN6_IS_ADDR_V4MAPPED(&a6->sin6_addr)) {
- /* convert "::ffff:127.0.0.1" to "127.0.0.1" */
-
- memset(&a4, 0, sizeof(a4));
- a4.sin_family = AF_INET;
- memcpy(&a4.sin_addr, ((const char *)&a6->sin6_addr) + 12,
- sizeof(a4.sin_addr));
- a4.sin_port = a6->sin6_port;
-
- sa = (const struct sockaddr *)&a4;
- length = sizeof(a4);
- }
-#endif
-
- ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv),
- NI_NUMERICHOST|NI_NUMERICSERV);
- if (ret != 0)
- return "unknown";
-
-#ifdef HAVE_IPV6
- if (strchr(host, ':') != nullptr) {
- std::string result("[");
- result.append(host);
- result.append("]:");
- result.append(serv);
- return result;
- }
-#endif
-
- std::string result(host);
- result.push_back(':');
- result.append(serv);
- return result;
-}
-
struct addrinfo *
resolve_host_port(const char *host_port, unsigned default_port,
int flags, int socktype,
diff --git a/src/system/Resolver.hxx b/src/net/Resolver.hxx
index 54922d98f..826cc4787 100644
--- a/src/system/Resolver.hxx
+++ b/src/net/Resolver.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,13 +20,9 @@
#ifndef MPD_RESOLVER_HXX
#define MPD_RESOLVER_HXX
+#include "check.h"
#include "Compiler.h"
-#include <string>
-
-#include <stddef.h>
-
-struct sockaddr;
struct addrinfo;
class Error;
class Domain;
@@ -34,17 +30,6 @@ class Domain;
extern const Domain resolver_domain;
/**
- * Converts the specified socket address into a string in the form
- * "IP:PORT".
- *
- * @param sa the sockaddr struct
- * @param length the length of #sa in bytes
- */
-gcc_pure
-std::string
-sockaddr_to_string(const sockaddr *sa, size_t length);
-
-/**
* Resolve a specification in the form "host", "host:port",
* "[host]:port". This is a convenience wrapper for getaddrinfo().
*
diff --git a/src/net/SocketAddress.cxx b/src/net/SocketAddress.cxx
new file mode 100644
index 000000000..38aeb8d6d
--- /dev/null
+++ b/src/net/SocketAddress.cxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "SocketAddress.hxx"
+
+#include <string.h>
+
+bool
+SocketAddress::operator==(SocketAddress other) const
+{
+ return size == other.size && memcmp(address, other.address, size) == 0;
+}
diff --git a/src/net/SocketAddress.hxx b/src/net/SocketAddress.hxx
new file mode 100644
index 000000000..0577edd72
--- /dev/null
+++ b/src/net/SocketAddress.hxx
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 SOCKET_ADDRESS_HXX
+#define SOCKET_ADDRESS_HXX
+
+#include "Compiler.h"
+
+#include <cstddef>
+
+#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#endif
+
+/**
+ * An OO wrapper for struct sockaddr.
+ */
+class SocketAddress {
+public:
+#ifdef WIN32
+ typedef int size_type;
+#else
+ typedef socklen_t size_type;
+#endif
+
+private:
+ const struct sockaddr *address;
+ size_type size;
+
+public:
+ SocketAddress() = default;
+
+ constexpr SocketAddress(std::nullptr_t):address(nullptr), size(0) {}
+
+ constexpr SocketAddress(const struct sockaddr *_address,
+ size_type _size)
+ :address(_address), size(_size) {}
+
+ static constexpr SocketAddress Null() {
+ return nullptr;
+ }
+
+ constexpr bool IsNull() const {
+ return address == nullptr;
+ }
+
+ const struct sockaddr *GetAddress() const {
+ return address;
+ }
+
+ constexpr size_type GetSize() const {
+ return size;
+ }
+
+ constexpr int GetFamily() const {
+ return address->sa_family;
+ }
+
+ /**
+ * Does the object have a well-defined address? Check !IsNull()
+ * before calling this method.
+ */
+ bool IsDefined() const {
+ return GetFamily() != AF_UNSPEC;
+ }
+
+ gcc_pure
+ bool operator==(const SocketAddress other) const;
+
+ bool operator!=(const SocketAddress other) const {
+ return !(*this == other);
+ }
+};
+
+#endif
diff --git a/src/system/SocketError.cxx b/src/net/SocketError.cxx
index e138f4dd3..efa969b1f 100644
--- a/src/system/SocketError.cxx
+++ b/src/net/SocketError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "SocketError.hxx"
#include "util/Domain.hxx"
+#include "util/Macros.hxx"
#include <string.h>
@@ -29,13 +30,31 @@ const Domain socket_domain("socket");
SocketErrorMessage::SocketErrorMessage(socket_error_t code)
{
+#ifdef _UNICODE
+ wchar_t buffer[ARRAY_SIZE(msg)];
+#else
+ auto *buffer = msg;
+#endif
+
DWORD nbytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL, code, 0,
- (LPSTR)msg, sizeof(msg), NULL);
- if (nbytes == 0)
+ nullptr, code, 0,
+ buffer, ARRAY_SIZE(msg), nullptr);
+ if (nbytes == 0) {
strcpy(msg, "Unknown error");
+ return;
+ }
+
+#ifdef _UNICODE
+ auto length = WideCharToMultiByte(CP_UTF8, 0, buffer, -1,
+ msg, ARRAY_SIZE(msg),
+ nullptr, nullptr);
+ if (length <= 0) {
+ strcpy(msg, "WideCharToMultiByte() error");
+ return;
+ }
+#endif
}
#else
diff --git a/src/system/SocketError.hxx b/src/net/SocketError.hxx
index 01abc9884..c9435d6fb 100644
--- a/src/system/SocketError.hxx
+++ b/src/net/SocketError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/SocketUtil.cxx b/src/net/SocketUtil.cxx
index b9df0d59d..72d710862 100644
--- a/src/system/SocketUtil.cxx
+++ b/src/net/SocketUtil.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,25 +19,19 @@
#include "config.h"
#include "SocketUtil.hxx"
+#include "SocketAddress.hxx"
#include "SocketError.hxx"
-#include "fd_util.h"
+#include "system/fd_util.h"
#include <unistd.h>
-#ifndef WIN32
-#include <sys/socket.h>
-#else
-#include <ws2tcpip.h>
-#include <winsock.h>
-#endif
-
#ifdef HAVE_IPV6
#include <string.h>
#endif
int
socket_bind_listen(int domain, int type, int protocol,
- const struct sockaddr *address, size_t address_length,
+ SocketAddress address,
int backlog,
Error &error)
{
@@ -60,7 +54,7 @@ socket_bind_listen(int domain, int type, int protocol,
return -1;
}
- ret = bind(fd, address, address_length);
+ ret = bind(fd, address.GetAddress(), address.GetSize());
if (ret < 0) {
SetSocketError(error);
close_socket(fd);
@@ -75,7 +69,7 @@ socket_bind_listen(int domain, int type, int protocol,
return -1;
}
-#ifdef HAVE_STRUCT_UCRED
+#if defined(HAVE_STRUCT_UCRED) && defined(SO_PASSCRED)
setsockopt(fd, SOL_SOCKET, SO_PASSCRED,
(const char *) &reuse, sizeof(reuse));
#endif
diff --git a/src/system/SocketUtil.hxx b/src/net/SocketUtil.hxx
index 652788759..e7f6b8eaa 100644
--- a/src/system/SocketUtil.hxx
+++ b/src/net/SocketUtil.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,9 +26,7 @@
#ifndef MPD_SOCKET_UTIL_HXX
#define MPD_SOCKET_UTIL_HXX
-#include <stddef.h>
-
-struct sockaddr;
+class SocketAddress;
class Error;
/**
@@ -39,7 +37,6 @@ class Error;
* @param type the socket type, e.g. SOCK_STREAM
* @param protocol the protocol, usually 0 to let the kernel choose
* @param address the address to listen on
- * @param address_length the size of #address
* @param backlog the backlog parameter for the listen() system call
* @param error location to store the error occurring, or NULL to
* ignore errors
@@ -47,7 +44,7 @@ class Error;
*/
int
socket_bind_listen(int domain, int type, int protocol,
- const struct sockaddr *address, size_t address_length,
+ SocketAddress address,
int backlog,
Error &error);
diff --git a/src/net/StaticSocketAddress.cxx b/src/net/StaticSocketAddress.cxx
new file mode 100644
index 000000000..94db4a49c
--- /dev/null
+++ b/src/net/StaticSocketAddress.cxx
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "config.h"
+#include "StaticSocketAddress.hxx"
+
+#include <algorithm>
+
+#include <string.h>
+
+StaticSocketAddress &
+StaticSocketAddress::operator=(SocketAddress other)
+{
+ size = std::min(other.GetSize(), GetCapacity());
+ memcpy(&address, other.GetAddress(), size);
+ return *this;
+}
diff --git a/src/net/StaticSocketAddress.hxx b/src/net/StaticSocketAddress.hxx
new file mode 100644
index 000000000..c8cef9dfe
--- /dev/null
+++ b/src/net/StaticSocketAddress.hxx
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 STATIC_SOCKET_ADDRESS_HXX
+#define STATIC_SOCKET_ADDRESS_HXX
+
+#include "SocketAddress.hxx"
+#include "Compiler.h"
+
+#include <assert.h>
+
+/**
+ * An OO wrapper for struct sockaddr_storage.
+ */
+class StaticSocketAddress {
+public:
+ typedef SocketAddress::size_type size_type;
+
+private:
+ size_type size;
+ struct sockaddr_storage address;
+
+public:
+ StaticSocketAddress() = default;
+
+ StaticSocketAddress &operator=(SocketAddress other);
+
+ operator SocketAddress() const {
+ return SocketAddress(reinterpret_cast<const struct sockaddr *>(&address),
+ size);
+ }
+
+ struct sockaddr *GetAddress() {
+ return reinterpret_cast<struct sockaddr *>(&address);
+ }
+
+ const struct sockaddr *GetAddress() const {
+ return reinterpret_cast<const struct sockaddr *>(&address);
+ }
+
+ constexpr size_type GetCapacity() const {
+ return sizeof(address);
+ }
+
+ size_type GetSize() const {
+ return size;
+ }
+
+ void SetSize(size_type _size) {
+ assert(_size > 0);
+ assert(size_t(_size) <= sizeof(address));
+
+ size = _size;
+ }
+
+ int GetFamily() const {
+ return address.ss_family;
+ }
+
+ bool IsDefined() const {
+ return GetFamily() != AF_UNSPEC;
+ }
+
+ void Clear() {
+ address.ss_family = AF_UNSPEC;
+ }
+
+ gcc_pure
+ bool operator==(SocketAddress other) const {
+ return (SocketAddress)*this == other;
+ }
+
+ bool operator!=(SocketAddress &other) const {
+ return !(*this == other);
+ }
+};
+
+#endif
diff --git a/src/net/ToString.cxx b/src/net/ToString.cxx
new file mode 100644
index 000000000..1acf0320b
--- /dev/null
+++ b/src/net/ToString.cxx
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "config.h"
+#include "ToString.hxx"
+#include "Features.hxx"
+#include "SocketAddress.hxx"
+
+#include <algorithm>
+
+#ifdef WIN32
+#include <ws2tcpip.h>
+#else
+#include <netdb.h>
+#ifdef HAVE_TCP
+#include <netinet/in.h>
+#endif
+#endif
+
+#ifdef HAVE_UN
+#include <sys/un.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef HAVE_UN
+
+static std::string
+LocalAddressToString(const struct sockaddr_un &s_un, size_t size)
+{
+ const size_t prefix_size = (size_t)
+ ((struct sockaddr_un *)nullptr)->sun_path;
+ assert(size >= prefix_size);
+
+ size_t result_length = size - prefix_size;
+
+ /* remove the trailing null terminator */
+ if (result_length > 0 && s_un.sun_path[result_length - 1] == 0)
+ --result_length;
+
+ if (result_length == 0)
+ return "local";
+
+ std::string result(s_un.sun_path, result_length);
+
+ /* replace all null bytes with '@'; this also handles abstract
+ addresses (Linux specific) */
+ std::replace(result.begin(), result.end(), '\0', '@');
+
+ return result;
+}
+
+#endif
+
+#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
+
+gcc_pure
+static bool
+IsV4Mapped(SocketAddress address)
+{
+ if (address.GetFamily() != AF_INET6)
+ return false;
+
+ const auto &a6 = *(const struct sockaddr_in6 *)address.GetAddress();
+ return IN6_IS_ADDR_V4MAPPED(&a6.sin6_addr);
+}
+
+/**
+ * Convert "::ffff:127.0.0.1" to "127.0.0.1".
+ */
+static SocketAddress
+UnmapV4(SocketAddress src, struct sockaddr_in &buffer)
+{
+ assert(IsV4Mapped(src));
+
+ const auto &src6 = *(const struct sockaddr_in6 *)src.GetAddress();
+ memset(&buffer, 0, sizeof(buffer));
+ buffer.sin_family = AF_INET;
+ memcpy(&buffer.sin_addr, ((const char *)&src6.sin6_addr) + 12,
+ sizeof(buffer.sin_addr));
+ buffer.sin_port = src6.sin6_port;
+
+ return { (const struct sockaddr *)&buffer, sizeof(buffer) };
+}
+
+#endif
+
+std::string
+ToString(SocketAddress address)
+{
+#ifdef HAVE_UN
+ if (address.GetFamily() == AF_UNIX)
+ /* return path of UNIX domain sockets */
+ return LocalAddressToString(*(const sockaddr_un *)address.GetAddress(),
+ address.GetSize());
+#endif
+
+#if defined(HAVE_IPV6) && defined(IN6_IS_ADDR_V4MAPPED)
+ struct sockaddr_in in_buffer;
+ if (IsV4Mapped(address))
+ address = UnmapV4(address, in_buffer);
+#endif
+
+ char host[NI_MAXHOST], serv[NI_MAXSERV];
+ int ret = getnameinfo(address.GetAddress(), address.GetSize(),
+ host, sizeof(host), serv, sizeof(serv),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ if (ret != 0)
+ return "unknown";
+
+#ifdef HAVE_IPV6
+ if (strchr(host, ':') != nullptr) {
+ std::string result("[");
+ result.append(host);
+ result.append("]:");
+ result.append(serv);
+ return result;
+ }
+#endif
+
+ std::string result(host);
+ result.push_back(':');
+ result.append(serv);
+ return result;
+}
diff --git a/src/net/ToString.hxx b/src/net/ToString.hxx
new file mode 100644
index 000000000..4b676008a
--- /dev/null
+++ b/src/net/ToString.hxx
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 NET_TO_STRING_HXX
+#define NET_TO_STRING_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#include <string>
+
+class SocketAddress;
+
+/**
+ * Converts the specified socket address into a string in the form
+ * "IP:PORT".
+ */
+gcc_pure
+std::string
+ToString(SocketAddress address);
+
+#endif
diff --git a/src/notify.cxx b/src/notify.cxx
index 5b0b4baa0..06a4da611 100644
--- a/src/notify.cxx
+++ b/src/notify.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/notify.hxx b/src/notify.hxx
index 3e62a0103..b1bc594be 100644
--- a/src/notify.hxx
+++ b/src/notify.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@ struct notify {
Cond cond;
bool pending;
-#if !defined(WIN32) && !defined(__NetBSD__) && !defined(__BIONIC__)
+#ifdef __GLIBC__
constexpr
#endif
notify():pending(false) {}
diff --git a/src/open.h b/src/open.h
index b05167188..71629f520 100644
--- a/src/open.h
+++ b/src/open.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Domain.cxx b/src/output/Domain.cxx
index 878e5f3c5..abfdb6a5e 100644
--- a/src/output/Domain.cxx
+++ b/src/output/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Domain.hxx b/src/output/Domain.hxx
index e3a20142f..136a2b8a9 100644
--- a/src/output/Domain.hxx
+++ b/src/output/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Finish.cxx b/src/output/Finish.cxx
index be2ca463e..2dd4acda5 100644
--- a/src/output/Finish.cxx
+++ b/src/output/Finish.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Init.cxx b/src/output/Init.cxx
index 79ef4f998..ae34bf846 100644
--- a/src/output/Init.cxx
+++ b/src/output/Init.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,7 @@
#include "filter/plugins/ChainFilterPlugin.hxx"
#include "config/ConfigError.hxx"
#include "config/ConfigGlobal.hxx"
+#include "config/Block.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
@@ -58,7 +59,7 @@ AudioOutput::AudioOutput(const AudioOutputPlugin &_plugin)
filter(nullptr),
replay_gain_filter(nullptr),
other_replay_gain_filter(nullptr),
- command(AO_COMMAND_NONE)
+ command(Command::NONE)
{
assert(plugin.finish != nullptr);
assert(plugin.open != nullptr);
@@ -94,27 +95,27 @@ audio_output_detect(Error &error)
* mixer_enabled, if the mixer_type setting is not configured.
*/
gcc_pure
-static enum mixer_type
-audio_output_mixer_type(const config_param &param)
+static MixerType
+audio_output_mixer_type(const ConfigBlock &block)
{
/* read the local "mixer_type" setting */
- const char *p = param.GetBlockValue("mixer_type");
+ const char *p = block.GetBlockValue("mixer_type");
if (p != nullptr)
return mixer_type_parse(p);
/* try the local "mixer_enabled" setting next (deprecated) */
- if (!param.GetBlockValue("mixer_enabled", true))
- return MIXER_TYPE_NONE;
+ if (!block.GetBlockValue("mixer_enabled", true))
+ return MixerType::NONE;
/* fall back to the global "mixer_type" setting (also
deprecated) */
- return mixer_type_parse(config_get_string(CONF_MIXER_TYPE,
+ return mixer_type_parse(config_get_string(ConfigOption::MIXER_TYPE,
"hardware"));
}
static Mixer *
audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
- const config_param &param,
+ const ConfigBlock &block,
const MixerPlugin *plugin,
Filter &filter_chain,
MixerListener &listener,
@@ -122,22 +123,26 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
{
Mixer *mixer;
- switch (audio_output_mixer_type(param)) {
- case MIXER_TYPE_NONE:
- case MIXER_TYPE_UNKNOWN:
+ switch (audio_output_mixer_type(block)) {
+ case MixerType::NONE:
+ case MixerType::UNKNOWN:
return nullptr;
- case MIXER_TYPE_HARDWARE:
+ case MixerType::NULL_:
+ return mixer_new(event_loop, null_mixer_plugin, ao, listener,
+ block, error);
+
+ case MixerType::HARDWARE:
if (plugin == nullptr)
return nullptr;
return mixer_new(event_loop, *plugin, ao, listener,
- param, error);
+ block, error);
- case MIXER_TYPE_SOFTWARE:
+ case MixerType::SOFTWARE:
mixer = mixer_new(event_loop, software_mixer_plugin, ao,
listener,
- config_param(),
+ ConfigBlock(),
IgnoreError());
assert(mixer != nullptr);
@@ -151,17 +156,17 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
}
bool
-AudioOutput::Configure(const config_param &param, Error &error)
+AudioOutput::Configure(const ConfigBlock &block, Error &error)
{
- if (!param.IsNull()) {
- name = param.GetBlockValue(AUDIO_OUTPUT_NAME);
+ if (!block.IsNull()) {
+ name = block.GetBlockValue(AUDIO_OUTPUT_NAME);
if (name == nullptr) {
error.Set(config_domain,
"Missing \"name\" configuration");
return false;
}
- const char *p = param.GetBlockValue(AUDIO_OUTPUT_FORMAT);
+ const char *p = block.GetBlockValue(AUDIO_OUTPUT_FORMAT);
if (p != nullptr) {
bool success =
audio_format_parse(config_audio_format,
@@ -176,9 +181,9 @@ AudioOutput::Configure(const config_param &param, Error &error)
config_audio_format.Clear();
}
- tags = param.GetBlockValue("tags", true);
- always_on = param.GetBlockValue("always_on", false);
- enabled = param.GetBlockValue("enabled", true);
+ tags = block.GetBlockValue("tags", true);
+ always_on = block.GetBlockValue("always_on", false);
+ enabled = block.GetBlockValue("enabled", true);
/* set up the filter chain */
@@ -187,9 +192,9 @@ AudioOutput::Configure(const config_param &param, Error &error)
/* create the normalization filter (if configured) */
- if (config_get_bool(CONF_VOLUME_NORMALIZATION, false)) {
+ if (config_get_bool(ConfigOption::VOLUME_NORMALIZATION, false)) {
Filter *normalize_filter =
- filter_new(&normalize_filter_plugin, config_param(),
+ filter_new(&normalize_filter_plugin, ConfigBlock(),
IgnoreError());
assert(normalize_filter != nullptr);
@@ -199,7 +204,7 @@ AudioOutput::Configure(const config_param &param, Error &error)
Error filter_error;
filter_chain_parse(*filter,
- param.GetBlockValue(AUDIO_FILTERS, ""),
+ block.GetBlockValue(AUDIO_FILTERS, ""),
filter_error);
// It's not really fatal - Part of the filter chain has been set up already
@@ -217,24 +222,24 @@ AudioOutput::Configure(const config_param &param, Error &error)
static bool
audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
MixerListener &mixer_listener,
- const config_param &param,
+ const ConfigBlock &block,
Error &error)
{
/* create the replay_gain filter */
const char *replay_gain_handler =
- param.GetBlockValue("replay_gain_handler", "software");
+ block.GetBlockValue("replay_gain_handler", "software");
if (strcmp(replay_gain_handler, "none") != 0) {
ao.replay_gain_filter = filter_new(&replay_gain_filter_plugin,
- param, IgnoreError());
+ block, IgnoreError());
assert(ao.replay_gain_filter != nullptr);
ao.replay_gain_serial = 0;
ao.other_replay_gain_filter = filter_new(&replay_gain_filter_plugin,
- param,
+ block,
IgnoreError());
assert(ao.other_replay_gain_filter != nullptr);
@@ -247,7 +252,7 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
/* set up the mixer */
Error mixer_error;
- ao.mixer = audio_output_load_mixer(event_loop, ao, param,
+ ao.mixer = audio_output_load_mixer(event_loop, ao, block,
ao.plugin.mixer_plugin,
*ao.filter,
mixer_listener,
@@ -275,7 +280,7 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
/* the "convert" filter must be the last one in the chain */
- ao.convert_filter = filter_new(&convert_filter_plugin, config_param(),
+ ao.convert_filter = filter_new(&convert_filter_plugin, ConfigBlock(),
IgnoreError());
assert(ao.convert_filter != nullptr);
@@ -285,17 +290,17 @@ audio_output_setup(EventLoop &event_loop, AudioOutput &ao,
}
AudioOutput *
-audio_output_new(EventLoop &event_loop, const config_param &param,
+audio_output_new(EventLoop &event_loop, const ConfigBlock &block,
MixerListener &mixer_listener,
PlayerControl &pc,
Error &error)
{
const AudioOutputPlugin *plugin;
- if (!param.IsNull()) {
+ if (!block.IsNull()) {
const char *p;
- p = param.GetBlockValue(AUDIO_OUTPUT_TYPE);
+ p = block.GetBlockValue(AUDIO_OUTPUT_TYPE);
if (p == nullptr) {
error.Set(config_domain,
"Missing \"type\" configuration");
@@ -321,12 +326,12 @@ audio_output_new(EventLoop &event_loop, const config_param &param,
plugin->name);
}
- AudioOutput *ao = ao_plugin_init(plugin, param, error);
+ AudioOutput *ao = ao_plugin_init(plugin, block, error);
if (ao == nullptr)
return nullptr;
if (!audio_output_setup(event_loop, *ao, mixer_listener,
- param, error)) {
+ block, error)) {
ao_plugin_finish(ao);
return nullptr;
}
diff --git a/src/output/Internal.hxx b/src/output/Internal.hxx
index 6e6ffb442..6b67a8783 100644
--- a/src/output/Internal.hxx
+++ b/src/output/Internal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,36 +36,36 @@ class EventLoop;
class Mixer;
class MixerListener;
struct MusicChunk;
-struct config_param;
+struct ConfigBlock;
struct PlayerControl;
struct AudioOutputPlugin;
-enum audio_output_command {
- AO_COMMAND_NONE = 0,
- AO_COMMAND_ENABLE,
- AO_COMMAND_DISABLE,
- AO_COMMAND_OPEN,
+struct AudioOutput {
+ enum class Command {
+ NONE,
+ ENABLE,
+ DISABLE,
+ OPEN,
- /**
- * This command is invoked when the input audio format
- * changes.
- */
- AO_COMMAND_REOPEN,
+ /**
+ * This command is invoked when the input audio format
+ * changes.
+ */
+ REOPEN,
- AO_COMMAND_CLOSE,
- AO_COMMAND_PAUSE,
+ CLOSE,
+ PAUSE,
- /**
- * Drains the internal (hardware) buffers of the device. This
- * operation may take a while to complete.
- */
- AO_COMMAND_DRAIN,
+ /**
+ * Drains the internal (hardware) buffers of the device. This
+ * operation may take a while to complete.
+ */
+ DRAIN,
- AO_COMMAND_CANCEL,
- AO_COMMAND_KILL
-};
+ CANCEL,
+ KILL
+ };
-struct AudioOutput {
/**
* The device's configured display name.
*/
@@ -231,7 +231,7 @@ struct AudioOutput {
/**
* The next command to be performed by the output thread.
*/
- enum audio_output_command command;
+ Command command;
/**
* The music pipe which provides music chunks to be played.
@@ -272,7 +272,7 @@ struct AudioOutput {
AudioOutput(const AudioOutputPlugin &_plugin);
~AudioOutput();
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
void StartThread();
void StopThread();
@@ -284,7 +284,7 @@ struct AudioOutput {
}
bool IsCommandFinished() const {
- return command == AO_COMMAND_NONE;
+ return command == Command::NONE;
}
/**
@@ -299,7 +299,7 @@ struct AudioOutput {
*
* Caller must lock the mutex.
*/
- void CommandAsync(audio_output_command cmd);
+ void CommandAsync(Command cmd);
/**
* Sends a command to the #AudioOutput object and waits for
@@ -307,13 +307,13 @@ struct AudioOutput {
*
* Caller must lock the mutex.
*/
- void CommandWait(audio_output_command cmd);
+ void CommandWait(Command cmd);
/**
* Lock the #AudioOutput object and execute the command
* synchronously.
*/
- void LockCommandWait(audio_output_command cmd);
+ void LockCommandWait(Command cmd);
/**
* Enables the device.
@@ -382,6 +382,13 @@ private:
void Close(bool drain);
void Reopen();
+ /**
+ * Close the output plugin.
+ *
+ * Mutex must not be locked.
+ */
+ void CloseOutput(bool drain);
+
AudioFormat OpenFilter(AudioFormat &format, Error &error_r);
/**
@@ -430,7 +437,7 @@ private:
extern struct notify audio_output_client_notify;
AudioOutput *
-audio_output_new(EventLoop &event_loop, const config_param &param,
+audio_output_new(EventLoop &event_loop, const ConfigBlock &block,
MixerListener &mixer_listener,
PlayerControl &pc,
Error &error);
diff --git a/src/output/MultipleOutputs.cxx b/src/output/MultipleOutputs.cxx
index 33ab57894..fc8b3888b 100644
--- a/src/output/MultipleOutputs.cxx
+++ b/src/output/MultipleOutputs.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "MultipleOutputs.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "Internal.hxx"
#include "Domain.hxx"
#include "MusicBuffer.hxx"
@@ -27,7 +27,7 @@
#include "MusicChunk.hxx"
#include "system/FatalError.hxx"
#include "util/Error.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "notify.hxx"
@@ -53,16 +53,16 @@ MultipleOutputs::~MultipleOutputs()
static AudioOutput *
LoadOutput(EventLoop &event_loop, MixerListener &mixer_listener,
- PlayerControl &pc, const config_param &param)
+ PlayerControl &pc, const ConfigBlock &block)
{
Error error;
- AudioOutput *output = audio_output_new(event_loop, param,
+ AudioOutput *output = audio_output_new(event_loop, block,
mixer_listener,
pc, error);
if (output == nullptr) {
- if (param.line > 0)
+ if (block.line > 0)
FormatFatalError("line %i: %s",
- param.line,
+ block.line,
error.GetMessage());
else
FatalError(error);
@@ -74,7 +74,7 @@ LoadOutput(EventLoop &event_loop, MixerListener &mixer_listener,
void
MultipleOutputs::Configure(EventLoop &event_loop, PlayerControl &pc)
{
- for (const config_param *param = config_get_param(CONF_AUDIO_OUTPUT);
+ for (const auto *param = config_get_block(ConfigBlockOption::AUDIO_OUTPUT);
param != nullptr; param = param->next) {
auto output = LoadOutput(event_loop, mixer_listener,
pc, *param);
@@ -87,7 +87,7 @@ MultipleOutputs::Configure(EventLoop &event_loop, PlayerControl &pc)
if (outputs.empty()) {
/* auto-detect device */
- const config_param empty;
+ const ConfigBlock empty;
auto output = LoadOutput(event_loop, mixer_listener,
pc, empty);
outputs.push_back(output);
diff --git a/src/output/MultipleOutputs.hxx b/src/output/MultipleOutputs.hxx
index 2c6536e2a..8b8360501 100644
--- a/src/output/MultipleOutputs.hxx
+++ b/src/output/MultipleOutputs.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -120,7 +120,7 @@ public:
* Opens all audio outputs which are not disabled.
*
* @param audio_format the preferred audio format
- * @param buffer the #music_buffer where consumed #MusicChunk objects
+ * @param _buffer the #music_buffer where consumed #MusicChunk objects
* should be returned
* @return true on success, false on failure
*/
diff --git a/src/output/OutputAPI.hxx b/src/output/OutputAPI.hxx
index e0fd6eec8..af3f90344 100644
--- a/src/output/OutputAPI.hxx
+++ b/src/output/OutputAPI.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#include "Internal.hxx"
#include "AudioFormat.hxx"
#include "tag/Tag.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
// IWYU pragma: end_exports
diff --git a/src/output/OutputCommand.cxx b/src/output/OutputCommand.cxx
index e6b8a8e7f..dc7a540a2 100644
--- a/src/output/OutputCommand.cxx
+++ b/src/output/OutputCommand.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,7 +28,7 @@
#include "OutputCommand.hxx"
#include "MultipleOutputs.hxx"
#include "Internal.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "mixer/MixerControl.hxx"
#include "mixer/Volume.hxx"
#include "Idle.hxx"
diff --git a/src/output/OutputCommand.hxx b/src/output/OutputCommand.hxx
index 53fc5c95e..5b53cd1c2 100644
--- a/src/output/OutputCommand.hxx
+++ b/src/output/OutputCommand.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/OutputControl.cxx b/src/output/OutputControl.cxx
index 9eafdb166..d7a114c01 100644
--- a/src/output/OutputControl.cxx
+++ b/src/output/OutputControl.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -46,7 +46,7 @@ AudioOutput::WaitForCommand()
}
void
-AudioOutput::CommandAsync(audio_output_command cmd)
+AudioOutput::CommandAsync(Command cmd)
{
assert(IsCommandFinished());
@@ -55,14 +55,14 @@ AudioOutput::CommandAsync(audio_output_command cmd)
}
void
-AudioOutput::CommandWait(audio_output_command cmd)
+AudioOutput::CommandWait(Command cmd)
{
CommandAsync(cmd);
WaitForCommand();
}
void
-AudioOutput::LockCommandWait(audio_output_command cmd)
+AudioOutput::LockCommandWait(Command cmd)
{
const ScopeLock protect(mutex);
CommandWait(cmd);
@@ -92,7 +92,7 @@ AudioOutput::LockEnableWait()
StartThread();
}
- LockCommandWait(AO_COMMAND_ENABLE);
+ LockCommandWait(Command::ENABLE);
}
void
@@ -109,7 +109,7 @@ AudioOutput::LockDisableWait()
return;
}
- LockCommandWait(AO_COMMAND_DISABLE);
+ LockCommandWait(Command::DISABLE);
}
inline bool
@@ -134,7 +134,7 @@ AudioOutput::Open(const AudioFormat audio_format, const MusicPipe &mp)
/* we're not using audio_output_cancel() here,
because that function is asynchronous */
- CommandWait(AO_COMMAND_CANCEL);
+ CommandWait(Command::CANCEL);
}
return true;
@@ -148,7 +148,9 @@ AudioOutput::Open(const AudioFormat audio_format, const MusicPipe &mp)
if (!thread.IsDefined())
StartThread();
- CommandWait(open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN);
+ CommandWait(open
+ ? Command::REOPEN
+ : Command::OPEN);
const bool open2 = open;
if (open2 && mixer != nullptr) {
@@ -172,7 +174,7 @@ AudioOutput::CloseWait()
assert(!open || !fail_timer.IsDefined());
if (open)
- CommandWait(AO_COMMAND_CLOSE);
+ CommandWait(Command::CLOSE);
else
fail_timer.Reset();
}
@@ -220,7 +222,7 @@ AudioOutput::LockPauseAsync()
assert(allow_play);
if (IsOpen())
- CommandAsync(AO_COMMAND_PAUSE);
+ CommandAsync(Command::PAUSE);
}
void
@@ -230,7 +232,7 @@ AudioOutput::LockDrainAsync()
assert(allow_play);
if (IsOpen())
- CommandAsync(AO_COMMAND_DRAIN);
+ CommandAsync(Command::DRAIN);
}
void
@@ -240,7 +242,7 @@ AudioOutput::LockCancelAsync()
if (IsOpen()) {
allow_play = false;
- CommandAsync(AO_COMMAND_CANCEL);
+ CommandAsync(Command::CANCEL);
}
}
@@ -278,7 +280,7 @@ AudioOutput::StopThread()
assert(thread.IsDefined());
assert(allow_play);
- LockCommandWait(AO_COMMAND_KILL);
+ LockCommandWait(Command::KILL);
thread.Join();
}
diff --git a/src/output/OutputControl.hxx b/src/output/OutputControl.hxx
index fff3fe406..5c8f49718 100644
--- a/src/output/OutputControl.hxx
+++ b/src/output/OutputControl.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/OutputPlugin.cxx b/src/output/OutputPlugin.cxx
index 33bb854d4..7d95ef345 100644
--- a/src/output/OutputPlugin.cxx
+++ b/src/output/OutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,13 +23,13 @@
AudioOutput *
ao_plugin_init(const AudioOutputPlugin *plugin,
- const config_param &param,
+ const ConfigBlock &block,
Error &error)
{
assert(plugin != nullptr);
assert(plugin->init != nullptr);
- return plugin->init(param, error);
+ return plugin->init(block, error);
}
void
@@ -75,7 +75,7 @@ ao_plugin_delay(AudioOutput *ao)
}
void
-ao_plugin_send_tag(AudioOutput *ao, const Tag *tag)
+ao_plugin_send_tag(AudioOutput *ao, const Tag &tag)
{
if (ao->plugin.send_tag != nullptr)
ao->plugin.send_tag(ao, tag);
diff --git a/src/output/OutputPlugin.hxx b/src/output/OutputPlugin.hxx
index 00fa36bc0..2f6869368 100644
--- a/src/output/OutputPlugin.hxx
+++ b/src/output/OutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,7 +24,7 @@
#include <stddef.h>
-struct config_param;
+struct ConfigBlock;
struct AudioFormat;
struct Tag;
struct AudioOutput;
@@ -44,7 +44,7 @@ struct AudioOutputPlugin {
* Test if this plugin can provide a default output, in case
* none has been configured. This method is optional.
*/
- bool (*test_default_device)(void);
+ bool (*test_default_device)();
/**
* Configure and initialize the device, but do not open it
@@ -55,8 +55,7 @@ struct AudioOutputPlugin {
* @return nullptr on error, or an opaque pointer to the plugin's
* data
*/
- AudioOutput *(*init)(const config_param &param,
- Error &error);
+ AudioOutput *(*init)(const ConfigBlock &block, Error &error);
/**
* Free resources allocated by this device.
@@ -107,7 +106,7 @@ struct AudioOutputPlugin {
* Display metadata for the next chunk. Optional method,
* because not all devices can display metadata.
*/
- void (*send_tag)(AudioOutput *data, const Tag *tag);
+ void (*send_tag)(AudioOutput *data, const Tag &tag);
/**
* Play a chunk of audio data.
@@ -162,7 +161,7 @@ ao_plugin_test_default_device(const AudioOutputPlugin *plugin)
gcc_malloc
AudioOutput *
ao_plugin_init(const AudioOutputPlugin *plugin,
- const config_param &param,
+ const ConfigBlock &block,
Error &error);
void
@@ -186,7 +185,7 @@ unsigned
ao_plugin_delay(AudioOutput *ao);
void
-ao_plugin_send_tag(AudioOutput *ao, const Tag *tag);
+ao_plugin_send_tag(AudioOutput *ao, const Tag &tag);
size_t
ao_plugin_play(AudioOutput *ao, const void *chunk, size_t size,
diff --git a/src/output/OutputPrint.cxx b/src/output/OutputPrint.cxx
index 414a86e32..d2ddbbf8b 100644
--- a/src/output/OutputPrint.cxx
+++ b/src/output/OutputPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,18 +26,17 @@
#include "OutputPrint.hxx"
#include "MultipleOutputs.hxx"
#include "Internal.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
void
-printAudioDevices(Client &client, const MultipleOutputs &outputs)
+printAudioDevices(Response &r, const MultipleOutputs &outputs)
{
for (unsigned i = 0, n = outputs.Size(); i != n; ++i) {
const AudioOutput &ao = outputs.Get(i);
- client_printf(client,
- "outputid: %i\n"
- "outputname: %s\n"
- "outputenabled: %i\n",
- i, ao.name, ao.enabled);
+ r.Format("outputid: %i\n"
+ "outputname: %s\n"
+ "outputenabled: %i\n",
+ i, ao.name, ao.enabled);
}
}
diff --git a/src/output/OutputPrint.hxx b/src/output/OutputPrint.hxx
index 29aa2b11c..e05c8efd5 100644
--- a/src/output/OutputPrint.hxx
+++ b/src/output/OutputPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,10 +25,10 @@
#ifndef MPD_OUTPUT_PRINT_HXX
#define MPD_OUTPUT_PRINT_HXX
-class Client;
+class Response;
class MultipleOutputs;
void
-printAudioDevices(Client &client, const MultipleOutputs &outputs);
+printAudioDevices(Response &r, const MultipleOutputs &outputs);
#endif
diff --git a/src/output/OutputState.cxx b/src/output/OutputState.cxx
index fb01b1c65..a1ca11b49 100644
--- a/src/output/OutputState.cxx
+++ b/src/output/OutputState.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/OutputState.hxx b/src/output/OutputState.hxx
index 47f8429d5..45076d59f 100644
--- a/src/output/OutputState.hxx
+++ b/src/output/OutputState.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -41,6 +41,6 @@ audio_output_state_save(BufferedOutputStream &os,
* whether the state has changed and the state file should be saved.
*/
unsigned
-audio_output_state_get_version(void);
+audio_output_state_get_version();
#endif
diff --git a/src/output/OutputThread.cxx b/src/output/OutputThread.cxx
index 2ec0670c1..67205aa4c 100644
--- a/src/output/OutputThread.cxx
+++ b/src/output/OutputThread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
#include "filter/FilterInternal.hxx"
#include "filter/plugins/ConvertFilterPlugin.hxx"
#include "filter/plugins/ReplayGainFilterPlugin.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "MusicPipe.hxx"
#include "MusicChunk.hxx"
#include "thread/Util.hxx"
@@ -45,8 +45,8 @@
void
AudioOutput::CommandFinished()
{
- assert(command != AO_COMMAND_NONE);
- command = AO_COMMAND_NONE;
+ assert(command != Command::NONE);
+ command = Command::NONE;
mutex.unlock();
audio_output_client_notify.Signal();
@@ -251,12 +251,7 @@ AudioOutput::Close(bool drain)
mutex.unlock();
- if (drain)
- ao_plugin_drain(this);
- else
- ao_plugin_cancel(this);
-
- ao_plugin_close(this);
+ CloseOutput(drain);
CloseFilter();
mutex.lock();
@@ -265,6 +260,17 @@ AudioOutput::Close(bool drain)
plugin.name, name);
}
+inline void
+AudioOutput::CloseOutput(bool drain)
+{
+ if (drain)
+ ao_plugin_drain(this);
+ else
+ ao_plugin_cancel(this);
+
+ ao_plugin_close(this);
+}
+
void
AudioOutput::ReopenFilter()
{
@@ -342,7 +348,7 @@ AudioOutput::WaitForDelay()
(void)cond.timed_wait(mutex, delay);
- if (command != AO_COMMAND_NONE)
+ if (command != Command::NONE)
return false;
}
}
@@ -455,7 +461,7 @@ AudioOutput::PlayChunk(const MusicChunk *chunk)
if (tags && gcc_unlikely(chunk->tag != nullptr)) {
mutex.unlock();
- ao_plugin_send_tag(this, chunk->tag);
+ ao_plugin_send_tag(this, *chunk->tag);
mutex.lock();
}
@@ -471,7 +477,7 @@ AudioOutput::PlayChunk(const MusicChunk *chunk)
Error error;
- while (!data.IsEmpty() && command == AO_COMMAND_NONE) {
+ while (!data.IsEmpty() && command == Command::NONE) {
if (!WaitForDelay())
break;
@@ -529,7 +535,7 @@ AudioOutput::Play()
assert(!in_playback_loop);
in_playback_loop = true;
- while (chunk != nullptr && command == AO_COMMAND_NONE) {
+ while (chunk != nullptr && command == Command::NONE) {
assert(!current_chunk_finished);
current_chunk = chunk;
@@ -577,7 +583,7 @@ AudioOutput::Pause()
Close(false);
break;
}
- } while (command == AO_COMMAND_NONE);
+ } while (command == Command::NONE);
pause = false;
}
@@ -594,30 +600,30 @@ AudioOutput::Task()
while (1) {
switch (command) {
- case AO_COMMAND_NONE:
+ case Command::NONE:
break;
- case AO_COMMAND_ENABLE:
+ case Command::ENABLE:
Enable();
CommandFinished();
break;
- case AO_COMMAND_DISABLE:
+ case Command::DISABLE:
Disable();
CommandFinished();
break;
- case AO_COMMAND_OPEN:
+ case Command::OPEN:
Open();
CommandFinished();
break;
- case AO_COMMAND_REOPEN:
+ case Command::REOPEN:
Reopen();
CommandFinished();
break;
- case AO_COMMAND_CLOSE:
+ case Command::CLOSE:
assert(open);
assert(pipe != nullptr);
@@ -625,7 +631,7 @@ AudioOutput::Task()
CommandFinished();
break;
- case AO_COMMAND_PAUSE:
+ case Command::PAUSE:
if (!open) {
/* the output has failed after
audio_output_all_pause() has
@@ -642,7 +648,7 @@ AudioOutput::Task()
the new command first */
continue;
- case AO_COMMAND_DRAIN:
+ case Command::DRAIN:
if (open) {
assert(current_chunk == nullptr);
assert(pipe->Peek() == nullptr);
@@ -655,7 +661,7 @@ AudioOutput::Task()
CommandFinished();
continue;
- case AO_COMMAND_CANCEL:
+ case Command::CANCEL:
current_chunk = nullptr;
if (open) {
@@ -667,7 +673,7 @@ AudioOutput::Task()
CommandFinished();
continue;
- case AO_COMMAND_KILL:
+ case Command::KILL:
current_chunk = nullptr;
CommandFinished();
mutex.unlock();
@@ -679,7 +685,7 @@ AudioOutput::Task()
chunks in the pipe */
continue;
- if (command == AO_COMMAND_NONE) {
+ if (command == Command::NONE) {
woken_for_play = false;
cond.wait(mutex);
}
@@ -696,7 +702,7 @@ AudioOutput::Task(void *arg)
void
AudioOutput::StartThread()
{
- assert(command == AO_COMMAND_NONE);
+ assert(command == Command::NONE);
Error error;
if (!thread.Start(Task, this, error))
diff --git a/src/output/Registry.cxx b/src/output/Registry.cxx
index 566f6b6a8..b1734983e 100644
--- a/src/output/Registry.cxx
+++ b/src/output/Registry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "plugins/AoOutputPlugin.hxx"
#include "plugins/FifoOutputPlugin.hxx"
#include "plugins/httpd/HttpdOutputPlugin.hxx"
+#include "plugins/HaikuOutputPlugin.hxx"
#include "plugins/JackOutputPlugin.hxx"
#include "plugins/NullOutputPlugin.hxx"
#include "plugins/OpenALOutputPlugin.hxx"
@@ -51,16 +52,19 @@ const AudioOutputPlugin *const audio_output_plugins[] = {
#ifdef HAVE_FIFO
&fifo_output_plugin,
#endif
+#ifdef HAVE_HAIKU
+ &haiku_output_plugin,
+#endif
#ifdef ENABLE_PIPE_OUTPUT
&pipe_output_plugin,
#endif
-#ifdef HAVE_ALSA
+#ifdef ENABLE_ALSA
&alsa_output_plugin,
#endif
-#ifdef HAVE_ROAR
+#ifdef ENABLE_ROAR
&roar_output_plugin,
#endif
-#ifdef HAVE_AO
+#ifdef ENABLE_AO
&ao_output_plugin,
#endif
#ifdef HAVE_OSS
@@ -75,10 +79,10 @@ const AudioOutputPlugin *const audio_output_plugins[] = {
#ifdef ENABLE_SOLARIS_OUTPUT
&solaris_output_plugin,
#endif
-#ifdef HAVE_PULSE
+#ifdef ENABLE_PULSE
&pulse_output_plugin,
#endif
-#ifdef HAVE_JACK
+#ifdef ENABLE_JACK
&jack_output_plugin,
#endif
#ifdef ENABLE_HTTPD_OUTPUT
diff --git a/src/output/Registry.hxx b/src/output/Registry.hxx
index bc9c1ae2b..2c7202a75 100644
--- a/src/output/Registry.hxx
+++ b/src/output/Registry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Timer.cxx b/src/output/Timer.cxx
index d3dcc714d..a75744744 100644
--- a/src/output/Timer.cxx
+++ b/src/output/Timer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Timer.hxx b/src/output/Timer.hxx
index 3c935cfac..057090c1e 100644
--- a/src/output/Timer.hxx
+++ b/src/output/Timer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/Wrapper.hxx b/src/output/Wrapper.hxx
new file mode 100644
index 000000000..c043849bb
--- /dev/null
+++ b/src/output/Wrapper.hxx
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_OUTPUT_WRAPPER_HXX
+#define MPD_OUTPUT_WRAPPER_HXX
+
+#include "util/Cast.hxx"
+
+struct ConfigBlock;
+
+template<class T>
+struct AudioOutputWrapper {
+ static T &Cast(AudioOutput &ao) {
+ return ContainerCast(ao, &T::base);
+ }
+
+ static AudioOutput *Init(const ConfigBlock &block, Error &error) {
+ T *t = T::Create(block, error);
+ return t != nullptr
+ ? &t->base
+ : nullptr;
+ }
+
+ static void Finish(AudioOutput *ao) {
+ T *t = &Cast(*ao);
+ delete t;
+ }
+
+ static bool Enable(AudioOutput *ao, Error &error) {
+ T &t = Cast(*ao);
+ return t.Enable(error);
+ }
+
+ static void Disable(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ t.Disable();
+ }
+
+ static bool Open(AudioOutput *ao, AudioFormat &audio_format,
+ Error &error) {
+ T &t = Cast(*ao);
+ return t.Open(audio_format, error);
+ }
+
+ static void Close(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ t.Close();
+ }
+
+ gcc_pure
+ static unsigned Delay(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ return t.Delay();
+ }
+
+ gcc_pure
+ static void SendTag(AudioOutput *ao, const Tag &tag) {
+ T &t = Cast(*ao);
+ t.SendTag(tag);
+ }
+
+ static size_t Play(AudioOutput *ao, const void *chunk, size_t size,
+ Error &error) {
+ T &t = Cast(*ao);
+ return t.Play(chunk, size, error);
+ }
+
+ static void Drain(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ t.Drain();
+ }
+
+ static void Cancel(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ t.Cancel();
+ }
+
+ gcc_pure
+ static bool Pause(AudioOutput *ao) {
+ T &t = Cast(*ao);
+ return t.Pause();
+ }
+};
+
+#endif
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index 28c374a00..8a7bb9643 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "AlsaOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "pcm/PcmExport.hxx"
#include "config/ConfigError.hxx"
@@ -131,92 +132,108 @@ struct AlsaOutput {
mode(0), writei(snd_pcm_writei) {
}
- bool Configure(const config_param &param, Error &error);
+ ~AlsaOutput() {
+ /* free libasound's config cache */
+ snd_config_update_free_global();
+ }
+
+ gcc_pure
+ const char *GetDevice() {
+ return device.empty() ? default_device : device.c_str();
+ }
+
+ bool Configure(const ConfigBlock &block, Error &error);
+ static AlsaOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Enable(Error &error);
+ void Disable();
+
+ bool Open(AudioFormat &audio_format, Error &error);
+ void Close();
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+ void Drain();
+ void Cancel();
+
+private:
+ bool SetupDop(AudioFormat audio_format,
+ bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
+ Error &error);
+ bool SetupOrDop(AudioFormat &audio_format, Error &error);
+
+ int Recover(int err);
+
+ /**
+ * Write silence to the ALSA device.
+ */
+ void WriteSilence(snd_pcm_uframes_t nframes) {
+ writei(pcm, silence, nframes);
+ }
+
};
static constexpr Domain alsa_output_domain("alsa_output");
-static const char *
-alsa_device(const AlsaOutput *ad)
-{
- return ad->device.empty() ? default_device : ad->device.c_str();
-}
-
inline bool
-AlsaOutput::Configure(const config_param &param, Error &error)
+AlsaOutput::Configure(const ConfigBlock &block, Error &error)
{
- if (!base.Configure(param, error))
+ if (!base.Configure(block, error))
return false;
- device = param.GetBlockValue("device", "");
+ device = block.GetBlockValue("device", "");
- use_mmap = param.GetBlockValue("use_mmap", false);
+ use_mmap = block.GetBlockValue("use_mmap", false);
- dop = param.GetBlockValue("dop", false) ||
+ dop = block.GetBlockValue("dop", false) ||
/* legacy name from MPD 0.18 and older: */
- param.GetBlockValue("dsd_usb", false);
+ block.GetBlockValue("dsd_usb", false);
- buffer_time = param.GetBlockValue("buffer_time",
+ buffer_time = block.GetBlockValue("buffer_time",
MPD_ALSA_BUFFER_TIME_US);
- period_time = param.GetBlockValue("period_time", 0u);
+ period_time = block.GetBlockValue("period_time", 0u);
#ifdef SND_PCM_NO_AUTO_RESAMPLE
- if (!param.GetBlockValue("auto_resample", true))
+ if (!block.GetBlockValue("auto_resample", true))
mode |= SND_PCM_NO_AUTO_RESAMPLE;
#endif
#ifdef SND_PCM_NO_AUTO_CHANNELS
- if (!param.GetBlockValue("auto_channels", true))
+ if (!block.GetBlockValue("auto_channels", true))
mode |= SND_PCM_NO_AUTO_CHANNELS;
#endif
#ifdef SND_PCM_NO_AUTO_FORMAT
- if (!param.GetBlockValue("auto_format", true))
+ if (!block.GetBlockValue("auto_format", true))
mode |= SND_PCM_NO_AUTO_FORMAT;
#endif
return true;
}
-static AudioOutput *
-alsa_init(const config_param &param, Error &error)
+inline AlsaOutput *
+AlsaOutput::Create(const ConfigBlock &block, Error &error)
{
AlsaOutput *ad = new AlsaOutput();
- if (!ad->Configure(param, error)) {
+ if (!ad->Configure(block, error)) {
delete ad;
return nullptr;
}
- return &ad->base;
+ return ad;
}
-static void
-alsa_finish(AudioOutput *ao)
-{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- delete ad;
-
- /* free libasound's config cache */
- snd_config_update_free_global();
-}
-
-static bool
-alsa_output_enable(AudioOutput *ao, gcc_unused Error &error)
+inline bool
+AlsaOutput::Enable(gcc_unused Error &error)
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- ad->pcm_export.Construct();
+ pcm_export.Construct();
return true;
}
-static void
-alsa_output_disable(AudioOutput *ao)
+inline void
+AlsaOutput::Disable()
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- ad->pcm_export.Destruct();
+ pcm_export.Destruct();
}
static bool
@@ -450,7 +467,7 @@ configure_hw:
if (err < 0) {
FormatWarning(alsa_output_domain,
"Cannot set mmap'ed mode on ALSA device \"%s\": %s",
- alsa_device(ad), snd_strerror(-err));
+ ad->GetDevice(), snd_strerror(-err));
LogWarning(alsa_output_domain,
"Falling back to direct write mode");
ad->use_mmap = false;
@@ -472,7 +489,7 @@ configure_hw:
if (err < 0) {
error.Format(alsa_output_domain, err,
"ALSA device \"%s\" does not support format %s: %s",
- alsa_device(ad),
+ ad->GetDevice(),
sample_format_to_string(audio_format.format),
snd_strerror(-err));
return false;
@@ -489,7 +506,7 @@ configure_hw:
if (err < 0) {
error.Format(alsa_output_domain, err,
"ALSA device \"%s\" does not support %i channels: %s",
- alsa_device(ad), (int)audio_format.channels,
+ ad->GetDevice(), (int)audio_format.channels,
snd_strerror(-err));
return false;
}
@@ -500,7 +517,7 @@ configure_hw:
if (err < 0 || sample_rate == 0) {
error.Format(alsa_output_domain, err,
"ALSA device \"%s\" does not support %u Hz audio",
- alsa_device(ad), audio_format.sample_rate);
+ ad->GetDevice(), audio_format.sample_rate);
return false;
}
audio_format.sample_rate = sample_rate;
@@ -631,16 +648,16 @@ configure_hw:
error:
error.Format(alsa_output_domain, err,
"Error opening ALSA device \"%s\" (%s): %s",
- alsa_device(ad), cmd, snd_strerror(-err));
+ ad->GetDevice(), cmd, snd_strerror(-err));
return false;
}
-static bool
-alsa_setup_dop(AlsaOutput *ad, const AudioFormat audio_format,
- bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
- Error &error)
+inline bool
+AlsaOutput::SetupDop(const AudioFormat audio_format,
+ bool *shift8_r, bool *packed_r, bool *reverse_endian_r,
+ Error &error)
{
- assert(ad->dop);
+ assert(dop);
assert(audio_format.format == SampleFormat::DSD);
/* pass 24 bit to alsa_setup() */
@@ -651,7 +668,7 @@ alsa_setup_dop(AlsaOutput *ad, const AudioFormat audio_format,
const AudioFormat check = dop_format;
- if (!alsa_setup(ad, dop_format, packed_r, reverse_endian_r, error))
+ if (!alsa_setup(this, dop_format, packed_r, reverse_endian_r, error))
return false;
/* if the device allows only 32 bit, shift all DoP
@@ -668,102 +685,91 @@ alsa_setup_dop(AlsaOutput *ad, const AudioFormat audio_format,
for DSD over USB */
error.Format(alsa_output_domain,
"Failed to configure DSD-over-PCM on ALSA device \"%s\"",
- alsa_device(ad));
- delete[] ad->silence;
+ GetDevice());
+ delete[] silence;
return false;
}
return true;
}
-static bool
-alsa_setup_or_dop(AlsaOutput *ad, AudioFormat &audio_format,
- Error &error)
+inline bool
+AlsaOutput::SetupOrDop(AudioFormat &audio_format, Error &error)
{
bool shift8 = false, packed, reverse_endian;
- const bool dop = ad->dop &&
+ const bool dop2 = dop &&
audio_format.format == SampleFormat::DSD;
- const bool success = dop
- ? alsa_setup_dop(ad, audio_format,
- &shift8, &packed, &reverse_endian,
- error)
- : alsa_setup(ad, audio_format, &packed, &reverse_endian,
+ const bool success = dop2
+ ? SetupDop(audio_format,
+ &shift8, &packed, &reverse_endian,
+ error)
+ : alsa_setup(this, audio_format, &packed, &reverse_endian,
error);
if (!success)
return false;
- ad->pcm_export->Open(audio_format.format,
- audio_format.channels,
- dop, shift8, packed, reverse_endian);
+ pcm_export->Open(audio_format.format,
+ audio_format.channels,
+ dop2, shift8, packed, reverse_endian);
return true;
}
-static bool
-alsa_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
+inline bool
+AlsaOutput::Open(AudioFormat &audio_format, Error &error)
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- int err = snd_pcm_open(&ad->pcm, alsa_device(ad),
- SND_PCM_STREAM_PLAYBACK, ad->mode);
+ int err = snd_pcm_open(&pcm, GetDevice(),
+ SND_PCM_STREAM_PLAYBACK, mode);
if (err < 0) {
error.Format(alsa_output_domain, err,
"Failed to open ALSA device \"%s\": %s",
- alsa_device(ad), snd_strerror(err));
+ GetDevice(), snd_strerror(err));
return false;
}
FormatDebug(alsa_output_domain, "opened %s type=%s",
- snd_pcm_name(ad->pcm),
- snd_pcm_type_name(snd_pcm_type(ad->pcm)));
+ snd_pcm_name(pcm),
+ snd_pcm_type_name(snd_pcm_type(pcm)));
- if (!alsa_setup_or_dop(ad, audio_format, error)) {
- snd_pcm_close(ad->pcm);
+ if (!SetupOrDop(audio_format, error)) {
+ snd_pcm_close(pcm);
return false;
}
- ad->in_frame_size = audio_format.GetFrameSize();
- ad->out_frame_size = ad->pcm_export->GetFrameSize(audio_format);
+ in_frame_size = audio_format.GetFrameSize();
+ out_frame_size = pcm_export->GetFrameSize(audio_format);
- ad->must_prepare = false;
+ must_prepare = false;
return true;
}
-/**
- * Write silence to the ALSA device.
- */
-static void
-alsa_write_silence(AlsaOutput *ad, snd_pcm_uframes_t nframes)
-{
- ad->writei(ad->pcm, ad->silence, nframes);
-}
-
-static int
-alsa_recover(AlsaOutput *ad, int err)
+inline int
+AlsaOutput::Recover(int err)
{
if (err == -EPIPE) {
FormatDebug(alsa_output_domain,
- "Underrun on ALSA device \"%s\"", alsa_device(ad));
+ "Underrun on ALSA device \"%s\"",
+ GetDevice());
} else if (err == -ESTRPIPE) {
FormatDebug(alsa_output_domain,
"ALSA device \"%s\" was suspended",
- alsa_device(ad));
+ GetDevice());
}
- switch (snd_pcm_state(ad->pcm)) {
+ switch (snd_pcm_state(pcm)) {
case SND_PCM_STATE_PAUSED:
- err = snd_pcm_pause(ad->pcm, /* disable */ 0);
+ err = snd_pcm_pause(pcm, /* disable */ 0);
break;
case SND_PCM_STATE_SUSPENDED:
- err = snd_pcm_resume(ad->pcm);
+ err = snd_pcm_resume(pcm);
if (err == -EAGAIN)
return 0;
/* fall-through to snd_pcm_prepare: */
case SND_PCM_STATE_SETUP:
case SND_PCM_STATE_XRUN:
- ad->period_position = 0;
- err = snd_pcm_prepare(ad->pcm);
+ period_position = 0;
+ err = snd_pcm_prepare(pcm);
break;
case SND_PCM_STATE_DISCONNECTED:
break;
@@ -779,67 +785,58 @@ alsa_recover(AlsaOutput *ad, int err)
return err;
}
-static void
-alsa_drain(AudioOutput *ao)
+inline void
+AlsaOutput::Drain()
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- if (snd_pcm_state(ad->pcm) != SND_PCM_STATE_RUNNING)
+ if (snd_pcm_state(pcm) != SND_PCM_STATE_RUNNING)
return;
- if (ad->period_position > 0) {
+ if (period_position > 0) {
/* generate some silence to finish the partial
period */
snd_pcm_uframes_t nframes =
- ad->period_frames - ad->period_position;
- alsa_write_silence(ad, nframes);
+ period_frames - period_position;
+ WriteSilence(nframes);
}
- snd_pcm_drain(ad->pcm);
+ snd_pcm_drain(pcm);
- ad->period_position = 0;
+ period_position = 0;
}
-static void
-alsa_cancel(AudioOutput *ao)
+inline void
+AlsaOutput::Cancel()
{
- AlsaOutput *ad = (AlsaOutput *)ao;
+ period_position = 0;
+ must_prepare = true;
- ad->period_position = 0;
- ad->must_prepare = true;
-
- snd_pcm_drop(ad->pcm);
+ snd_pcm_drop(pcm);
}
-static void
-alsa_close(AudioOutput *ao)
+inline void
+AlsaOutput::Close()
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
- snd_pcm_close(ad->pcm);
- delete[] ad->silence;
+ snd_pcm_close(pcm);
+ delete[] silence;
}
-static size_t
-alsa_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+AlsaOutput::Play(const void *chunk, size_t size, Error &error)
{
- AlsaOutput *ad = (AlsaOutput *)ao;
-
assert(size > 0);
- assert(size % ad->in_frame_size == 0);
+ assert(size % in_frame_size == 0);
- if (ad->must_prepare) {
- ad->must_prepare = false;
+ if (must_prepare) {
+ must_prepare = false;
- int err = snd_pcm_prepare(ad->pcm);
+ int err = snd_pcm_prepare(pcm);
if (err < 0) {
error.Set(alsa_output_domain, err, snd_strerror(-err));
return 0;
}
}
- const auto e = ad->pcm_export->Export({chunk, size});
+ const auto e = pcm_export->Export({chunk, size});
if (e.size == 0)
/* the DoP (DSD over PCM) filter converts two frames
at a time and ignores the last odd frame; if there
@@ -852,43 +849,45 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size,
chunk = e.data;
size = e.size;
- assert(size % ad->out_frame_size == 0);
+ assert(size % out_frame_size == 0);
- size /= ad->out_frame_size;
+ size /= out_frame_size;
assert(size > 0);
while (true) {
- snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size);
+ snd_pcm_sframes_t ret = writei(pcm, chunk, size);
if (ret > 0) {
- ad->period_position = (ad->period_position + ret)
- % ad->period_frames;
+ period_position = (period_position + ret)
+ % period_frames;
- size_t bytes_written = ret * ad->out_frame_size;
- return ad->pcm_export->CalcSourceSize(bytes_written);
+ size_t bytes_written = ret * out_frame_size;
+ return pcm_export->CalcSourceSize(bytes_written);
}
if (ret < 0 && ret != -EAGAIN && ret != -EINTR &&
- alsa_recover(ad, ret) < 0) {
+ Recover(ret) < 0) {
error.Set(alsa_output_domain, ret, snd_strerror(-ret));
return 0;
}
}
}
+typedef AudioOutputWrapper<AlsaOutput> Wrapper;
+
const struct AudioOutputPlugin alsa_output_plugin = {
"alsa",
alsa_test_default_device,
- alsa_init,
- alsa_finish,
- alsa_output_enable,
- alsa_output_disable,
- alsa_open,
- alsa_close,
+ &Wrapper::Init,
+ &Wrapper::Finish,
+ &Wrapper::Enable,
+ &Wrapper::Disable,
+ &Wrapper::Open,
+ &Wrapper::Close,
nullptr,
nullptr,
- alsa_play,
- alsa_drain,
- alsa_cancel,
+ &Wrapper::Play,
+ &Wrapper::Drain,
+ &Wrapper::Cancel,
nullptr,
&alsa_mixer_plugin,
diff --git a/src/output/plugins/AlsaOutputPlugin.hxx b/src/output/plugins/AlsaOutputPlugin.hxx
index f72116f91..ff7d439a9 100644
--- a/src/output/plugins/AlsaOutputPlugin.hxx
+++ b/src/output/plugins/AlsaOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/AoOutputPlugin.cxx b/src/output/plugins/AoOutputPlugin.cxx
index af8c88fa1..3c0cf74a4 100644
--- a/src/output/plugins/AoOutputPlugin.cxx
+++ b/src/output/plugins/AoOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,12 +20,13 @@
#include "config.h"
#include "AoOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "util/DivideString.hxx"
+#include "util/SplitString.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
#include <ao/ao.h>
-#include <glib.h>
#include <string.h>
@@ -45,11 +46,11 @@ struct AoOutput {
AoOutput()
:base(ao_output_plugin) {}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
};
static constexpr Domain ao_output_domain("ao_output");
@@ -89,20 +90,20 @@ ao_output_error(Error &error_r)
}
inline bool
-AoOutput::Configure(const config_param &param, Error &error)
+AoOutput::Configure(const ConfigBlock &block, Error &error)
{
const char *value;
options = nullptr;
- write_size = param.GetBlockValue("write_size", 1024u);
+ write_size = block.GetBlockValue("write_size", 1024u);
if (ao_output_ref == 0) {
ao_initialize();
}
ao_output_ref++;
- value = param.GetBlockValue("driver", "default");
+ value = block.GetBlockValue("driver", "default");
if (0 == strcmp(value, "default"))
driver = ao_default_driver_id();
else
@@ -122,45 +123,38 @@ AoOutput::Configure(const config_param &param, Error &error)
}
FormatDebug(ao_output_domain, "using ao driver \"%s\" for \"%s\"\n",
- ai->short_name, param.GetBlockValue("name", nullptr));
+ ai->short_name, block.GetBlockValue("name", nullptr));
- value = param.GetBlockValue("options", nullptr);
+ value = block.GetBlockValue("options", nullptr);
if (value != nullptr) {
- gchar **_options = g_strsplit(value, ";", 0);
+ for (const auto &i : SplitString(value, ';')) {
+ const DivideString ss(i.c_str(), '=', true);
- for (unsigned i = 0; _options[i] != nullptr; ++i) {
- gchar **key_value = g_strsplit(_options[i], "=", 2);
-
- if (key_value[0] == nullptr || key_value[1] == nullptr) {
+ if (!ss.IsDefined()) {
error.Format(ao_output_domain,
"problems parsing options \"%s\"",
- _options[i]);
+ i.c_str());
return false;
}
- ao_append_option(&options, key_value[0],
- key_value[1]);
-
- g_strfreev(key_value);
+ ao_append_option(&options, ss.GetFirst(), ss.GetSecond());
}
-
- g_strfreev(_options);
}
return true;
}
static AudioOutput *
-ao_output_init(const config_param &param, Error &error)
+ao_output_init(const ConfigBlock &block, Error &error)
{
AoOutput *ad = new AoOutput();
- if (!ad->Initialize(param, error)) {
+ if (!ad->Initialize(block, error)) {
delete ad;
return nullptr;
}
- if (!ad->Configure(param, error)) {
+ if (!ad->Configure(block, error)) {
delete ad;
return nullptr;
}
diff --git a/src/output/plugins/AoOutputPlugin.hxx b/src/output/plugins/AoOutputPlugin.hxx
index 07c2ba16b..582070c47 100644
--- a/src/output/plugins/AoOutputPlugin.hxx
+++ b/src/output/plugins/AoOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/FifoOutputPlugin.cxx b/src/output/plugins/FifoOutputPlugin.cxx
index 9df5a74dd..d4019df53 100644
--- a/src/output/plugins/FifoOutputPlugin.cxx
+++ b/src/output/plugins/FifoOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,9 +21,11 @@
#include "FifoOutputPlugin.hxx"
#include "config/ConfigError.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "../Timer.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
@@ -33,9 +35,9 @@
#include <errno.h>
#include <unistd.h>
-#define FIFO_BUFFER_SIZE 65536 /* pipe capacity on Linux >= 2.6.11 */
+class FifoOutput {
+ friend struct AudioOutputWrapper<FifoOutput>;
-struct FifoOutput {
AudioOutput base;
AllocatedPath path;
@@ -46,21 +48,35 @@ struct FifoOutput {
bool created;
Timer *timer;
+public:
FifoOutput()
:base(fifo_output_plugin),
path(AllocatedPath::Null()), input(-1), output(-1),
created(false) {}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ ~FifoOutput() {
+ CloseFifo();
}
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
+ }
+
+ static FifoOutput *Create(const ConfigBlock &block, Error &error);
+
bool Create(Error &error);
bool Check(Error &error);
void Delete();
- bool Open(Error &error);
+ bool OpenFifo(Error &error);
+ void CloseFifo();
+
+ bool Open(AudioFormat &audio_format, Error &error);
void Close();
+
+ unsigned Delay() const;
+ size_t Play(const void *chunk, size_t size, Error &error);
+ void Cancel();
};
static constexpr Domain fifo_output_domain("fifo_output");
@@ -82,7 +98,7 @@ FifoOutput::Delete()
}
void
-FifoOutput::Close()
+FifoOutput::CloseFifo()
{
if (input >= 0) {
close(input);
@@ -94,8 +110,8 @@ FifoOutput::Close()
output = -1;
}
- struct stat st;
- if (created && StatFile(path, st))
+ FileInfo fi;
+ if (created && GetFileInfo(path, fi))
Delete();
}
@@ -138,7 +154,7 @@ FifoOutput::Check(Error &error)
}
inline bool
-FifoOutput::Open(Error &error)
+FifoOutput::OpenFifo(Error &error)
{
if (!Check(error))
return false;
@@ -147,7 +163,7 @@ FifoOutput::Open(Error &error)
if (input < 0) {
error.FormatErrno("Could not open FIFO \"%s\" for reading",
path_utf8.c_str());
- Close();
+ CloseFifo();
return false;
}
@@ -155,25 +171,19 @@ FifoOutput::Open(Error &error)
if (output < 0) {
error.FormatErrno("Could not open FIFO \"%s\" for writing",
path_utf8.c_str());
- Close();
+ CloseFifo();
return false;
}
return true;
}
-static bool
-fifo_open(FifoOutput *fd, Error &error)
-{
- return fd->Open(error);
-}
-
-static AudioOutput *
-fifo_output_init(const config_param &param, Error &error)
+inline FifoOutput *
+FifoOutput::Create(const ConfigBlock &block, Error &error)
{
FifoOutput *fd = new FifoOutput();
- fd->path = param.GetBlockPath("path", error);
+ fd->path = block.GetBlockPath("path", error);
if (fd->path.IsNull()) {
delete fd;
@@ -185,89 +195,67 @@ fifo_output_init(const config_param &param, Error &error)
fd->path_utf8 = fd->path.ToUTF8();
- if (!fd->Initialize(param, error)) {
+ if (!fd->Initialize(block, error)) {
delete fd;
return nullptr;
}
- if (!fifo_open(fd, error)) {
+ if (!fd->OpenFifo(error)) {
delete fd;
return nullptr;
}
- return &fd->base;
-}
-
-static void
-fifo_output_finish(AudioOutput *ao)
-{
- FifoOutput *fd = (FifoOutput *)ao;
-
- fd->Close();
- delete fd;
+ return fd;
}
-static bool
-fifo_output_open(AudioOutput *ao, AudioFormat &audio_format,
- gcc_unused Error &error)
+bool
+FifoOutput::Open(AudioFormat &audio_format, gcc_unused Error &error)
{
- FifoOutput *fd = (FifoOutput *)ao;
-
- fd->timer = new Timer(audio_format);
-
+ timer = new Timer(audio_format);
return true;
}
-static void
-fifo_output_close(AudioOutput *ao)
+void
+FifoOutput::Close()
{
- FifoOutput *fd = (FifoOutput *)ao;
-
- delete fd->timer;
+ delete timer;
}
-static void
-fifo_output_cancel(AudioOutput *ao)
+inline void
+FifoOutput::Cancel()
{
- FifoOutput *fd = (FifoOutput *)ao;
- char buf[FIFO_BUFFER_SIZE];
- int bytes = 1;
-
- fd->timer->Reset();
+ timer->Reset();
- while (bytes > 0 && errno != EINTR)
- bytes = read(fd->input, buf, FIFO_BUFFER_SIZE);
+ ssize_t bytes;
+ do {
+ char buffer[16384];
+ bytes = read(input, buffer, sizeof(buffer));
+ } while (bytes > 0 && errno != EINTR);
if (bytes < 0 && errno != EAGAIN) {
FormatErrno(fifo_output_domain,
"Flush of FIFO \"%s\" failed",
- fd->path_utf8.c_str());
+ path_utf8.c_str());
}
}
-static unsigned
-fifo_output_delay(AudioOutput *ao)
+inline unsigned
+FifoOutput::Delay() const
{
- FifoOutput *fd = (FifoOutput *)ao;
-
- return fd->timer->IsStarted()
- ? fd->timer->GetDelay()
+ return timer->IsStarted()
+ ? timer->GetDelay()
: 0;
}
-static size_t
-fifo_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+FifoOutput::Play(const void *chunk, size_t size, Error &error)
{
- FifoOutput *fd = (FifoOutput *)ao;
- ssize_t bytes;
-
- if (!fd->timer->IsStarted())
- fd->timer->Start();
- fd->timer->Add(size);
+ if (!timer->IsStarted())
+ timer->Start();
+ timer->Add(size);
while (true) {
- bytes = write(fd->output, chunk, size);
+ ssize_t bytes = write(output, chunk, size);
if (bytes > 0)
return (size_t)bytes;
@@ -275,33 +263,35 @@ fifo_output_play(AudioOutput *ao, const void *chunk, size_t size,
switch (errno) {
case EAGAIN:
/* The pipe is full, so empty it */
- fifo_output_cancel(&fd->base);
+ Cancel();
continue;
case EINTR:
continue;
}
error.FormatErrno("Failed to write to FIFO %s",
- fd->path_utf8.c_str());
+ path_utf8.c_str());
return 0;
}
}
}
+typedef AudioOutputWrapper<FifoOutput> Wrapper;
+
const struct AudioOutputPlugin fifo_output_plugin = {
"fifo",
nullptr,
- fifo_output_init,
- fifo_output_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
nullptr,
- fifo_output_open,
- fifo_output_close,
- fifo_output_delay,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- fifo_output_play,
+ &Wrapper::Play,
nullptr,
- fifo_output_cancel,
+ &Wrapper::Cancel,
nullptr,
nullptr,
};
diff --git a/src/output/plugins/FifoOutputPlugin.hxx b/src/output/plugins/FifoOutputPlugin.hxx
index f41ceded6..353be51a6 100644
--- a/src/output/plugins/FifoOutputPlugin.hxx
+++ b/src/output/plugins/FifoOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/HaikuOutputPlugin.cxx b/src/output/plugins/HaikuOutputPlugin.cxx
new file mode 100644
index 000000000..e235d595a
--- /dev/null
+++ b/src/output/plugins/HaikuOutputPlugin.cxx
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ * Copyright (C) 2014-2015 François 'mmu_man' Revol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "HaikuOutputPlugin.hxx"
+#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
+#include "mixer/MixerList.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <AppFileInfo.h>
+#include <Application.h>
+#include <Bitmap.h>
+#include <IconUtils.h>
+#include <MediaDefs.h>
+#include <MediaRoster.h>
+#include <Notification.h>
+#include <OS.h>
+#include <Resources.h>
+#include <StringList.h>
+#include <SoundPlayer.h>
+
+#include <string.h>
+
+#define UTF8_PLAY "\xE2\x96\xB6"
+
+class HaikuOutput {
+ friend struct AudioOutputWrapper<HaikuOutput>;
+ friend int haiku_output_get_volume(HaikuOutput &haiku);
+ friend bool haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
+
+ AudioOutput base;
+
+ size_t write_size;
+
+ media_raw_audio_format* format;
+ BSoundPlayer* sound_player;
+
+ sem_id new_buffer;
+ sem_id buffer_done;
+
+ uint8* buffer;
+ size_t buffer_size;
+ size_t buffer_filled;
+
+ unsigned buffer_delay;
+
+public:
+ HaikuOutput()
+ :base(haiku_output_plugin) {}
+ ~HaikuOutput();
+
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
+ }
+
+ static HaikuOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Open(AudioFormat &audio_format, Error &error);
+
+ void Close() {
+ DoClose();
+ }
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+ void Cancel();
+
+ bool Configure(const ConfigBlock &block, Error &error);
+
+ size_t Delay();
+
+ void FillBuffer(void* _buffer, size_t size,
+ gcc_unused const media_raw_audio_format& _format);
+
+ void SendTag(const Tag &tag);
+
+private:
+
+ void DoClose();
+};
+
+static constexpr Domain haiku_output_domain("haiku_output");
+
+static void
+haiku_output_error(Error &error_r, status_t err)
+{
+ const char *error = strerror(err);
+ error_r.Set(haiku_output_domain, err, error);
+}
+
+static void
+initialize_application()
+{
+ // required to send the notification with a bitmap
+ // TODO: actually Run() it and handle B_QUIT_REQUESTED
+ // TODO: use some locking?
+ if (be_app == NULL) {
+ FormatDebug(haiku_output_domain, "creating be_app\n");
+ new BApplication("application/x-vnd.MusicPD");
+ }
+}
+
+static void
+finalize_application()
+{
+ // TODO: use some locking?
+ delete be_app;
+ be_app = NULL;
+ FormatDebug(haiku_output_domain, "deleting be_app\n");
+}
+
+inline bool
+HaikuOutput::Configure(const ConfigBlock &block, Error &error)
+{
+ /* XXX: by default we should let the MediaKit propose the buffer size */
+ write_size = block.GetBlockValue("write_size", 4096u);
+
+ format = (media_raw_audio_format*)malloc(
+ sizeof(media_raw_audio_format));
+ if (format == nullptr) {
+ haiku_output_error(error, B_NO_MEMORY);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+haiku_test_default_device(void)
+{
+ BSoundPlayer testPlayer;
+ return testPlayer.InitCheck() == B_OK;
+
+}
+
+inline HaikuOutput *
+HaikuOutput::Create(const ConfigBlock &block, Error &error)
+{
+ initialize_application();
+
+ HaikuOutput *ad = new HaikuOutput();
+
+ if (!ad->Initialize(block, error)) {
+ delete ad;
+ return nullptr;
+ }
+
+ if (!ad->Configure(block, error)) {
+ delete ad;
+ return nullptr;
+ }
+
+ return ad;
+}
+
+void
+HaikuOutput::DoClose()
+{
+ sound_player->SetHasData(false);
+ delete_sem(new_buffer);
+ delete_sem(buffer_done);
+ sound_player->Stop();
+ delete sound_player;
+ sound_player = nullptr;
+}
+
+
+
+HaikuOutput::~HaikuOutput()
+{
+ free(format);
+ delete_sem(new_buffer);
+ delete_sem(buffer_done);
+
+ finalize_application();
+}
+
+static void
+fill_buffer(void* cookie, void* buffer, size_t size,
+ const media_raw_audio_format& format)
+{
+ HaikuOutput *ad = (HaikuOutput *)cookie;
+ ad->FillBuffer(buffer, size, format);
+}
+
+
+void
+HaikuOutput::FillBuffer(void* _buffer, size_t size,
+ gcc_unused const media_raw_audio_format& _format)
+{
+
+ buffer = (uint8*)_buffer;
+ buffer_size = size;
+ buffer_filled = 0;
+ bigtime_t start = system_time();
+ release_sem(new_buffer);
+ acquire_sem(buffer_done);
+ bigtime_t w = system_time() - start;
+
+ if (w > 5000LL) {
+ FormatDebug(haiku_output_domain,
+ "haiku:fill_buffer waited %Ldus\n", w);
+ }
+
+ if (buffer_filled < buffer_size) {
+ memset(buffer + buffer_filled, 0,
+ buffer_size - buffer_filled);
+ FormatDebug(haiku_output_domain,
+ "haiku:fill_buffer filled %d size %d clearing remainder\n",
+ (int)buffer_filled, (int)buffer_size);
+
+ }
+}
+
+inline bool
+HaikuOutput::Open(AudioFormat &audio_format, Error &error)
+{
+ status_t err;
+ *format = media_multi_audio_format::wildcard;
+
+ switch (audio_format.format) {
+ case SampleFormat::S8:
+ format->format = media_raw_audio_format::B_AUDIO_CHAR;
+ break;
+
+ case SampleFormat::S16:
+ format->format = media_raw_audio_format::B_AUDIO_SHORT;
+ break;
+
+ case SampleFormat::S32:
+ format->format = media_raw_audio_format::B_AUDIO_INT;
+ break;
+
+ case SampleFormat::FLOAT:
+ format->format = media_raw_audio_format::B_AUDIO_FLOAT;
+ break;
+
+ default:
+ /* fall back to float */
+ audio_format.format = SampleFormat::FLOAT;
+ format->format = media_raw_audio_format::B_AUDIO_FLOAT;
+ break;
+ }
+
+ format->frame_rate = audio_format.sample_rate;
+ format->byte_order = B_MEDIA_HOST_ENDIAN;
+ format->channel_count = audio_format.channels;
+
+ buffer_size = 0;
+
+ if (write_size)
+ format->buffer_size = write_size;
+ else
+ format->buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor(
+ format->channel_count, format->format,
+ format->frame_rate, B_UNKNOWN_BUS) * 2;
+
+ FormatDebug(haiku_output_domain,
+ "using haiku driver ad: bs: %d ws: %d "
+ "channels %d rate %f fmt %08lx bs %d\n",
+ (int)buffer_size, (int)write_size,
+ (int)format->channel_count, format->frame_rate,
+ format->format, (int)format->buffer_size);
+
+ sound_player = new BSoundPlayer(format, "MPD Output",
+ fill_buffer, NULL, this);
+
+ err = sound_player->InitCheck();
+ if (err != B_OK) {
+ delete sound_player;
+ sound_player = NULL;
+ haiku_output_error(error, err);
+ return false;
+ }
+
+ // calculate the allowable delay for the buffer (ms)
+ buffer_delay = format->buffer_size;
+ buffer_delay /= (format->format &
+ media_raw_audio_format::B_AUDIO_SIZE_MASK);
+ buffer_delay /= format->channel_count;
+ buffer_delay *= 1000 / format->frame_rate;
+ // half of the total buffer play time
+ buffer_delay /= 2;
+ FormatDebug(haiku_output_domain,
+ "buffer delay: %d ms\n", buffer_delay);
+
+ new_buffer = create_sem(0, "New buffer request");
+ buffer_done = create_sem(0, "Buffer done");
+
+ sound_player->SetVolume(1.0);
+ sound_player->Start();
+ sound_player->SetHasData(false);
+
+ return true;
+}
+
+inline size_t
+HaikuOutput::Play(const void *chunk, size_t size, gcc_unused Error &error)
+{
+ BSoundPlayer* const soundPlayer = sound_player;
+ const uint8 *data = (const uint8 *)chunk;
+
+ if (size == 0) {
+ soundPlayer->SetHasData(false);
+ return 0;
+ }
+
+ if (!soundPlayer->HasData())
+ soundPlayer->SetHasData(true);
+ acquire_sem(new_buffer);
+
+ size_t bytesLeft = size;
+ while (bytesLeft > 0) {
+ if (buffer_filled == buffer_size) {
+ // Request another buffer from BSoundPlayer
+ release_sem(buffer_done);
+ acquire_sem(new_buffer);
+ }
+
+ const size_t copyBytes = std::min(bytesLeft, buffer_size
+ - buffer_filled);
+ memcpy(buffer + buffer_filled, data,
+ copyBytes);
+ buffer_filled += copyBytes;
+ data += copyBytes;
+ bytesLeft -= copyBytes;
+ }
+
+
+ if (buffer_filled < buffer_size) {
+ // Continue filling this buffer the next time this function is called
+ release_sem(new_buffer);
+ } else {
+ // Buffer is full
+ release_sem(buffer_done);
+ //soundPlayer->SetHasData(false);
+ }
+
+ return size;
+}
+
+inline size_t
+HaikuOutput::Delay()
+{
+ unsigned delay = buffer_filled ? 0 : buffer_delay;
+
+ //FormatDebug(haiku_output_domain,
+ // "delay=%d\n", delay / 2);
+ // XXX: doesn't work
+ //return (delay / 2) ? 1 : 0;
+ (void)delay;
+
+ return 0;
+}
+
+inline void
+HaikuOutput::SendTag(const Tag &tag)
+{
+ status_t err;
+
+ /* lazily initialized */
+ static BBitmap *icon = NULL;
+
+ if (icon == NULL) {
+ BAppFileInfo info;
+ BResources resources;
+ err = resources.SetToImage((const void *)&HaikuOutput::SendTag);
+ BFile file(resources.File());
+ err = info.SetTo(&file);
+ icon = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
+ (float)B_LARGE_ICON - 1), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
+ err = info.GetIcon(icon, B_LARGE_ICON);
+ if (err != B_OK) {
+ delete icon;
+ icon = NULL;
+ }
+ }
+
+ BNotification notification(B_INFORMATION_NOTIFICATION);
+
+ BString messageId("mpd_");
+ messageId << find_thread(NULL);
+ notification.SetMessageID(messageId);
+
+ notification.SetGroup("Music Player Daemon");
+
+ char timebuf[16];
+ unsigned seconds = 0;
+ if (!tag.duration.IsNegative()) {
+ seconds = tag.duration.ToS();
+ snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",
+ seconds / 3600, (seconds % 3600) / 60, seconds % 60);
+ }
+
+ BString artist;
+ BString album;
+ BString title;
+ BString track;
+ BString name;
+
+ for (const auto &item : tag)
+ {
+ switch (item.type) {
+ case TAG_ARTIST:
+ case TAG_ALBUM_ARTIST:
+ if (artist.Length() == 0)
+ artist << item.value;
+ break;
+ case TAG_ALBUM:
+ if (album.Length() == 0)
+ album << item.value;
+ break;
+ case TAG_TITLE:
+ if (title.Length() == 0)
+ title << item.value;
+ break;
+ case TAG_TRACK:
+ if (track.Length() == 0)
+ track << item.value;
+ break;
+ case TAG_NAME:
+ if (name.Length() == 0)
+ name << item.value;
+ break;
+ case TAG_GENRE:
+ case TAG_DATE:
+ case TAG_PERFORMER:
+ case TAG_COMMENT:
+ case TAG_DISC:
+ case TAG_COMPOSER:
+ case TAG_MUSICBRAINZ_ARTISTID:
+ case TAG_MUSICBRAINZ_ALBUMID:
+ case TAG_MUSICBRAINZ_ALBUMARTISTID:
+ case TAG_MUSICBRAINZ_TRACKID:
+ default:
+ FormatDebug(haiku_output_domain,
+ "tag item: type %d value '%s'\n", item.type, item.value);
+ break;
+ }
+ }
+
+ notification.SetTitle(UTF8_PLAY " Now Playing:");
+
+ BStringList content;
+ if (name.Length())
+ content.Add(name);
+ if (artist.Length())
+ content.Add(artist);
+ if (album.Length())
+ content.Add(album);
+ if (track.Length())
+ content.Add(track);
+ if (title.Length())
+ content.Add(title);
+
+ if (content.CountStrings() == 0)
+ content.Add("(Unknown)");
+
+ BString full = content.Join(" " B_UTF8_BULLET " ");
+
+ if (seconds > 0)
+ full << " (" << timebuf << ")";
+
+ notification.SetContent(full);
+
+ err = notification.SetIcon(icon);
+
+ notification.Send();
+}
+
+int
+haiku_output_get_volume(HaikuOutput &haiku)
+{
+ BSoundPlayer* const soundPlayer = haiku.sound_player;
+
+ if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
+ return 0;
+
+ return (int)(soundPlayer->Volume() * 100 + 0.5);
+}
+
+bool
+haiku_output_set_volume(HaikuOutput &haiku, unsigned volume)
+{
+ BSoundPlayer* const soundPlayer = haiku.sound_player;
+
+ if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
+ return false;
+
+ soundPlayer->SetVolume((float)volume / 100);
+ return true;
+}
+
+typedef AudioOutputWrapper<HaikuOutput> Wrapper;
+
+const struct AudioOutputPlugin haiku_output_plugin = {
+ "haiku",
+ haiku_test_default_device,
+ &Wrapper::Init,
+ &Wrapper::Finish,
+ nullptr,
+ nullptr,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
+ &Wrapper::SendTag,
+ &Wrapper::Play,
+ nullptr,
+ nullptr,
+ nullptr,
+
+ &haiku_mixer_plugin,
+};
diff --git a/src/output/plugins/HaikuOutputPlugin.hxx b/src/output/plugins/HaikuOutputPlugin.hxx
new file mode 100644
index 000000000..fb85d4b83
--- /dev/null
+++ b/src/output/plugins/HaikuOutputPlugin.hxx
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ * Copyright (C) 2014-2015 François 'mmu_man' Revol
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_HAIKU_OUTPUT_PLUGIN_HXX
+#define MPD_HAIKU_OUTPUT_PLUGIN_HXX
+
+class HaikuOutput;
+
+extern const struct AudioOutputPlugin haiku_output_plugin;
+
+int
+haiku_output_get_volume(HaikuOutput &haiku);
+
+bool
+haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
+
+#endif
diff --git a/src/output/plugins/JackOutputPlugin.cxx b/src/output/plugins/JackOutputPlugin.cxx
index e1dad7893..23843ab5e 100644
--- a/src/output/plugins/JackOutputPlugin.cxx
+++ b/src/output/plugins/JackOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,26 +20,27 @@
#include "config.h"
#include "JackOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "config/ConfigError.hxx"
+#include "util/ConstBuffer.hxx"
+#include "util/SplitString.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
#include <assert.h>
-#include <glib.h>
#include <jack/jack.h>
#include <jack/types.h>
#include <jack/ringbuffer.h>
+#include <unistd.h> /* for usleep() */
#include <stdlib.h>
#include <string.h>
-enum {
- MAX_PORTS = 16,
-};
+static constexpr unsigned MAX_PORTS = 16;
-static const size_t jack_sample_size = sizeof(jack_default_audio_sample_t);
+static constexpr size_t jack_sample_size = sizeof(jack_default_audio_sample_t);
struct JackOutput {
AudioOutput base;
@@ -55,10 +56,10 @@ struct JackOutput {
/* configuration */
- char *source_ports[MAX_PORTS];
+ std::string source_ports[MAX_PORTS];
unsigned num_source_ports;
- char *destination_ports[MAX_PORTS];
+ std::string destination_ports[MAX_PORTS];
unsigned num_destination_ports;
size_t ringbuffer_size;
@@ -82,24 +83,65 @@ struct JackOutput {
JackOutput()
:base(jack_output_plugin) {}
- bool Initialize(const config_param &param, Error &error_r) {
- return base.Configure(param, error_r);
+ bool Configure(const ConfigBlock &block, Error &error);
+
+ bool Connect(Error &error);
+
+ /**
+ * Disconnect the JACK client.
+ */
+ void Disconnect();
+
+ void Shutdown() {
+ shutdown = true;
+ }
+
+ bool Enable(Error &error);
+ void Disable();
+
+ bool Open(AudioFormat &new_audio_format, Error &error);
+
+ void Close() {
+ Stop();
+ }
+
+ bool Start(Error &error);
+ void Stop();
+
+ /**
+ * Determine the number of frames guaranteed to be available
+ * on all channels.
+ */
+ gcc_pure
+ jack_nframes_t GetAvailable() const;
+
+ void Process(jack_nframes_t nframes);
+
+ /**
+ * @return the number of frames that were written
+ */
+ size_t WriteSamples(const float *src, size_t n_frames);
+
+ unsigned Delay() const {
+ return base.pause && pause && !shutdown
+ ? 1000
+ : 0;
}
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+
+ bool Pause();
};
static constexpr Domain jack_output_domain("jack_output");
-/**
- * Determine the number of frames guaranteed to be available on all
- * channels.
- */
-static jack_nframes_t
-mpd_jack_available(const JackOutput *jd)
+inline jack_nframes_t
+JackOutput::GetAvailable() const
{
- size_t min = jack_ringbuffer_read_space(jd->ringbuffer[0]);
+ size_t min = jack_ringbuffer_read_space(ringbuffer[0]);
- for (unsigned i = 1; i < jd->audio_format.channels; ++i) {
- size_t current = jack_ringbuffer_read_space(jd->ringbuffer[i]);
+ for (unsigned i = 1; i < audio_format.channels; ++i) {
+ size_t current = jack_ringbuffer_read_space(ringbuffer[i]);
if (current < min)
min = current;
}
@@ -109,85 +151,121 @@ mpd_jack_available(const JackOutput *jd)
return min / jack_sample_size;
}
-static int
-mpd_jack_process(jack_nframes_t nframes, void *arg)
+/**
+ * Call jack_ringbuffer_read_advance() on all buffers in the list.
+ */
+static void
+MultiReadAdvance(ConstBuffer<jack_ringbuffer_t *> buffers,
+ size_t size)
{
- JackOutput *jd = (JackOutput *) arg;
+ for (auto *i : buffers)
+ jack_ringbuffer_read_advance(i, size);
+}
+/**
+ * Write a specific amount of "silence" to the given port.
+ */
+static void
+WriteSilence(jack_port_t &port, jack_nframes_t nframes)
+{
+ jack_default_audio_sample_t *out =
+ (jack_default_audio_sample_t *)
+ jack_port_get_buffer(&port, nframes);
+ if (out == nullptr)
+ /* workaround for libjack1 bug: if the server
+ connection fails, the process callback is invoked
+ anyway, but unable to get a buffer */
+ return;
+
+ std::fill_n(out, nframes, 0.0);
+}
+
+/**
+ * Write a specific amount of "silence" to all ports in the list.
+ */
+static void
+MultiWriteSilence(ConstBuffer<jack_port_t *> ports, jack_nframes_t nframes)
+{
+ for (auto *i : ports)
+ WriteSilence(*i, nframes);
+}
+
+/**
+ * Copy data from the buffer to the port. If the buffer underruns,
+ * fill with silence.
+ */
+static void
+Copy(jack_port_t &dest, jack_nframes_t nframes,
+ jack_ringbuffer_t &src, jack_nframes_t available)
+{
+ jack_default_audio_sample_t *out =
+ (jack_default_audio_sample_t *)
+ jack_port_get_buffer(&dest, nframes);
+ if (out == nullptr)
+ /* workaround for libjack1 bug: if the server
+ connection fails, the process callback is
+ invoked anyway, but unable to get a
+ buffer */
+ return;
+
+ /* copy from buffer to port */
+ jack_ringbuffer_read(&src, (char *)out,
+ available * jack_sample_size);
+
+ /* ringbuffer underrun, fill with silence */
+ std::fill(out + available, out + nframes, 0.0);
+}
+
+inline void
+JackOutput::Process(jack_nframes_t nframes)
+{
if (nframes <= 0)
- return 0;
+ return;
- if (jd->pause) {
+ jack_nframes_t available = GetAvailable();
+
+ const unsigned n_channels = audio_format.channels;
+
+ if (pause) {
/* empty the ring buffers */
- const jack_nframes_t available = mpd_jack_available(jd);
- for (unsigned i = 0; i < jd->audio_format.channels; ++i)
- jack_ringbuffer_read_advance(jd->ringbuffer[i],
- available * jack_sample_size);
+ MultiReadAdvance({ringbuffer, n_channels},
+ available * jack_sample_size);
/* generate silence while MPD is paused */
- for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
- jack_default_audio_sample_t *out =
- (jack_default_audio_sample_t *)
- jack_port_get_buffer(jd->ports[i], nframes);
+ MultiWriteSilence({ports, n_channels}, nframes);
- for (jack_nframes_t f = 0; f < nframes; ++f)
- out[f] = 0.0;
- }
-
- return 0;
+ return;
}
- jack_nframes_t available = mpd_jack_available(jd);
if (available > nframes)
available = nframes;
- for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
- jack_default_audio_sample_t *out =
- (jack_default_audio_sample_t *)
- jack_port_get_buffer(jd->ports[i], nframes);
- if (out == nullptr)
- /* workaround for libjack1 bug: if the server
- connection fails, the process callback is
- invoked anyway, but unable to get a
- buffer */
- continue;
-
- jack_ringbuffer_read(jd->ringbuffer[i],
- (char *)out, available * jack_sample_size);
-
- for (jack_nframes_t f = available; f < nframes; ++f)
- /* ringbuffer underrun, fill with silence */
- out[f] = 0.0;
- }
+ for (unsigned i = 0; i < n_channels; ++i)
+ Copy(*ports[i], nframes, *ringbuffer[i], available);
/* generate silence for the unused source ports */
- for (unsigned i = jd->audio_format.channels;
- i < jd->num_source_ports; ++i) {
- jack_default_audio_sample_t *out =
- (jack_default_audio_sample_t *)
- jack_port_get_buffer(jd->ports[i], nframes);
- if (out == nullptr)
- /* workaround for libjack1 bug: if the server
- connection fails, the process callback is
- invoked anyway, but unable to get a
- buffer */
- continue;
-
- for (jack_nframes_t f = 0; f < nframes; ++f)
- out[f] = 0.0;
- }
+ MultiWriteSilence({ports + n_channels, num_source_ports - n_channels},
+ nframes);
+}
+
+static int
+mpd_jack_process(jack_nframes_t nframes, void *arg)
+{
+ JackOutput &jo = *(JackOutput *) arg;
+ jo.Process(nframes);
return 0;
}
static void
mpd_jack_shutdown(void *arg)
{
- JackOutput *jd = (JackOutput *) arg;
- jd->shutdown = true;
+ JackOutput &jo = *(JackOutput *) arg;
+
+ jo.Shutdown();
}
static void
@@ -200,9 +278,10 @@ set_audioformat(JackOutput *jd, AudioFormat &audio_format)
else if (audio_format.channels > jd->num_source_ports)
audio_format.channels = 2;
- if (audio_format.format != SampleFormat::S16 &&
- audio_format.format != SampleFormat::S24_P32)
- audio_format.format = SampleFormat::S24_P32;
+ /* JACK uses 32 bit float in the range [-1 .. 1] - just like
+ MPD's SampleFormat::FLOAT*/
+ static_assert(jack_sample_size == sizeof(float), "Expected float32");
+ audio_format.format = SampleFormat::FLOAT;
}
static void
@@ -219,55 +298,47 @@ mpd_jack_info(const char *msg)
}
#endif
-/**
- * Disconnect the JACK client.
- */
-static void
-mpd_jack_disconnect(JackOutput *jd)
+void
+JackOutput::Disconnect()
{
- assert(jd != nullptr);
- assert(jd->client != nullptr);
+ assert(client != nullptr);
- jack_deactivate(jd->client);
- jack_client_close(jd->client);
- jd->client = nullptr;
+ jack_deactivate(client);
+ jack_client_close(client);
+ client = nullptr;
}
/**
* Connect the JACK client and performs some basic setup
* (e.g. register callbacks).
*/
-static bool
-mpd_jack_connect(JackOutput *jd, Error &error)
+bool
+JackOutput::Connect(Error &error)
{
- jack_status_t status;
-
- assert(jd != nullptr);
-
- jd->shutdown = false;
+ shutdown = false;
- jd->client = jack_client_open(jd->name, jd->options, &status,
- jd->server_name);
- if (jd->client == nullptr) {
+ jack_status_t status;
+ client = jack_client_open(name, options, &status, server_name);
+ if (client == nullptr) {
error.Format(jack_output_domain, status,
"Failed to connect to JACK server, status=%d",
status);
return false;
}
- jack_set_process_callback(jd->client, mpd_jack_process, jd);
- jack_on_shutdown(jd->client, mpd_jack_shutdown, jd);
+ jack_set_process_callback(client, mpd_jack_process, this);
+ jack_on_shutdown(client, mpd_jack_shutdown, this);
- for (unsigned i = 0; i < jd->num_source_ports; ++i) {
- jd->ports[i] = jack_port_register(jd->client,
- jd->source_ports[i],
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput, 0);
- if (jd->ports[i] == nullptr) {
+ for (unsigned i = 0; i < num_source_ports; ++i) {
+ ports[i] = jack_port_register(client,
+ source_ports[i].c_str(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ if (ports[i] == nullptr) {
error.Format(jack_output_domain,
"Cannot register output port \"%s\"",
- jd->source_ports[i]);
- mpd_jack_disconnect(jd);
+ source_ports[i].c_str());
+ Disconnect();
return false;
}
}
@@ -282,23 +353,19 @@ mpd_jack_test_default_device(void)
}
static unsigned
-parse_port_list(const char *source, char **dest, Error &error)
+parse_port_list(const char *source, std::string dest[], Error &error)
{
- char **list = g_strsplit(source, ",", 0);
unsigned n = 0;
-
- for (n = 0; list[n] != nullptr; ++n) {
+ for (auto &&i : SplitString(source, ',')) {
if (n >= MAX_PORTS) {
error.Set(config_domain,
"too many port names");
return 0;
}
- dest[n] = list[n];
+ dest[n++] = std::move(i);
}
- g_free(list);
-
if (n == 0) {
error.Format(config_domain,
"at least one port name expected");
@@ -308,243 +375,221 @@ parse_port_list(const char *source, char **dest, Error &error)
return n;
}
-static AudioOutput *
-mpd_jack_init(const config_param &param, Error &error)
+bool
+JackOutput::Configure(const ConfigBlock &block, Error &error)
{
- JackOutput *jd = new JackOutput();
-
- if (!jd->Initialize(param, error)) {
- delete jd;
- return nullptr;
- }
-
- const char *value;
+ if (!base.Configure(block, error))
+ return false;
- jd->options = JackNullOption;
+ options = JackNullOption;
- jd->name = param.GetBlockValue("client_name", nullptr);
- if (jd->name != nullptr)
- jd->options = jack_options_t(jd->options | JackUseExactName);
+ name = block.GetBlockValue("client_name", nullptr);
+ if (name != nullptr)
+ options = jack_options_t(options | JackUseExactName);
else
/* if there's a no configured client name, we don't
care about the JackUseExactName option */
- jd->name = "Music Player Daemon";
+ name = "Music Player Daemon";
- jd->server_name = param.GetBlockValue("server_name", nullptr);
- if (jd->server_name != nullptr)
- jd->options = jack_options_t(jd->options | JackServerName);
+ server_name = block.GetBlockValue("server_name", nullptr);
+ if (server_name != nullptr)
+ options = jack_options_t(options | JackServerName);
- if (!param.GetBlockValue("autostart", false))
- jd->options = jack_options_t(jd->options | JackNoStartServer);
+ if (!block.GetBlockValue("autostart", false))
+ options = jack_options_t(options | JackNoStartServer);
/* configure the source ports */
- value = param.GetBlockValue("source_ports", "left,right");
- jd->num_source_ports = parse_port_list(value,
- jd->source_ports, error);
- if (jd->num_source_ports == 0)
- return nullptr;
+ const char *value = block.GetBlockValue("source_ports", "left,right");
+ num_source_ports = parse_port_list(value, source_ports, error);
+ if (num_source_ports == 0)
+ return false;
/* configure the destination ports */
- value = param.GetBlockValue("destination_ports", nullptr);
+ value = block.GetBlockValue("destination_ports", nullptr);
if (value == nullptr) {
/* compatibility with MPD < 0.16 */
- value = param.GetBlockValue("ports", nullptr);
+ value = block.GetBlockValue("ports", nullptr);
if (value != nullptr)
FormatWarning(jack_output_domain,
"deprecated option 'ports' in line %d",
- param.line);
+ block.line);
}
if (value != nullptr) {
- jd->num_destination_ports =
- parse_port_list(value,
- jd->destination_ports, error);
- if (jd->num_destination_ports == 0)
- return nullptr;
+ num_destination_ports =
+ parse_port_list(value, destination_ports, error);
+ if (num_destination_ports == 0)
+ return false;
} else {
- jd->num_destination_ports = 0;
+ num_destination_ports = 0;
}
- if (jd->num_destination_ports > 0 &&
- jd->num_destination_ports != jd->num_source_ports)
+ if (num_destination_ports > 0 &&
+ num_destination_ports != num_source_ports)
FormatWarning(jack_output_domain,
"number of source ports (%u) mismatches the "
"number of destination ports (%u) in line %d",
- jd->num_source_ports, jd->num_destination_ports,
- param.line);
-
- jd->ringbuffer_size = param.GetBlockValue("ringbuffer_size", 32768u);
+ num_source_ports, num_destination_ports,
+ block.line);
- jack_set_error_function(mpd_jack_error);
+ ringbuffer_size = block.GetBlockValue("ringbuffer_size", 32768u);
-#ifdef HAVE_JACK_SET_INFO_FUNCTION
- jack_set_info_function(mpd_jack_info);
-#endif
-
- return &jd->base;
+ return true;
}
-static void
-mpd_jack_finish(AudioOutput *ao)
+inline bool
+JackOutput::Enable(Error &error)
{
- JackOutput *jd = (JackOutput *)ao;
-
- for (unsigned i = 0; i < jd->num_source_ports; ++i)
- g_free(jd->source_ports[i]);
+ for (unsigned i = 0; i < num_source_ports; ++i)
+ ringbuffer[i] = nullptr;
- for (unsigned i = 0; i < jd->num_destination_ports; ++i)
- g_free(jd->destination_ports[i]);
-
- delete jd;
+ return Connect(error);
}
-static bool
-mpd_jack_enable(AudioOutput *ao, Error &error)
+inline void
+JackOutput::Disable()
{
- JackOutput *jd = (JackOutput *)ao;
+ if (client != nullptr)
+ Disconnect();
- for (unsigned i = 0; i < jd->num_source_ports; ++i)
- jd->ringbuffer[i] = nullptr;
-
- return mpd_jack_connect(jd, error);
+ for (unsigned i = 0; i < num_source_ports; ++i) {
+ if (ringbuffer[i] != nullptr) {
+ jack_ringbuffer_free(ringbuffer[i]);
+ ringbuffer[i] = nullptr;
+ }
+ }
}
-static void
-mpd_jack_disable(AudioOutput *ao)
+static AudioOutput *
+mpd_jack_init(const ConfigBlock &block, Error &error)
{
- JackOutput *jd = (JackOutput *)ao;
-
- if (jd->client != nullptr)
- mpd_jack_disconnect(jd);
+ JackOutput *jd = new JackOutput();
- for (unsigned i = 0; i < jd->num_source_ports; ++i) {
- if (jd->ringbuffer[i] != nullptr) {
- jack_ringbuffer_free(jd->ringbuffer[i]);
- jd->ringbuffer[i] = nullptr;
- }
+ if (!jd->Configure(block, error)) {
+ delete jd;
+ return nullptr;
}
+
+ jack_set_error_function(mpd_jack_error);
+
+#ifdef HAVE_JACK_SET_INFO_FUNCTION
+ jack_set_info_function(mpd_jack_info);
+#endif
+
+ return &jd->base;
}
/**
* Stops the playback on the JACK connection.
*/
-static void
-mpd_jack_stop(JackOutput *jd)
+void
+JackOutput::Stop()
{
- assert(jd != nullptr);
-
- if (jd->client == nullptr)
+ if (client == nullptr)
return;
- if (jd->shutdown)
+ if (shutdown)
/* the connection has failed; close it */
- mpd_jack_disconnect(jd);
+ Disconnect();
else
/* the connection is alive: just stop playback */
- jack_deactivate(jd->client);
+ jack_deactivate(client);
}
-static bool
-mpd_jack_start(JackOutput *jd, Error &error)
+inline bool
+JackOutput::Start(Error &error)
{
- const char *destination_ports[MAX_PORTS], **jports;
- const char *duplicate_port = nullptr;
- unsigned num_destination_ports;
-
- assert(jd->client != nullptr);
- assert(jd->audio_format.channels <= jd->num_source_ports);
+ assert(client != nullptr);
+ assert(audio_format.channels <= num_source_ports);
/* allocate the ring buffers on the first open(); these
persist until MPD exits. It's too unsafe to delete them
because we can never know when mpd_jack_process() gets
called */
- for (unsigned i = 0; i < jd->num_source_ports; ++i) {
- if (jd->ringbuffer[i] == nullptr)
- jd->ringbuffer[i] =
- jack_ringbuffer_create(jd->ringbuffer_size);
+ for (unsigned i = 0; i < num_source_ports; ++i) {
+ if (ringbuffer[i] == nullptr)
+ ringbuffer[i] =
+ jack_ringbuffer_create(ringbuffer_size);
/* clear the ring buffer to be sure that data from
previous playbacks are gone */
- jack_ringbuffer_reset(jd->ringbuffer[i]);
+ jack_ringbuffer_reset(ringbuffer[i]);
}
- if ( jack_activate(jd->client) ) {
+ if ( jack_activate(client) ) {
error.Set(jack_output_domain, "cannot activate client");
- mpd_jack_stop(jd);
+ Stop();
return false;
}
- if (jd->num_destination_ports == 0) {
+ const char *dports[MAX_PORTS], **jports;
+ unsigned num_dports;
+ if (num_destination_ports == 0) {
/* no output ports were configured - ask libjack for
defaults */
- jports = jack_get_ports(jd->client, nullptr, nullptr,
+ jports = jack_get_ports(client, nullptr, nullptr,
JackPortIsPhysical | JackPortIsInput);
if (jports == nullptr) {
error.Set(jack_output_domain, "no ports found");
- mpd_jack_stop(jd);
+ Stop();
return false;
}
assert(*jports != nullptr);
- for (num_destination_ports = 0;
- num_destination_ports < MAX_PORTS &&
- jports[num_destination_ports] != nullptr;
- ++num_destination_ports) {
+ for (num_dports = 0; num_dports < MAX_PORTS &&
+ jports[num_dports] != nullptr;
+ ++num_dports) {
FormatDebug(jack_output_domain,
"destination_port[%u] = '%s'\n",
- num_destination_ports,
- jports[num_destination_ports]);
- destination_ports[num_destination_ports] =
- jports[num_destination_ports];
+ num_dports,
+ jports[num_dports]);
+ dports[num_dports] = jports[num_dports];
}
} else {
/* use the configured output ports */
- num_destination_ports = jd->num_destination_ports;
- memcpy(destination_ports, jd->destination_ports,
- num_destination_ports * sizeof(*destination_ports));
+ num_dports = num_destination_ports;
+ for (unsigned i = 0; i < num_dports; ++i)
+ dports[i] = destination_ports[i].c_str();
jports = nullptr;
}
- assert(num_destination_ports > 0);
+ assert(num_dports > 0);
- if (jd->audio_format.channels >= 2 && num_destination_ports == 1) {
+ const char *duplicate_port = nullptr;
+ if (audio_format.channels >= 2 && num_dports == 1) {
/* mix stereo signal on one speaker */
- while (num_destination_ports < jd->audio_format.channels)
- destination_ports[num_destination_ports++] =
- destination_ports[0];
- } else if (num_destination_ports > jd->audio_format.channels) {
- if (jd->audio_format.channels == 1 && num_destination_ports > 2) {
+ std::fill(dports + num_dports, dports + audio_format.channels,
+ dports[0]);
+ } else if (num_dports > audio_format.channels) {
+ if (audio_format.channels == 1 && num_dports > 2) {
/* mono input file: connect the one source
channel to the both destination channels */
- duplicate_port = destination_ports[1];
- num_destination_ports = 1;
+ duplicate_port = dports[1];
+ num_dports = 1;
} else
/* connect only as many ports as we need */
- num_destination_ports = jd->audio_format.channels;
+ num_dports = audio_format.channels;
}
- assert(num_destination_ports <= jd->num_source_ports);
-
- for (unsigned i = 0; i < num_destination_ports; ++i) {
- int ret;
+ assert(num_dports <= num_source_ports);
- ret = jack_connect(jd->client, jack_port_name(jd->ports[i]),
- destination_ports[i]);
+ for (unsigned i = 0; i < num_dports; ++i) {
+ int ret = jack_connect(client, jack_port_name(ports[i]),
+ dports[i]);
if (ret != 0) {
error.Format(jack_output_domain,
- "Not a valid JACK port: %s",
- destination_ports[i]);
+ "Not a valid JACK port: %s", dports[i]);
if (jports != nullptr)
free(jports);
- mpd_jack_stop(jd);
+ Stop();
return false;
}
}
@@ -554,7 +599,7 @@ mpd_jack_start(JackOutput *jd, Error &error)
the both destination channels */
int ret;
- ret = jack_connect(jd->client, jack_port_name(jd->ports[0]),
+ ret = jack_connect(client, jack_port_name(ports[0]),
duplicate_port);
if (ret != 0) {
error.Format(jack_output_domain,
@@ -564,7 +609,7 @@ mpd_jack_start(JackOutput *jd, Error &error)
if (jports != nullptr)
free(jports);
- mpd_jack_stop(jd);
+ Stop();
return false;
}
}
@@ -575,188 +620,119 @@ mpd_jack_start(JackOutput *jd, Error &error)
return true;
}
-static bool
-mpd_jack_open(AudioOutput *ao, AudioFormat &audio_format,
- Error &error)
+inline bool
+JackOutput::Open(AudioFormat &new_audio_format, Error &error)
{
- JackOutput *jd = (JackOutput *)ao;
+ pause = false;
- assert(jd != nullptr);
+ if (client != nullptr && shutdown)
+ Disconnect();
- jd->pause = false;
-
- if (jd->client != nullptr && jd->shutdown)
- mpd_jack_disconnect(jd);
-
- if (jd->client == nullptr && !mpd_jack_connect(jd, error))
+ if (client == nullptr && !Connect(error))
return false;
- set_audioformat(jd, audio_format);
- jd->audio_format = audio_format;
+ set_audioformat(this, new_audio_format);
+ audio_format = new_audio_format;
- if (!mpd_jack_start(jd, error))
- return false;
-
- return true;
+ return Start(error);
}
-static void
-mpd_jack_close(gcc_unused AudioOutput *ao)
+inline size_t
+JackOutput::WriteSamples(const float *src, size_t n_frames)
{
- JackOutput *jd = (JackOutput *)ao;
+ assert(n_frames > 0);
- mpd_jack_stop(jd);
-}
+ const unsigned n_channels = audio_format.channels;
-static unsigned
-mpd_jack_delay(AudioOutput *ao)
-{
- JackOutput *jd = (JackOutput *)ao;
+ float *dest[MAX_CHANNELS];
+ size_t space = -1;
+ for (unsigned i = 0; i < n_channels; ++i) {
+ jack_ringbuffer_data_t d[2];
+ jack_ringbuffer_get_write_vector(ringbuffer[i], d);
- return jd->base.pause && jd->pause && !jd->shutdown
- ? 1000
- : 0;
-}
+ /* choose the first non-empty writable area */
+ const jack_ringbuffer_data_t &e = d[d[0].len == 0];
-static inline jack_default_audio_sample_t
-sample_16_to_jack(int16_t sample)
-{
- return sample / (jack_default_audio_sample_t)(1 << (16 - 1));
-}
+ if (e.len < space)
+ /* send data symmetrically */
+ space = e.len;
-static void
-mpd_jack_write_samples_16(JackOutput *jd, const int16_t *src,
- unsigned num_samples)
-{
- jack_default_audio_sample_t sample;
- unsigned i;
-
- while (num_samples-- > 0) {
- for (i = 0; i < jd->audio_format.channels; ++i) {
- sample = sample_16_to_jack(*src++);
- jack_ringbuffer_write(jd->ringbuffer[i],
- (const char *)&sample,
- sizeof(sample));
- }
+ dest[i] = (float *)e.buf;
}
-}
-static inline jack_default_audio_sample_t
-sample_24_to_jack(int32_t sample)
-{
- return sample / (jack_default_audio_sample_t)(1 << (24 - 1));
-}
+ space /= jack_sample_size;
+ if (space == 0)
+ return 0;
-static void
-mpd_jack_write_samples_24(JackOutput *jd, const int32_t *src,
- unsigned num_samples)
-{
- jack_default_audio_sample_t sample;
- unsigned i;
-
- while (num_samples-- > 0) {
- for (i = 0; i < jd->audio_format.channels; ++i) {
- sample = sample_24_to_jack(*src++);
- jack_ringbuffer_write(jd->ringbuffer[i],
- (const char *)&sample,
- sizeof(sample));
- }
- }
-}
+ const size_t result = n_frames = std::min(space, n_frames);
-static void
-mpd_jack_write_samples(JackOutput *jd, const void *src,
- unsigned num_samples)
-{
- switch (jd->audio_format.format) {
- case SampleFormat::S16:
- mpd_jack_write_samples_16(jd, (const int16_t*)src,
- num_samples);
- break;
-
- case SampleFormat::S24_P32:
- mpd_jack_write_samples_24(jd, (const int32_t*)src,
- num_samples);
- break;
-
- default:
- assert(false);
- gcc_unreachable();
- }
+ while (n_frames-- > 0)
+ for (unsigned i = 0; i < n_channels; ++i)
+ *dest[i]++ = *src++;
+
+ const size_t per_channel_advance = result * jack_sample_size;
+ for (unsigned i = 0; i < n_channels; ++i)
+ jack_ringbuffer_write_advance(ringbuffer[i],
+ per_channel_advance);
+
+ return result;
}
-static size_t
-mpd_jack_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+JackOutput::Play(const void *chunk, size_t size, Error &error)
{
- JackOutput *jd = (JackOutput *)ao;
- const size_t frame_size = jd->audio_format.GetFrameSize();
- size_t space = 0, space1;
-
- jd->pause = false;
+ pause = false;
+ const size_t frame_size = audio_format.GetFrameSize();
assert(size % frame_size == 0);
size /= frame_size;
while (true) {
- if (jd->shutdown) {
+ if (shutdown) {
error.Set(jack_output_domain,
"Refusing to play, because "
"there is no client thread");
return 0;
}
- space = jack_ringbuffer_write_space(jd->ringbuffer[0]);
- for (unsigned i = 1; i < jd->audio_format.channels; ++i) {
- space1 = jack_ringbuffer_write_space(jd->ringbuffer[i]);
- if (space > space1)
- /* send data symmetrically */
- space = space1;
- }
-
- if (space >= jack_sample_size)
- break;
+ size_t frames_written =
+ WriteSamples((const float *)chunk, size);
+ if (frames_written > 0)
+ return frames_written * frame_size;
/* XXX do something more intelligent to
synchronize */
- g_usleep(1000);
+ usleep(1000);
}
-
- space /= jack_sample_size;
- if (space < size)
- size = space;
-
- mpd_jack_write_samples(jd, chunk, size);
- return size * frame_size;
}
-static bool
-mpd_jack_pause(AudioOutput *ao)
+inline bool
+JackOutput::Pause()
{
- JackOutput *jd = (JackOutput *)ao;
-
- if (jd->shutdown)
+ if (shutdown)
return false;
- jd->pause = true;
+ pause = true;
return true;
}
+typedef AudioOutputWrapper<JackOutput> Wrapper;
+
const struct AudioOutputPlugin jack_output_plugin = {
"jack",
mpd_jack_test_default_device,
mpd_jack_init,
- mpd_jack_finish,
- mpd_jack_enable,
- mpd_jack_disable,
- mpd_jack_open,
- mpd_jack_close,
- mpd_jack_delay,
+ &Wrapper::Finish,
+ &Wrapper::Enable,
+ &Wrapper::Disable,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- mpd_jack_play,
+ &Wrapper::Play,
nullptr,
nullptr,
- mpd_jack_pause,
+ &Wrapper::Pause,
nullptr,
};
diff --git a/src/output/plugins/JackOutputPlugin.hxx b/src/output/plugins/JackOutputPlugin.hxx
index 6f1f7ecb9..f76431690 100644
--- a/src/output/plugins/JackOutputPlugin.hxx
+++ b/src/output/plugins/JackOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/NullOutputPlugin.cxx b/src/output/plugins/NullOutputPlugin.cxx
index 098f58926..e1731f0fe 100644
--- a/src/output/plugins/NullOutputPlugin.cxx
+++ b/src/output/plugins/NullOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,119 +20,94 @@
#include "config.h"
#include "NullOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "../Timer.hxx"
-struct NullOutput {
+class NullOutput {
+ friend struct AudioOutputWrapper<NullOutput>;
+
AudioOutput base;
bool sync;
Timer *timer;
+public:
NullOutput()
:base(null_output_plugin) {}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
- }
-};
-
-static AudioOutput *
-null_init(const config_param &param, Error &error)
-{
- NullOutput *nd = new NullOutput();
-
- if (!nd->Initialize(param, error)) {
- delete nd;
- return nullptr;
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
}
- nd->sync = param.GetBlockValue("sync", true);
+ static NullOutput *Create(const ConfigBlock &block, Error &error);
- return &nd->base;
-}
+ bool Open(AudioFormat &audio_format, gcc_unused Error &error) {
+ if (sync)
+ timer = new Timer(audio_format);
-static void
-null_finish(AudioOutput *ao)
-{
- NullOutput *nd = (NullOutput *)ao;
-
- delete nd;
-}
-
-static bool
-null_open(AudioOutput *ao, AudioFormat &audio_format,
- gcc_unused Error &error)
-{
- NullOutput *nd = (NullOutput *)ao;
-
- if (nd->sync)
- nd->timer = new Timer(audio_format);
+ return true;
+ }
- return true;
-}
+ void Close() {
+ if (sync)
+ delete timer;
+ }
-static void
-null_close(AudioOutput *ao)
-{
- NullOutput *nd = (NullOutput *)ao;
+ unsigned Delay() const {
+ return sync && timer->IsStarted()
+ ? timer->GetDelay()
+ : 0;
+ }
- if (nd->sync)
- delete nd->timer;
-}
+ size_t Play(gcc_unused const void *chunk, size_t size,
+ gcc_unused Error &error) {
+ if (sync) {
+ if (!timer->IsStarted())
+ timer->Start();
+ timer->Add(size);
+ }
-static unsigned
-null_delay(AudioOutput *ao)
-{
- NullOutput *nd = (NullOutput *)ao;
+ return size;
+ }
- return nd->sync && nd->timer->IsStarted()
- ? nd->timer->GetDelay()
- : 0;
-}
+ void Cancel() {
+ if (sync)
+ timer->Reset();
+ }
+};
-static size_t
-null_play(AudioOutput *ao, gcc_unused const void *chunk, size_t size,
- gcc_unused Error &error)
+inline NullOutput *
+NullOutput::Create(const ConfigBlock &block, Error &error)
{
- NullOutput *nd = (NullOutput *)ao;
- Timer *timer = nd->timer;
+ NullOutput *nd = new NullOutput();
- if (!nd->sync)
- return size;
+ if (!nd->Initialize(block, error)) {
+ delete nd;
+ return nullptr;
+ }
- if (!timer->IsStarted())
- timer->Start();
- timer->Add(size);
+ nd->sync = block.GetBlockValue("sync", true);
- return size;
+ return nd;
}
-static void
-null_cancel(AudioOutput *ao)
-{
- NullOutput *nd = (NullOutput *)ao;
-
- if (!nd->sync)
- return;
-
- nd->timer->Reset();
-}
+typedef AudioOutputWrapper<NullOutput> Wrapper;
const struct AudioOutputPlugin null_output_plugin = {
"null",
nullptr,
- null_init,
- null_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
nullptr,
- null_open,
- null_close,
- null_delay,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- null_play,
+ &Wrapper::Play,
nullptr,
- null_cancel,
+ &Wrapper::Cancel,
nullptr,
nullptr,
};
diff --git a/src/output/plugins/NullOutputPlugin.hxx b/src/output/plugins/NullOutputPlugin.hxx
index f25f5b9f3..9a1d1558b 100644
--- a/src/output/plugins/NullOutputPlugin.hxx
+++ b/src/output/plugins/NullOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/OSXOutputPlugin.cxx b/src/output/plugins/OSXOutputPlugin.cxx
index 13ac7b35e..16c042ba3 100644
--- a/src/output/plugins/OSXOutputPlugin.cxx
+++ b/src/output/plugins/OSXOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -61,17 +61,17 @@ osx_output_test_default_device(void)
}
static void
-osx_output_configure(OSXOutput *oo, const config_param &param)
+osx_output_configure(OSXOutput *oo, const ConfigBlock &block)
{
- const char *device = param.GetBlockValue("device");
+ const char *device = block.GetBlockValue("device");
- if (device == NULL || 0 == strcmp(device, "default")) {
+ if (device == nullptr || 0 == strcmp(device, "default")) {
oo->component_subtype = kAudioUnitSubType_DefaultOutput;
- oo->device_name = NULL;
+ oo->device_name = nullptr;
}
else if (0 == strcmp(device, "system")) {
oo->component_subtype = kAudioUnitSubType_SystemOutput;
- oo->device_name = NULL;
+ oo->device_name = nullptr;
}
else {
oo->component_subtype = kAudioUnitSubType_HALOutput;
@@ -81,15 +81,15 @@ osx_output_configure(OSXOutput *oo, const config_param &param)
}
static AudioOutput *
-osx_output_init(const config_param &param, Error &error)
+osx_output_init(const ConfigBlock &block, Error &error)
{
OSXOutput *oo = new OSXOutput();
- if (!oo->base.Configure(param, error)) {
+ if (!oo->base.Configure(block, error)) {
delete oo;
- return NULL;
+ return nullptr;
}
- osx_output_configure(oo, param);
+ osx_output_configure(oo, block);
return &oo->base;
}
@@ -108,7 +108,7 @@ osx_output_set_device(OSXOutput *oo, Error &error)
bool ret = true;
OSStatus status;
UInt32 size, numdevices;
- AudioDeviceID *deviceids = NULL;
+ AudioDeviceID *deviceids = nullptr;
char name[256];
unsigned int i;
@@ -118,7 +118,7 @@ osx_output_set_device(OSXOutput *oo, Error &error)
/* how many audio devices are there? */
status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
&size,
- NULL);
+ nullptr);
if (status != noErr) {
error.Format(osx_output_domain, status,
"Unable to determine number of OS X audio devices: %s",
@@ -206,7 +206,7 @@ osx_render(void *vdata,
AudioBuffer *buffer = &buffer_list->mBuffers[0];
size_t buffer_size = buffer->mDataByteSize;
- assert(od->buffer != NULL);
+ assert(od->buffer != nullptr);
od->mutex.lock();
@@ -245,7 +245,7 @@ osx_output_enable(AudioOutput *ao, Error &error)
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
- Component comp = FindNextComponent(NULL, &desc);
+ Component comp = FindNextComponent(nullptr, &desc);
if (comp == 0) {
error.Set(osx_output_domain,
"Error finding OS X component");
diff --git a/src/output/plugins/OSXOutputPlugin.hxx b/src/output/plugins/OSXOutputPlugin.hxx
index d7aed40b6..89cd3fe91 100644
--- a/src/output/plugins/OSXOutputPlugin.hxx
+++ b/src/output/plugins/OSXOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/OpenALOutputPlugin.cxx b/src/output/plugins/OpenALOutputPlugin.cxx
index 2f095c0a4..eb55c6e9b 100644
--- a/src/output/plugins/OpenALOutputPlugin.cxx
+++ b/src/output/plugins/OpenALOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "OpenALOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -33,10 +34,12 @@
#include <OpenAL/alc.h>
#endif
-/* should be enough for buffer size = 2048 */
-#define NUM_BUFFERS 16
+class OpenALOutput {
+ friend struct AudioOutputWrapper<OpenALOutput>;
+
+ /* should be enough for buffer size = 2048 */
+ static constexpr unsigned NUM_BUFFERS = 16;
-struct OpenALOutput {
AudioOutput base;
const char *device_name;
@@ -51,9 +54,47 @@ struct OpenALOutput {
OpenALOutput()
:base(openal_output_plugin) {}
- bool Initialize(const config_param &param, Error &error_r) {
- return base.Configure(param, error_r);
+ bool Configure(const ConfigBlock &block, Error &error);
+
+ static OpenALOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Open(AudioFormat &audio_format, Error &error);
+
+ void Close();
+
+ gcc_pure
+ unsigned Delay() const {
+ return filled < NUM_BUFFERS || HasProcessed()
+ ? 0
+ /* we don't know exactly how long we must wait
+ for the next buffer to finish, so this is a
+ random guess: */
+ : 50;
+ }
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+
+ void Cancel();
+
+private:
+ gcc_pure
+ ALint GetSourceI(ALenum param) const {
+ ALint value;
+ alGetSourcei(source, param, &value);
+ return value;
+ }
+
+ gcc_pure
+ bool HasProcessed() const {
+ return GetSourceI(AL_BUFFERS_PROCESSED) > 0;
}
+
+ gcc_pure
+ bool IsPlaying() const {
+ return GetSourceI(AL_SOURCE_STATE) == AL_PLAYING;
+ }
+
+ bool SetupContext(Error &error);
};
static constexpr Domain openal_output_domain("openal_output");
@@ -83,200 +124,154 @@ openal_audio_format(AudioFormat &audio_format)
}
}
-gcc_pure
-static inline ALint
-openal_get_source_i(const OpenALOutput *od, ALenum param)
-{
- ALint value;
- alGetSourcei(od->source, param, &value);
- return value;
-}
-
-gcc_pure
-static inline bool
-openal_has_processed(const OpenALOutput *od)
-{
- return openal_get_source_i(od, AL_BUFFERS_PROCESSED) > 0;
-}
-
-gcc_pure
-static inline ALint
-openal_is_playing(const OpenALOutput *od)
-{
- return openal_get_source_i(od, AL_SOURCE_STATE) == AL_PLAYING;
-}
-
-static bool
-openal_setup_context(OpenALOutput *od, Error &error)
+inline bool
+OpenALOutput::SetupContext(Error &error)
{
- od->device = alcOpenDevice(od->device_name);
+ device = alcOpenDevice(device_name);
- if (od->device == nullptr) {
+ if (device == nullptr) {
error.Format(openal_output_domain,
"Error opening OpenAL device \"%s\"",
- od->device_name);
+ device_name);
return false;
}
- od->context = alcCreateContext(od->device, nullptr);
+ context = alcCreateContext(device, nullptr);
- if (od->context == nullptr) {
+ if (context == nullptr) {
error.Format(openal_output_domain,
"Error creating context for \"%s\"",
- od->device_name);
- alcCloseDevice(od->device);
+ device_name);
+ alcCloseDevice(device);
return false;
}
return true;
}
-static AudioOutput *
-openal_init(const config_param &param, Error &error)
+inline bool
+OpenALOutput::Configure(const ConfigBlock &block, Error &error)
{
- const char *device_name = param.GetBlockValue("device");
- if (device_name == nullptr) {
- device_name = alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
- }
-
- OpenALOutput *od = new OpenALOutput();
- if (!od->Initialize(param, error)) {
- delete od;
- return nullptr;
- }
+ if (!base.Configure(block, error))
+ return false;
- od->device_name = device_name;
+ device_name = block.GetBlockValue("device");
+ if (device_name == nullptr)
+ device_name = alcGetString(nullptr,
+ ALC_DEFAULT_DEVICE_SPECIFIER);
- return &od->base;
+ return true;
}
-static void
-openal_finish(AudioOutput *ao)
+inline OpenALOutput *
+OpenALOutput::Create(const ConfigBlock &block, Error &error)
{
- OpenALOutput *od = (OpenALOutput *)ao;
+ OpenALOutput *oo = new OpenALOutput();
+
+ if (!oo->Configure(block, error)) {
+ delete oo;
+ return nullptr;
+ }
- delete od;
+ return oo;
}
-static bool
-openal_open(AudioOutput *ao, AudioFormat &audio_format,
- Error &error)
+inline bool
+OpenALOutput::Open(AudioFormat &audio_format, Error &error)
{
- OpenALOutput *od = (OpenALOutput *)ao;
+ format = openal_audio_format(audio_format);
- od->format = openal_audio_format(audio_format);
-
- if (!openal_setup_context(od, error)) {
+ if (!SetupContext(error))
return false;
- }
- alcMakeContextCurrent(od->context);
- alGenBuffers(NUM_BUFFERS, od->buffers);
+ alcMakeContextCurrent(context);
+ alGenBuffers(NUM_BUFFERS, buffers);
if (alGetError() != AL_NO_ERROR) {
error.Set(openal_output_domain, "Failed to generate buffers");
return false;
}
- alGenSources(1, &od->source);
+ alGenSources(1, &source);
if (alGetError() != AL_NO_ERROR) {
error.Set(openal_output_domain, "Failed to generate source");
- alDeleteBuffers(NUM_BUFFERS, od->buffers);
+ alDeleteBuffers(NUM_BUFFERS, buffers);
return false;
}
- od->filled = 0;
- od->frequency = audio_format.sample_rate;
+ filled = 0;
+ frequency = audio_format.sample_rate;
return true;
}
-static void
-openal_close(AudioOutput *ao)
+inline void
+OpenALOutput::Close()
{
- OpenALOutput *od = (OpenALOutput *)ao;
-
- alcMakeContextCurrent(od->context);
- alDeleteSources(1, &od->source);
- alDeleteBuffers(NUM_BUFFERS, od->buffers);
- alcDestroyContext(od->context);
- alcCloseDevice(od->device);
+ alcMakeContextCurrent(context);
+ alDeleteSources(1, &source);
+ alDeleteBuffers(NUM_BUFFERS, buffers);
+ alcDestroyContext(context);
+ alcCloseDevice(device);
}
-static unsigned
-openal_delay(AudioOutput *ao)
+inline size_t
+OpenALOutput::Play(const void *chunk, size_t size, gcc_unused Error &error)
{
- OpenALOutput *od = (OpenALOutput *)ao;
-
- return od->filled < NUM_BUFFERS || openal_has_processed(od)
- ? 0
- /* we don't know exactly how long we must wait for the
- next buffer to finish, so this is a random
- guess: */
- : 50;
-}
+ if (alcGetCurrentContext() != context)
+ alcMakeContextCurrent(context);
-static size_t
-openal_play(AudioOutput *ao, const void *chunk, size_t size,
- gcc_unused Error &error)
-{
- OpenALOutput *od = (OpenALOutput *)ao;
ALuint buffer;
-
- if (alcGetCurrentContext() != od->context) {
- alcMakeContextCurrent(od->context);
- }
-
- if (od->filled < NUM_BUFFERS) {
+ if (filled < NUM_BUFFERS) {
/* fill all buffers */
- buffer = od->buffers[od->filled];
- od->filled++;
+ buffer = buffers[filled];
+ filled++;
} else {
/* wait for processed buffer */
- while (!openal_has_processed(od))
+ while (!HasProcessed())
usleep(10);
- alSourceUnqueueBuffers(od->source, 1, &buffer);
+ alSourceUnqueueBuffers(source, 1, &buffer);
}
- alBufferData(buffer, od->format, chunk, size, od->frequency);
- alSourceQueueBuffers(od->source, 1, &buffer);
+ alBufferData(buffer, format, chunk, size, frequency);
+ alSourceQueueBuffers(source, 1, &buffer);
- if (!openal_is_playing(od))
- alSourcePlay(od->source);
+ if (!IsPlaying())
+ alSourcePlay(source);
return size;
}
-static void
-openal_cancel(AudioOutput *ao)
+inline void
+OpenALOutput::Cancel()
{
- OpenALOutput *od = (OpenALOutput *)ao;
-
- od->filled = 0;
- alcMakeContextCurrent(od->context);
- alSourceStop(od->source);
+ filled = 0;
+ alcMakeContextCurrent(context);
+ alSourceStop(source);
/* force-unqueue all buffers */
- alSourcei(od->source, AL_BUFFER, 0);
- od->filled = 0;
+ alSourcei(source, AL_BUFFER, 0);
+ filled = 0;
}
+typedef AudioOutputWrapper<OpenALOutput> Wrapper;
+
const struct AudioOutputPlugin openal_output_plugin = {
"openal",
nullptr,
- openal_init,
- openal_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
nullptr,
- openal_open,
- openal_close,
- openal_delay,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- openal_play,
+ &Wrapper::Play,
nullptr,
- openal_cancel,
+ &Wrapper::Cancel,
nullptr,
nullptr,
};
diff --git a/src/output/plugins/OpenALOutputPlugin.hxx b/src/output/plugins/OpenALOutputPlugin.hxx
index a27e6b53c..abf4ffdb1 100644
--- a/src/output/plugins/OpenALOutputPlugin.hxx
+++ b/src/output/plugins/OpenALOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/OssOutputPlugin.cxx b/src/output/plugins/OssOutputPlugin.cxx
index 39d87fc35..7f75f4e31 100644
--- a/src/output/plugins/OssOutputPlugin.cxx
+++ b/src/output/plugins/OssOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "OssOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "system/fd_util.h"
#include "util/ConstBuffer.hxx"
@@ -57,7 +58,9 @@
#include "util/Manual.hxx"
#endif
-struct OssOutput {
+class OssOutput {
+ friend struct AudioOutputWrapper<OssOutput>;
+
AudioOutput base;
#ifdef AFMT_S24_PACKED
@@ -79,13 +82,49 @@ struct OssOutput {
*/
int oss_format;
- OssOutput()
+public:
+ OssOutput(const char *_device=nullptr)
:base(oss_output_plugin),
- fd(-1), device(nullptr) {}
+ fd(-1), device(_device) {}
- bool Initialize(const config_param &param, Error &error_r) {
- return base.Configure(param, error_r);
+ bool Initialize(const ConfigBlock &block, Error &error_r) {
+ return base.Configure(block, error_r);
}
+
+ static OssOutput *Create(const ConfigBlock &block, Error &error);
+
+#ifdef AFMT_S24_PACKED
+ bool Enable(gcc_unused Error &error) {
+ pcm_export.Construct();
+ return true;
+ }
+
+ void Disable() {
+ pcm_export.Destruct();
+ }
+#endif
+
+ bool Open(AudioFormat &audio_format, Error &error);
+
+ void Close() {
+ DoClose();
+ }
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+ void Cancel();
+
+private:
+ /**
+ * Sets up the OSS device which was opened before.
+ */
+ bool Setup(AudioFormat &audio_format, Error &error);
+
+ /**
+ * Reopen the device with the saved audio_format, without any probing.
+ */
+ bool Reopen(Error &error);
+
+ void DoClose();
};
static constexpr Domain oss_output_domain("oss_output");
@@ -124,7 +163,7 @@ oss_stat_device(const char *device, int *errno_r)
return OSS_STAT_NO_ERROR;
}
-static const char *default_devices[] = { "/dev/sound/dsp", "/dev/dsp" };
+static const char *const default_devices[] = { "/dev/sound/dsp", "/dev/dsp" };
static bool
oss_output_test_default_device(void)
@@ -147,24 +186,23 @@ oss_output_test_default_device(void)
return false;
}
-static AudioOutput *
+static OssOutput *
oss_open_default(Error &error)
{
int err[ARRAY_SIZE(default_devices)];
enum oss_stat ret[ARRAY_SIZE(default_devices)];
- const config_param empty;
+ const ConfigBlock empty;
for (int i = ARRAY_SIZE(default_devices); --i >= 0; ) {
ret[i] = oss_stat_device(default_devices[i], &err[i]);
if (ret[i] == OSS_STAT_NO_ERROR) {
- OssOutput *od = new OssOutput();
+ OssOutput *od = new OssOutput(default_devices[i]);
if (!od->Initialize(empty, error)) {
delete od;
- return NULL;
+ return nullptr;
}
- od->device = default_devices[i];
- return &od->base;
+ return od;
}
}
@@ -194,62 +232,33 @@ oss_open_default(Error &error)
error.Set(oss_output_domain,
"error trying to open default OSS device");
- return NULL;
+ return nullptr;
}
-static AudioOutput *
-oss_output_init(const config_param &param, Error &error)
+inline OssOutput *
+OssOutput::Create(const ConfigBlock &block, Error &error)
{
- const char *device = param.GetBlockValue("device");
- if (device != NULL) {
+ const char *device = block.GetBlockValue("device");
+ if (device != nullptr) {
OssOutput *od = new OssOutput();
- if (!od->Initialize(param, error)) {
+ if (!od->Initialize(block, error)) {
delete od;
- return NULL;
+ return nullptr;
}
od->device = device;
- return &od->base;
+ return od;
}
return oss_open_default(error);
}
-static void
-oss_output_finish(AudioOutput *ao)
+void
+OssOutput::DoClose()
{
- OssOutput *od = (OssOutput *)ao;
-
- delete od;
-}
-
-#ifdef AFMT_S24_PACKED
-
-static bool
-oss_output_enable(AudioOutput *ao, gcc_unused Error &error)
-{
- OssOutput *od = (OssOutput *)ao;
-
- od->pcm_export.Construct();
- return true;
-}
-
-static void
-oss_output_disable(AudioOutput *ao)
-{
- OssOutput *od = (OssOutput *)ao;
-
- od->pcm_export.Destruct();
-}
-
-#endif
-
-static void
-oss_close(OssOutput *od)
-{
- if (od->fd >= 0)
- close(od->fd);
- od->fd = -1;
+ if (fd >= 0)
+ close(fd);
+ fd = -1;
}
/**
@@ -271,8 +280,8 @@ oss_try_ioctl_r(int fd, unsigned long request, int *value_r,
const char *msg, Error &error)
{
assert(fd >= 0);
- assert(value_r != NULL);
- assert(msg != NULL);
+ assert(value_r != nullptr);
+ assert(msg != nullptr);
assert(!error.IsDefined());
int ret = ioctl(fd, request, value_r);
@@ -380,7 +389,7 @@ oss_setup_sample_rate(int fd, AudioFormat &audio_format,
break;
}
- static const int sample_rates[] = { 48000, 44100, 0 };
+ static constexpr int sample_rates[] = { 48000, 44100, 0 };
for (unsigned i = 0; sample_rates[i] != 0; ++i) {
sample_rate = sample_rates[i];
if (sample_rate == (int)audio_format.sample_rate)
@@ -412,6 +421,7 @@ oss_setup_sample_rate(int fd, AudioFormat &audio_format,
* Convert a MPD sample format to its OSS counterpart. Returns
* AFMT_QUERY if there is no direct counterpart.
*/
+gcc_const
static int
sample_format_to_oss(SampleFormat format)
{
@@ -442,13 +452,15 @@ sample_format_to_oss(SampleFormat format)
#endif
}
- return AFMT_QUERY;
+ assert(false);
+ gcc_unreachable();
}
/**
* Convert an OSS sample format to its MPD counterpart. Returns
* SampleFormat::UNDEFINED if there is no direct counterpart.
*/
+gcc_const
static SampleFormat
sample_format_from_oss(int format)
{
@@ -572,7 +584,7 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
/* the requested sample format is not available - probe for
other formats supported by MPD */
- static const SampleFormat sample_formats[] = {
+ static constexpr SampleFormat sample_formats[] = {
SampleFormat::S24_P32,
SampleFormat::S32,
SampleFormat::S16,
@@ -609,18 +621,14 @@ oss_setup_sample_format(int fd, AudioFormat &audio_format,
return false;
}
-/**
- * Sets up the OSS device which was opened before.
- */
-static bool
-oss_setup(OssOutput *od, AudioFormat &audio_format,
- Error &error)
+inline bool
+OssOutput::Setup(AudioFormat &_audio_format, Error &error)
{
- return oss_setup_channels(od->fd, audio_format, error) &&
- oss_setup_sample_rate(od->fd, audio_format, error) &&
- oss_setup_sample_format(od->fd, audio_format, &od->oss_format,
+ return oss_setup_channels(fd, _audio_format, error) &&
+ oss_setup_sample_rate(fd, _audio_format, error) &&
+ oss_setup_sample_format(fd, _audio_format, &oss_format,
#ifdef AFMT_S24_PACKED
- od->pcm_export,
+ pcm_export,
#endif
error);
}
@@ -628,46 +636,46 @@ oss_setup(OssOutput *od, AudioFormat &audio_format,
/**
* Reopen the device with the saved audio_format, without any probing.
*/
-static bool
-oss_reopen(OssOutput *od, Error &error)
+inline bool
+OssOutput::Reopen(Error &error)
{
- assert(od->fd < 0);
+ assert(fd < 0);
- od->fd = open_cloexec(od->device, O_WRONLY, 0);
- if (od->fd < 0) {
+ fd = open_cloexec(device, O_WRONLY, 0);
+ if (fd < 0) {
error.FormatErrno("Error opening OSS device \"%s\"",
- od->device);
+ device);
return false;
}
enum oss_setup_result result;
const char *const msg1 = "Failed to set channel count";
- result = oss_try_ioctl(od->fd, SNDCTL_DSP_CHANNELS,
- od->audio_format.channels, msg1, error);
+ result = oss_try_ioctl(fd, SNDCTL_DSP_CHANNELS,
+ audio_format.channels, msg1, error);
if (result != SUCCESS) {
- oss_close(od);
+ DoClose();
if (result == UNSUPPORTED)
error.Set(oss_output_domain, msg1);
return false;
}
const char *const msg2 = "Failed to set sample rate";
- result = oss_try_ioctl(od->fd, SNDCTL_DSP_SPEED,
- od->audio_format.sample_rate, msg2, error);
+ result = oss_try_ioctl(fd, SNDCTL_DSP_SPEED,
+ audio_format.sample_rate, msg2, error);
if (result != SUCCESS) {
- oss_close(od);
+ DoClose();
if (result == UNSUPPORTED)
error.Set(oss_output_domain, msg2);
return false;
}
const char *const msg3 = "Failed to set sample format";
- result = oss_try_ioctl(od->fd, SNDCTL_DSP_SAMPLESIZE,
- od->oss_format,
+ result = oss_try_ioctl(fd, SNDCTL_DSP_SAMPLESIZE,
+ oss_format,
msg3, error);
if (result != SUCCESS) {
- oss_close(od);
+ DoClose();
if (result == UNSUPPORTED)
error.Set(oss_output_domain, msg3);
return false;
@@ -676,62 +684,47 @@ oss_reopen(OssOutput *od, Error &error)
return true;
}
-static bool
-oss_output_open(AudioOutput *ao, AudioFormat &audio_format,
- Error &error)
+inline bool
+OssOutput::Open(AudioFormat &_audio_format, Error &error)
{
- OssOutput *od = (OssOutput *)ao;
-
- od->fd = open_cloexec(od->device, O_WRONLY, 0);
- if (od->fd < 0) {
+ fd = open_cloexec(device, O_WRONLY, 0);
+ if (fd < 0) {
error.FormatErrno("Error opening OSS device \"%s\"",
- od->device);
+ device);
return false;
}
- if (!oss_setup(od, audio_format, error)) {
- oss_close(od);
+ if (!Setup(_audio_format, error)) {
+ DoClose();
return false;
}
- od->audio_format = audio_format;
+ audio_format = _audio_format;
return true;
}
-static void
-oss_output_close(AudioOutput *ao)
+inline void
+OssOutput::Cancel()
{
- OssOutput *od = (OssOutput *)ao;
-
- oss_close(od);
-}
-
-static void
-oss_output_cancel(AudioOutput *ao)
-{
- OssOutput *od = (OssOutput *)ao;
-
- if (od->fd >= 0) {
- ioctl(od->fd, SNDCTL_DSP_RESET, 0);
- oss_close(od);
+ if (fd >= 0) {
+ ioctl(fd, SNDCTL_DSP_RESET, 0);
+ DoClose();
}
}
-static size_t
-oss_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+OssOutput::Play(const void *chunk, size_t size, Error &error)
{
- OssOutput *od = (OssOutput *)ao;
ssize_t ret;
assert(size > 0);
/* reopen the device since it was closed by dropBufferedAudio */
- if (od->fd < 0 && !oss_reopen(od, error))
+ if (fd < 0 && !Reopen(error))
return 0;
#ifdef AFMT_S24_PACKED
- const auto e = od->pcm_export->Export({chunk, size});
+ const auto e = pcm_export->Export({chunk, size});
chunk = e.data;
size = e.size;
#endif
@@ -739,40 +732,42 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size,
assert(size > 0);
while (true) {
- ret = write(od->fd, chunk, size);
+ ret = write(fd, chunk, size);
if (ret > 0) {
#ifdef AFMT_S24_PACKED
- ret = od->pcm_export->CalcSourceSize(ret);
+ ret = pcm_export->CalcSourceSize(ret);
#endif
return ret;
}
if (ret < 0 && errno != EINTR) {
- error.FormatErrno("Write error on %s", od->device);
+ error.FormatErrno("Write error on %s", device);
return 0;
}
}
}
+typedef AudioOutputWrapper<OssOutput> Wrapper;
+
const struct AudioOutputPlugin oss_output_plugin = {
"oss",
oss_output_test_default_device,
- oss_output_init,
- oss_output_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
#ifdef AFMT_S24_PACKED
- oss_output_enable,
- oss_output_disable,
+ &Wrapper::Enable,
+ &Wrapper::Disable,
#else
nullptr,
nullptr,
#endif
- oss_output_open,
- oss_output_close,
+ &Wrapper::Open,
+ &Wrapper::Close,
nullptr,
nullptr,
- oss_output_play,
+ &Wrapper::Play,
nullptr,
- oss_output_cancel,
+ &Wrapper::Cancel,
nullptr,
&oss_mixer_plugin,
diff --git a/src/output/plugins/OssOutputPlugin.hxx b/src/output/plugins/OssOutputPlugin.hxx
index f9970c8f0..8f9b3d424 100644
--- a/src/output/plugins/OssOutputPlugin.hxx
+++ b/src/output/plugins/OssOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/PipeOutputPlugin.cxx b/src/output/plugins/PipeOutputPlugin.cxx
index d8075d505..c70e2d498 100644
--- a/src/output/plugins/PipeOutputPlugin.cxx
+++ b/src/output/plugins/PipeOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "PipeOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "config/ConfigError.hxx"
#include "util/Error.hxx"
@@ -27,7 +28,9 @@
#include <stdio.h>
-struct PipeOutput {
+class PipeOutput {
+ friend struct AudioOutputWrapper<PipeOutput>;
+
AudioOutput base;
std::string cmd;
@@ -36,17 +39,27 @@ struct PipeOutput {
PipeOutput()
:base(pipe_output_plugin) {}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ bool Configure(const ConfigBlock &block, Error &error);
+
+public:
+ static PipeOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Open(AudioFormat &audio_format, Error &error);
+
+ void Close() {
+ pclose(fh);
}
- bool Configure(const config_param &param, Error &error);
+ size_t Play(const void *chunk, size_t size, Error &error);
};
inline bool
-PipeOutput::Configure(const config_param &param, Error &error)
+PipeOutput::Configure(const ConfigBlock &block, Error &error)
{
- cmd = param.GetBlockValue("command", "");
+ if (!base.Configure(block, error))
+ return false;
+
+ cmd = block.GetBlockValue("command", "");
if (cmd.empty()) {
error.Set(config_domain,
"No \"command\" parameter specified");
@@ -56,83 +69,56 @@ PipeOutput::Configure(const config_param &param, Error &error)
return true;
}
-static AudioOutput *
-pipe_output_init(const config_param &param, Error &error)
+inline PipeOutput *
+PipeOutput::Create(const ConfigBlock &block, Error &error)
{
- PipeOutput *pd = new PipeOutput();
+ PipeOutput *po = new PipeOutput();
- if (!pd->Initialize(param, error)) {
- delete pd;
+ if (!po->Configure(block, error)) {
+ delete po;
return nullptr;
}
- if (!pd->Configure(param, error)) {
- delete pd;
- return nullptr;
- }
-
- return &pd->base;
+ return po;
}
-static void
-pipe_output_finish(AudioOutput *ao)
-{
- PipeOutput *pd = (PipeOutput *)ao;
-
- delete pd;
-}
-
-static bool
-pipe_output_open(AudioOutput *ao,
- gcc_unused AudioFormat &audio_format,
- Error &error)
+inline bool
+PipeOutput::Open(gcc_unused AudioFormat &audio_format, Error &error)
{
- PipeOutput *pd = (PipeOutput *)ao;
-
- pd->fh = popen(pd->cmd.c_str(), "w");
- if (pd->fh == nullptr) {
+ fh = popen(cmd.c_str(), "w");
+ if (fh == nullptr) {
error.FormatErrno("Error opening pipe \"%s\"",
- pd->cmd.c_str());
+ cmd.c_str());
return false;
}
return true;
}
-static void
-pipe_output_close(AudioOutput *ao)
-{
- PipeOutput *pd = (PipeOutput *)ao;
-
- pclose(pd->fh);
-}
-
-static size_t
-pipe_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+PipeOutput::Play(const void *chunk, size_t size, Error &error)
{
- PipeOutput *pd = (PipeOutput *)ao;
- size_t ret;
-
- ret = fwrite(chunk, 1, size, pd->fh);
- if (ret == 0)
+ size_t nbytes = fwrite(chunk, 1, size, fh);
+ if (nbytes == 0)
error.SetErrno("Write error on pipe");
- return ret;
+ return nbytes;
}
+typedef AudioOutputWrapper<PipeOutput> Wrapper;
+
const struct AudioOutputPlugin pipe_output_plugin = {
"pipe",
nullptr,
- pipe_output_init,
- pipe_output_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
nullptr,
- pipe_output_open,
- pipe_output_close,
+ &Wrapper::Open,
+ &Wrapper::Close,
nullptr,
nullptr,
- pipe_output_play,
+ &Wrapper::Play,
nullptr,
nullptr,
nullptr,
diff --git a/src/output/plugins/PipeOutputPlugin.hxx b/src/output/plugins/PipeOutputPlugin.hxx
index bdaf2ecfd..5d92848c2 100644
--- a/src/output/plugins/PipeOutputPlugin.hxx
+++ b/src/output/plugins/PipeOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/PulseOutputPlugin.cxx b/src/output/plugins/PulseOutputPlugin.cxx
index 120bad090..8b5225584 100644
--- a/src/output/plugins/PulseOutputPlugin.cxx
+++ b/src/output/plugins/PulseOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,11 +19,14 @@
#include "config.h"
#include "PulseOutputPlugin.hxx"
+#include "lib/pulse/Domain.hxx"
+#include "lib/pulse/Error.hxx"
+#include "lib/pulse/LogError.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "mixer/plugins/PulseMixerPlugin.hxx"
#include "util/Error.hxx"
-#include "util/Domain.hxx"
#include "Log.hxx"
#include <pulse/thread-mainloop.h>
@@ -31,7 +34,6 @@
#include <pulse/stream.h>
#include <pulse/introspect.h>
#include <pulse/subscribe.h>
-#include <pulse/error.h>
#include <pulse/version.h>
#include <assert.h>
@@ -40,7 +42,9 @@
#define MPD_PULSE_NAME "Music Player Daemon"
-struct PulseOutput {
+class PulseOutput {
+ friend struct AudioOutputWrapper<PulseOutput>;
+
AudioOutput base;
const char *name;
@@ -56,80 +60,190 @@ struct PulseOutput {
size_t writable;
PulseOutput()
- :base(pulse_output_plugin) {}
-};
+ :base(pulse_output_plugin),
+ mixer(nullptr),
+ mainloop(nullptr), stream(nullptr) {}
-static constexpr Domain pulse_output_domain("pulse_output");
+public:
+ void SetMixer(PulseMixer &_mixer);
-static void
-SetError(Error &error, pa_context *context, const char *msg)
-{
- const int e = pa_context_errno(context);
- error.Format(pulse_output_domain, e, "%s: %s", msg, pa_strerror(e));
-}
+ void ClearMixer(gcc_unused PulseMixer &old_mixer) {
+ assert(mixer == &old_mixer);
+
+ mixer = nullptr;
+ }
+
+ bool SetVolume(const pa_cvolume &volume, Error &error);
+
+ void Lock() {
+ pa_threaded_mainloop_lock(mainloop);
+ }
+
+ void Unlock() {
+ pa_threaded_mainloop_unlock(mainloop);
+ }
+
+ void OnContextStateChanged(pa_context_state_t new_state);
+ void OnServerLayoutChanged(pa_subscription_event_type_t t,
+ uint32_t idx);
+ void OnStreamSuspended(pa_stream *_stream);
+ void OnStreamStateChanged(pa_stream *_stream,
+ pa_stream_state_t new_state);
+ void OnStreamWrite(size_t nbytes);
+
+ void OnStreamSuccess() {
+ Signal();
+ }
+
+ gcc_const
+ static bool TestDefaultDevice();
+
+ bool Configure(const ConfigBlock &block, Error &error);
+ static PulseOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Enable(Error &error);
+ void Disable();
+
+ bool Open(AudioFormat &audio_format, Error &error);
+ void Close();
+
+ unsigned Delay();
+ size_t Play(const void *chunk, size_t size, Error &error);
+ void Cancel();
+ bool Pause();
+
+private:
+ /**
+ * Attempt to connect asynchronously to the PulseAudio server.
+ *
+ * @return true on success, false on error
+ */
+ bool Connect(Error &error);
+
+ /**
+ * Create, set up and connect a context.
+ *
+ * Caller must lock the main loop.
+ *
+ * @return true on success, false on error
+ */
+ bool SetupContext(Error &error);
+
+ /**
+ * Frees and clears the context.
+ *
+ * Caller must lock the main loop.
+ */
+ void DeleteContext();
+
+ void Signal() {
+ pa_threaded_mainloop_signal(mainloop, 0);
+ }
+
+ /**
+ * Check if the context is (already) connected, and waits if
+ * not. If the context has been disconnected, retry to
+ * connect.
+ *
+ * Caller must lock the main loop.
+ *
+ * @return true on success, false on error
+ */
+ bool WaitConnection(Error &error);
+
+ /**
+ * Create, set up and connect a context.
+ *
+ * Caller must lock the main loop.
+ *
+ * @return true on success, false on error
+ */
+ bool SetupStream(const pa_sample_spec &ss, Error &error);
+
+ /**
+ * Frees and clears the stream.
+ */
+ void DeleteStream();
+
+ /**
+ * Check if the stream is (already) connected, and waits if
+ * not. The mainloop must be locked before calling this
+ * function.
+ *
+ * @return true on success, false on error
+ */
+ bool WaitStream(Error &error);
+
+ /**
+ * Sets cork mode on the stream.
+ */
+ bool StreamPause(bool pause, Error &error);
+};
void
pulse_output_lock(PulseOutput &po)
{
- pa_threaded_mainloop_lock(po.mainloop);
+ po.Lock();
}
void
pulse_output_unlock(PulseOutput &po)
{
- pa_threaded_mainloop_unlock(po.mainloop);
+ po.Unlock();
}
-void
-pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm)
+inline void
+PulseOutput::SetMixer(PulseMixer &_mixer)
{
- assert(po.mixer == nullptr);
+ assert(mixer == nullptr);
- po.mixer = &pm;
+ mixer = &_mixer;
- if (po.mainloop == nullptr)
+ if (mainloop == nullptr)
return;
- pa_threaded_mainloop_lock(po.mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (po.context != nullptr &&
- pa_context_get_state(po.context) == PA_CONTEXT_READY) {
- pulse_mixer_on_connect(pm, po.context);
+ if (context != nullptr &&
+ pa_context_get_state(context) == PA_CONTEXT_READY) {
+ pulse_mixer_on_connect(_mixer, context);
- if (po.stream != nullptr &&
- pa_stream_get_state(po.stream) == PA_STREAM_READY)
- pulse_mixer_on_change(pm, po.context, po.stream);
+ if (stream != nullptr &&
+ pa_stream_get_state(stream) == PA_STREAM_READY)
+ pulse_mixer_on_change(_mixer, context, stream);
}
- pa_threaded_mainloop_unlock(po.mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
}
void
-pulse_output_clear_mixer(PulseOutput &po, gcc_unused PulseMixer &pm)
+pulse_output_set_mixer(PulseOutput &po, PulseMixer &pm)
{
- assert(po.mixer == &pm);
-
- po.mixer = nullptr;
+ po.SetMixer(pm);
}
-bool
-pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume,
- Error &error)
+void
+pulse_output_clear_mixer(PulseOutput &po, PulseMixer &pm)
{
- pa_operation *o;
+ po.ClearMixer(pm);
+}
- if (po.context == nullptr || po.stream == nullptr ||
- pa_stream_get_state(po.stream) != PA_STREAM_READY) {
- error.Set(pulse_output_domain, "disconnected");
+inline bool
+PulseOutput::SetVolume(const pa_cvolume &volume, Error &error)
+{
+ if (context == nullptr || stream == nullptr ||
+ pa_stream_get_state(stream) != PA_STREAM_READY) {
+ error.Set(pulse_domain, "disconnected");
return false;
}
- o = pa_context_set_sink_input_volume(po.context,
- pa_stream_get_index(po.stream),
- volume, nullptr, nullptr);
+ pa_operation *o =
+ pa_context_set_sink_input_volume(context,
+ pa_stream_get_index(stream),
+ &volume, nullptr, nullptr);
if (o == nullptr) {
- SetError(error, po.context,
- "failed to set PulseAudio volume");
+ SetPulseError(error, context,
+ "failed to set PulseAudio volume");
return false;
}
@@ -137,6 +251,13 @@ pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume,
return true;
}
+bool
+pulse_output_set_volume(PulseOutput &po, const pa_cvolume *volume,
+ Error &error)
+{
+ return po.SetVolume(*volume, error);
+}
+
/**
* \brief waits for a pulseaudio operation to finish, frees it and
* unlocks the mainloop
@@ -169,32 +290,30 @@ static void
pulse_output_stream_success_cb(gcc_unused pa_stream *s,
gcc_unused int success, void *userdata)
{
- PulseOutput *po = (PulseOutput *)userdata;
+ PulseOutput &po = *(PulseOutput *)userdata;
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ po.OnStreamSuccess();
}
-static void
-pulse_output_context_state_cb(struct pa_context *context, void *userdata)
+inline void
+PulseOutput::OnContextStateChanged(pa_context_state_t new_state)
{
- PulseOutput *po = (PulseOutput *)userdata;
-
- switch (pa_context_get_state(context)) {
+ switch (new_state) {
case PA_CONTEXT_READY:
- if (po->mixer != nullptr)
- pulse_mixer_on_connect(*po->mixer, context);
+ if (mixer != nullptr)
+ pulse_mixer_on_connect(*mixer, context);
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ Signal();
break;
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
- if (po->mixer != nullptr)
- pulse_mixer_on_disconnect(*po->mixer);
+ if (mixer != nullptr)
+ pulse_mixer_on_disconnect(*mixer);
/* the caller thread might be waiting for these
states */
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ Signal();
break;
case PA_CONTEXT_UNCONNECTED:
@@ -206,230 +325,203 @@ pulse_output_context_state_cb(struct pa_context *context, void *userdata)
}
static void
-pulse_output_subscribe_cb(pa_context *context,
- pa_subscription_event_type_t t,
- uint32_t idx, void *userdata)
+pulse_output_context_state_cb(struct pa_context *context, void *userdata)
+{
+ PulseOutput &po = *(PulseOutput *)userdata;
+
+ po.OnContextStateChanged(pa_context_get_state(context));
+}
+
+inline void
+PulseOutput::OnServerLayoutChanged(pa_subscription_event_type_t t,
+ uint32_t idx)
{
- PulseOutput *po = (PulseOutput *)userdata;
pa_subscription_event_type_t facility =
pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK);
pa_subscription_event_type_t type =
pa_subscription_event_type_t(t & PA_SUBSCRIPTION_EVENT_TYPE_MASK);
- if (po->mixer != nullptr &&
+ if (mixer != nullptr &&
facility == PA_SUBSCRIPTION_EVENT_SINK_INPUT &&
- po->stream != nullptr &&
- pa_stream_get_state(po->stream) == PA_STREAM_READY &&
- idx == pa_stream_get_index(po->stream) &&
+ stream != nullptr &&
+ pa_stream_get_state(stream) == PA_STREAM_READY &&
+ idx == pa_stream_get_index(stream) &&
(type == PA_SUBSCRIPTION_EVENT_NEW ||
type == PA_SUBSCRIPTION_EVENT_CHANGE))
- pulse_mixer_on_change(*po->mixer, context, po->stream);
+ pulse_mixer_on_change(*mixer, context, stream);
}
-/**
- * Attempt to connect asynchronously to the PulseAudio server.
- *
- * @return true on success, false on error
- */
-static bool
-pulse_output_connect(PulseOutput *po, Error &error)
+static void
+pulse_output_subscribe_cb(gcc_unused pa_context *context,
+ pa_subscription_event_type_t t,
+ uint32_t idx, void *userdata)
{
- assert(po != nullptr);
- assert(po->context != nullptr);
+ PulseOutput &po = *(PulseOutput *)userdata;
- if (pa_context_connect(po->context, po->server,
+ po.OnServerLayoutChanged(t, idx);
+}
+
+inline bool
+PulseOutput::Connect(Error &error)
+{
+ assert(context != nullptr);
+
+ if (pa_context_connect(context, server,
(pa_context_flags_t)0, nullptr) < 0) {
- SetError(error, po->context,
- "pa_context_connect() has failed");
+ SetPulseError(error, context,
+ "pa_context_connect() has failed");
return false;
}
return true;
}
-/**
- * Frees and clears the stream.
- */
-static void
-pulse_output_delete_stream(PulseOutput *po)
+void
+PulseOutput::DeleteStream()
{
- assert(po != nullptr);
- assert(po->stream != nullptr);
+ assert(stream != nullptr);
- pa_stream_set_suspended_callback(po->stream, nullptr, nullptr);
+ pa_stream_set_suspended_callback(stream, nullptr, nullptr);
- pa_stream_set_state_callback(po->stream, nullptr, nullptr);
- pa_stream_set_write_callback(po->stream, nullptr, nullptr);
+ pa_stream_set_state_callback(stream, nullptr, nullptr);
+ pa_stream_set_write_callback(stream, nullptr, nullptr);
- pa_stream_disconnect(po->stream);
- pa_stream_unref(po->stream);
- po->stream = nullptr;
+ pa_stream_disconnect(stream);
+ pa_stream_unref(stream);
+ stream = nullptr;
}
-/**
- * Frees and clears the context.
- *
- * Caller must lock the main loop.
- */
-static void
-pulse_output_delete_context(PulseOutput *po)
+void
+PulseOutput::DeleteContext()
{
- assert(po != nullptr);
- assert(po->context != nullptr);
+ assert(context != nullptr);
- pa_context_set_state_callback(po->context, nullptr, nullptr);
- pa_context_set_subscribe_callback(po->context, nullptr, nullptr);
+ pa_context_set_state_callback(context, nullptr, nullptr);
+ pa_context_set_subscribe_callback(context, nullptr, nullptr);
- pa_context_disconnect(po->context);
- pa_context_unref(po->context);
- po->context = nullptr;
+ pa_context_disconnect(context);
+ pa_context_unref(context);
+ context = nullptr;
}
-/**
- * Create, set up and connect a context.
- *
- * Caller must lock the main loop.
- *
- * @return true on success, false on error
- */
-static bool
-pulse_output_setup_context(PulseOutput *po, Error &error)
+bool
+PulseOutput::SetupContext(Error &error)
{
- assert(po != nullptr);
- assert(po->mainloop != nullptr);
+ assert(mainloop != nullptr);
- po->context = pa_context_new(pa_threaded_mainloop_get_api(po->mainloop),
- MPD_PULSE_NAME);
- if (po->context == nullptr) {
- error.Set(pulse_output_domain, "pa_context_new() has failed");
+ context = pa_context_new(pa_threaded_mainloop_get_api(mainloop),
+ MPD_PULSE_NAME);
+ if (context == nullptr) {
+ error.Set(pulse_domain, "pa_context_new() has failed");
return false;
}
- pa_context_set_state_callback(po->context,
- pulse_output_context_state_cb, po);
- pa_context_set_subscribe_callback(po->context,
- pulse_output_subscribe_cb, po);
+ pa_context_set_state_callback(context,
+ pulse_output_context_state_cb, this);
+ pa_context_set_subscribe_callback(context,
+ pulse_output_subscribe_cb, this);
- if (!pulse_output_connect(po, error)) {
- pulse_output_delete_context(po);
+ if (!Connect(error)) {
+ DeleteContext();
return false;
}
return true;
}
-static AudioOutput *
-pulse_output_init(const config_param &param, Error &error)
+inline bool
+PulseOutput::Configure(const ConfigBlock &block, Error &error)
{
- PulseOutput *po;
+ if (!base.Configure(block, error))
+ return false;
+
+ name = block.GetBlockValue("name", "mpd_pulse");
+ server = block.GetBlockValue("server");
+ sink = block.GetBlockValue("sink");
+ return true;
+}
+
+PulseOutput *
+PulseOutput::Create(const ConfigBlock &block, Error &error)
+{
setenv("PULSE_PROP_media.role", "music", true);
setenv("PULSE_PROP_application.icon_name", "mpd", true);
- po = new PulseOutput();
- if (!po->base.Configure(param, error)) {
+ auto *po = new PulseOutput();
+ if (!po->Configure(block, error)) {
delete po;
return nullptr;
}
- po->name = param.GetBlockValue("name", "mpd_pulse");
- po->server = param.GetBlockValue("server");
- po->sink = param.GetBlockValue("sink");
-
- po->mixer = nullptr;
- po->mainloop = nullptr;
- po->context = nullptr;
- po->stream = nullptr;
-
- return &po->base;
+ return po;
}
-static void
-pulse_output_finish(AudioOutput *ao)
+inline bool
+PulseOutput::Enable(Error &error)
{
- PulseOutput *po = (PulseOutput *)ao;
-
- delete po;
-}
-
-static bool
-pulse_output_enable(AudioOutput *ao, Error &error)
-{
- PulseOutput *po = (PulseOutput *)ao;
-
- assert(po->mainloop == nullptr);
- assert(po->context == nullptr);
+ assert(mainloop == nullptr);
/* create the libpulse mainloop and start the thread */
- po->mainloop = pa_threaded_mainloop_new();
- if (po->mainloop == nullptr) {
- error.Set(pulse_output_domain,
+ mainloop = pa_threaded_mainloop_new();
+ if (mainloop == nullptr) {
+ error.Set(pulse_domain,
"pa_threaded_mainloop_new() has failed");
return false;
}
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (pa_threaded_mainloop_start(po->mainloop) < 0) {
- pa_threaded_mainloop_unlock(po->mainloop);
- pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = nullptr;
+ if (pa_threaded_mainloop_start(mainloop) < 0) {
+ pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_free(mainloop);
+ mainloop = nullptr;
- error.Set(pulse_output_domain,
+ error.Set(pulse_domain,
"pa_threaded_mainloop_start() has failed");
return false;
}
/* create the libpulse context and connect it */
- if (!pulse_output_setup_context(po, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
- pa_threaded_mainloop_stop(po->mainloop);
- pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = nullptr;
+ if (!SetupContext(error)) {
+ pa_threaded_mainloop_unlock(mainloop);
+ pa_threaded_mainloop_stop(mainloop);
+ pa_threaded_mainloop_free(mainloop);
+ mainloop = nullptr;
return false;
}
- pa_threaded_mainloop_unlock(po->mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
return true;
}
-static void
-pulse_output_disable(AudioOutput *ao)
+inline void
+PulseOutput::Disable()
{
- PulseOutput *po = (PulseOutput *)ao;
-
- assert(po->mainloop != nullptr);
+ assert(mainloop != nullptr);
- pa_threaded_mainloop_stop(po->mainloop);
- if (po->context != nullptr)
- pulse_output_delete_context(po);
- pa_threaded_mainloop_free(po->mainloop);
- po->mainloop = nullptr;
+ pa_threaded_mainloop_stop(mainloop);
+ if (context != nullptr)
+ DeleteContext();
+ pa_threaded_mainloop_free(mainloop);
+ mainloop = nullptr;
}
-/**
- * Check if the context is (already) connected, and waits if not. If
- * the context has been disconnected, retry to connect.
- *
- * Caller must lock the main loop.
- *
- * @return true on success, false on error
- */
-static bool
-pulse_output_wait_connection(PulseOutput *po, Error &error)
+bool
+PulseOutput::WaitConnection(Error &error)
{
- assert(po->mainloop != nullptr);
+ assert(mainloop != nullptr);
pa_context_state_t state;
- if (po->context == nullptr && !pulse_output_setup_context(po, error))
+ if (context == nullptr && !SetupContext(error))
return false;
while (true) {
- state = pa_context_get_state(po->context);
+ state = pa_context_get_state(context);
switch (state) {
case PA_CONTEXT_READY:
/* nothing to do */
@@ -439,56 +531,61 @@ pulse_output_wait_connection(PulseOutput *po, Error &error)
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
/* failure */
- SetError(error, po->context, "failed to connect");
- pulse_output_delete_context(po);
+ SetPulseError(error, context, "failed to connect");
+ DeleteContext();
return false;
case PA_CONTEXT_CONNECTING:
case PA_CONTEXT_AUTHORIZING:
case PA_CONTEXT_SETTING_NAME:
/* wait some more */
- pa_threaded_mainloop_wait(po->mainloop);
+ pa_threaded_mainloop_wait(mainloop);
break;
}
}
}
-static void
-pulse_output_stream_suspended_cb(gcc_unused pa_stream *stream, void *userdata)
+inline void
+PulseOutput::OnStreamSuspended(gcc_unused pa_stream *_stream)
{
- PulseOutput *po = (PulseOutput *)userdata;
-
- assert(stream == po->stream || po->stream == nullptr);
- assert(po->mainloop != nullptr);
+ assert(_stream == stream || stream == nullptr);
+ assert(mainloop != nullptr);
/* wake up the main loop to break out of the loop in
pulse_output_play() */
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ Signal();
}
static void
-pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
+pulse_output_stream_suspended_cb(pa_stream *stream, void *userdata)
{
- PulseOutput *po = (PulseOutput *)userdata;
+ PulseOutput &po = *(PulseOutput *)userdata;
- assert(stream == po->stream || po->stream == nullptr);
- assert(po->mainloop != nullptr);
- assert(po->context != nullptr);
+ po.OnStreamSuspended(stream);
+}
+
+inline void
+PulseOutput::OnStreamStateChanged(pa_stream *_stream,
+ pa_stream_state_t new_state)
+{
+ assert(_stream == stream || stream == nullptr);
+ assert(mainloop != nullptr);
+ assert(context != nullptr);
- switch (pa_stream_get_state(stream)) {
+ switch (new_state) {
case PA_STREAM_READY:
- if (po->mixer != nullptr)
- pulse_mixer_on_change(*po->mixer, po->context, stream);
+ if (mixer != nullptr)
+ pulse_mixer_on_change(*mixer, context, _stream);
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ Signal();
break;
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
- if (po->mixer != nullptr)
- pulse_mixer_on_disconnect(*po->mixer);
+ if (mixer != nullptr)
+ pulse_mixer_on_disconnect(*mixer);
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ Signal();
break;
case PA_STREAM_UNCONNECTED:
@@ -498,68 +595,75 @@ pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
}
static void
+pulse_output_stream_state_cb(pa_stream *stream, void *userdata)
+{
+ PulseOutput &po = *(PulseOutput *)userdata;
+
+ return po.OnStreamStateChanged(stream, pa_stream_get_state(stream));
+}
+
+inline void
+PulseOutput::OnStreamWrite(size_t nbytes)
+{
+ assert(mainloop != nullptr);
+
+ writable = nbytes;
+ Signal();
+}
+
+static void
pulse_output_stream_write_cb(gcc_unused pa_stream *stream, size_t nbytes,
void *userdata)
{
- PulseOutput *po = (PulseOutput *)userdata;
-
- assert(po->mainloop != nullptr);
+ PulseOutput &po = *(PulseOutput *)userdata;
- po->writable = nbytes;
- pa_threaded_mainloop_signal(po->mainloop, 0);
+ return po.OnStreamWrite(nbytes);
}
-/**
- * Create, set up and connect a context.
- *
- * Caller must lock the main loop.
- *
- * @return true on success, false on error
- */
-static bool
-pulse_output_setup_stream(PulseOutput *po, const pa_sample_spec *ss,
- Error &error)
+inline bool
+PulseOutput::SetupStream(const pa_sample_spec &ss, Error &error)
{
- assert(po != nullptr);
- assert(po->context != nullptr);
+ assert(context != nullptr);
- po->stream = pa_stream_new(po->context, po->name, ss, nullptr);
- if (po->stream == nullptr) {
- SetError(error, po->context, "pa_stream_new() has failed");
+ /* WAVE-EX is been adopted as the speaker map for most media files */
+ pa_channel_map chan_map;
+ pa_channel_map_init_auto(&chan_map, ss.channels,
+ PA_CHANNEL_MAP_WAVEEX);
+ stream = pa_stream_new(context, name, &ss, &chan_map);
+ if (stream == nullptr) {
+ SetPulseError(error, context,
+ "pa_stream_new() has failed");
return false;
}
- pa_stream_set_suspended_callback(po->stream,
- pulse_output_stream_suspended_cb, po);
+ pa_stream_set_suspended_callback(stream,
+ pulse_output_stream_suspended_cb,
+ this);
- pa_stream_set_state_callback(po->stream,
- pulse_output_stream_state_cb, po);
- pa_stream_set_write_callback(po->stream,
- pulse_output_stream_write_cb, po);
+ pa_stream_set_state_callback(stream,
+ pulse_output_stream_state_cb, this);
+ pa_stream_set_write_callback(stream,
+ pulse_output_stream_write_cb, this);
return true;
}
-static bool
-pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
- Error &error)
+inline bool
+PulseOutput::Open(AudioFormat &audio_format, Error &error)
{
- PulseOutput *po = (PulseOutput *)ao;
- pa_sample_spec ss;
-
- assert(po->mainloop != nullptr);
+ assert(mainloop != nullptr);
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (po->context != nullptr) {
- switch (pa_context_get_state(po->context)) {
+ if (context != nullptr) {
+ switch (pa_context_get_state(context)) {
case PA_CONTEXT_UNCONNECTED:
case PA_CONTEXT_TERMINATED:
case PA_CONTEXT_FAILED:
/* the connection was closed meanwhile; delete
it, and pulse_output_wait_connection() will
reopen it */
- pulse_output_delete_context(po);
+ DeleteContext();
break;
case PA_CONTEXT_READY:
@@ -570,8 +674,8 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
}
}
- if (!pulse_output_wait_connection(po, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (!WaitConnection(error)) {
+ pa_threaded_mainloop_unlock(mainloop);
return false;
}
@@ -579,304 +683,282 @@ pulse_output_open(AudioOutput *ao, AudioFormat &audio_format,
we just force MPD to send us everything as 16 bit */
audio_format.format = SampleFormat::S16;
+ pa_sample_spec ss;
ss.format = PA_SAMPLE_S16NE;
ss.rate = audio_format.sample_rate;
ss.channels = audio_format.channels;
/* create a stream .. */
- if (!pulse_output_setup_stream(po, &ss, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (!SetupStream(ss, error)) {
+ pa_threaded_mainloop_unlock(mainloop);
return false;
}
/* .. and connect it (asynchronously) */
- if (pa_stream_connect_playback(po->stream, po->sink,
+ if (pa_stream_connect_playback(stream, sink,
nullptr, pa_stream_flags_t(0),
nullptr, nullptr) < 0) {
- pulse_output_delete_stream(po);
+ DeleteStream();
- SetError(error, po->context,
- "pa_stream_connect_playback() has failed");
- pa_threaded_mainloop_unlock(po->mainloop);
+ SetPulseError(error, context,
+ "pa_stream_connect_playback() has failed");
+ pa_threaded_mainloop_unlock(mainloop);
return false;
}
- pa_threaded_mainloop_unlock(po->mainloop);
-
+ pa_threaded_mainloop_unlock(mainloop);
return true;
}
-static void
-pulse_output_close(AudioOutput *ao)
+inline void
+PulseOutput::Close()
{
- PulseOutput *po = (PulseOutput *)ao;
- pa_operation *o;
-
- assert(po->mainloop != nullptr);
+ assert(mainloop != nullptr);
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (pa_stream_get_state(po->stream) == PA_STREAM_READY) {
- o = pa_stream_drain(po->stream,
- pulse_output_stream_success_cb, po);
+ if (pa_stream_get_state(stream) == PA_STREAM_READY) {
+ pa_operation *o =
+ pa_stream_drain(stream,
+ pulse_output_stream_success_cb, this);
if (o == nullptr) {
- FormatWarning(pulse_output_domain,
- "pa_stream_drain() has failed: %s",
- pa_strerror(pa_context_errno(po->context)));
+ LogPulseError(context,
+ "pa_stream_drain() has failed");
} else
- pulse_wait_for_operation(po->mainloop, o);
+ pulse_wait_for_operation(mainloop, o);
}
- pulse_output_delete_stream(po);
+ DeleteStream();
- if (po->context != nullptr &&
- pa_context_get_state(po->context) != PA_CONTEXT_READY)
- pulse_output_delete_context(po);
+ if (context != nullptr &&
+ pa_context_get_state(context) != PA_CONTEXT_READY)
+ DeleteContext();
- pa_threaded_mainloop_unlock(po->mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
}
-/**
- * Check if the stream is (already) connected, and waits if not. The
- * mainloop must be locked before calling this function.
- *
- * @return true on success, false on error
- */
-static bool
-pulse_output_wait_stream(PulseOutput *po, Error &error)
+bool
+PulseOutput::WaitStream(Error &error)
{
while (true) {
- switch (pa_stream_get_state(po->stream)) {
+ switch (pa_stream_get_state(stream)) {
case PA_STREAM_READY:
return true;
case PA_STREAM_FAILED:
case PA_STREAM_TERMINATED:
case PA_STREAM_UNCONNECTED:
- SetError(error, po->context,
- "failed to connect the stream");
+ SetPulseError(error, context,
+ "failed to connect the stream");
return false;
case PA_STREAM_CREATING:
- pa_threaded_mainloop_wait(po->mainloop);
+ pa_threaded_mainloop_wait(mainloop);
break;
}
}
}
-/**
- * Sets cork mode on the stream.
- */
-static bool
-pulse_output_stream_pause(PulseOutput *po, bool pause,
- Error &error)
+bool
+PulseOutput::StreamPause(bool pause, Error &error)
{
- pa_operation *o;
-
- assert(po->mainloop != nullptr);
- assert(po->context != nullptr);
- assert(po->stream != nullptr);
+ assert(mainloop != nullptr);
+ assert(context != nullptr);
+ assert(stream != nullptr);
- o = pa_stream_cork(po->stream, pause,
- pulse_output_stream_success_cb, po);
+ pa_operation *o = pa_stream_cork(stream, pause,
+ pulse_output_stream_success_cb, this);
if (o == nullptr) {
- SetError(error, po->context, "pa_stream_cork() has failed");
+ SetPulseError(error, context,
+ "pa_stream_cork() has failed");
return false;
}
- if (!pulse_wait_for_operation(po->mainloop, o)) {
- SetError(error, po->context, "pa_stream_cork() has failed");
+ if (!pulse_wait_for_operation(mainloop, o)) {
+ SetPulseError(error, context,
+ "pa_stream_cork() has failed");
return false;
}
return true;
}
-static unsigned
-pulse_output_delay(AudioOutput *ao)
+inline unsigned
+PulseOutput::Delay()
{
- PulseOutput *po = (PulseOutput *)ao;
- unsigned result = 0;
-
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (po->base.pause && pa_stream_is_corked(po->stream) &&
- pa_stream_get_state(po->stream) == PA_STREAM_READY)
+ unsigned result = 0;
+ if (base.pause && pa_stream_is_corked(stream) &&
+ pa_stream_get_state(stream) == PA_STREAM_READY)
/* idle while paused */
result = 1000;
- pa_threaded_mainloop_unlock(po->mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
return result;
}
-static size_t
-pulse_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+PulseOutput::Play(const void *chunk, size_t size, Error &error)
{
- PulseOutput *po = (PulseOutput *)ao;
-
- assert(po->mainloop != nullptr);
- assert(po->stream != nullptr);
+ assert(mainloop != nullptr);
+ assert(stream != nullptr);
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
/* check if the stream is (already) connected */
- if (!pulse_output_wait_stream(po, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (!WaitStream(error)) {
+ pa_threaded_mainloop_unlock(mainloop);
return 0;
}
- assert(po->context != nullptr);
+ assert(context != nullptr);
/* unpause if previously paused */
- if (pa_stream_is_corked(po->stream) &&
- !pulse_output_stream_pause(po, false, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (pa_stream_is_corked(stream) && !StreamPause(false, error)) {
+ pa_threaded_mainloop_unlock(mainloop);
return 0;
}
/* wait until the server allows us to write */
- while (po->writable == 0) {
- if (pa_stream_is_suspended(po->stream)) {
- pa_threaded_mainloop_unlock(po->mainloop);
- error.Set(pulse_output_domain, "suspended");
+ while (writable == 0) {
+ if (pa_stream_is_suspended(stream)) {
+ pa_threaded_mainloop_unlock(mainloop);
+ error.Set(pulse_domain, "suspended");
return 0;
}
- pa_threaded_mainloop_wait(po->mainloop);
+ pa_threaded_mainloop_wait(mainloop);
- if (pa_stream_get_state(po->stream) != PA_STREAM_READY) {
- pa_threaded_mainloop_unlock(po->mainloop);
- error.Set(pulse_output_domain, "disconnected");
+ if (pa_stream_get_state(stream) != PA_STREAM_READY) {
+ pa_threaded_mainloop_unlock(mainloop);
+ error.Set(pulse_domain, "disconnected");
return 0;
}
}
/* now write */
- if (size > po->writable)
+ if (size > writable)
/* don't send more than possible */
- size = po->writable;
+ size = writable;
- po->writable -= size;
+ writable -= size;
- int result = pa_stream_write(po->stream, chunk, size, nullptr,
+ int result = pa_stream_write(stream, chunk, size, nullptr,
0, PA_SEEK_RELATIVE);
- pa_threaded_mainloop_unlock(po->mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
if (result < 0) {
- SetError(error, po->context, "pa_stream_write() failed");
+ SetPulseError(error, context, "pa_stream_write() failed");
return 0;
}
return size;
}
-static void
-pulse_output_cancel(AudioOutput *ao)
+inline void
+PulseOutput::Cancel()
{
- PulseOutput *po = (PulseOutput *)ao;
- pa_operation *o;
-
- assert(po->mainloop != nullptr);
- assert(po->stream != nullptr);
+ assert(mainloop != nullptr);
+ assert(stream != nullptr);
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
- if (pa_stream_get_state(po->stream) != PA_STREAM_READY) {
+ if (pa_stream_get_state(stream) != PA_STREAM_READY) {
/* no need to flush when the stream isn't connected
yet */
- pa_threaded_mainloop_unlock(po->mainloop);
+ pa_threaded_mainloop_unlock(mainloop);
return;
}
- assert(po->context != nullptr);
+ assert(context != nullptr);
- o = pa_stream_flush(po->stream, pulse_output_stream_success_cb, po);
+ pa_operation *o = pa_stream_flush(stream,
+ pulse_output_stream_success_cb,
+ this);
if (o == nullptr) {
- FormatWarning(pulse_output_domain,
- "pa_stream_flush() has failed: %s",
- pa_strerror(pa_context_errno(po->context)));
- pa_threaded_mainloop_unlock(po->mainloop);
+ LogPulseError(context, "pa_stream_flush() has failed");
+ pa_threaded_mainloop_unlock(mainloop);
return;
}
- pulse_wait_for_operation(po->mainloop, o);
- pa_threaded_mainloop_unlock(po->mainloop);
+ pulse_wait_for_operation(mainloop, o);
+ pa_threaded_mainloop_unlock(mainloop);
}
-static bool
-pulse_output_pause(AudioOutput *ao)
+inline bool
+PulseOutput::Pause()
{
- PulseOutput *po = (PulseOutput *)ao;
-
- assert(po->mainloop != nullptr);
- assert(po->stream != nullptr);
+ assert(mainloop != nullptr);
+ assert(stream != nullptr);
- pa_threaded_mainloop_lock(po->mainloop);
+ pa_threaded_mainloop_lock(mainloop);
/* check if the stream is (already/still) connected */
Error error;
- if (!pulse_output_wait_stream(po, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (!WaitStream(error)) {
+ pa_threaded_mainloop_unlock(mainloop);
LogError(error);
return false;
}
- assert(po->context != nullptr);
+ assert(context != nullptr);
/* cork the stream */
- if (!pa_stream_is_corked(po->stream) &&
- !pulse_output_stream_pause(po, true, error)) {
- pa_threaded_mainloop_unlock(po->mainloop);
+ if (!pa_stream_is_corked(stream) && !StreamPause(true, error)) {
+ pa_threaded_mainloop_unlock(mainloop);
LogError(error);
return false;
}
- pa_threaded_mainloop_unlock(po->mainloop);
-
+ pa_threaded_mainloop_unlock(mainloop);
return true;
}
-static bool
-pulse_output_test_default_device(void)
+inline bool
+PulseOutput::TestDefaultDevice()
{
- bool success;
-
- const config_param empty;
- PulseOutput *po = (PulseOutput *)
- pulse_output_init(empty, IgnoreError());
+ const ConfigBlock empty;
+ PulseOutput *po = PulseOutput::Create(empty, IgnoreError());
if (po == nullptr)
return false;
- success = pulse_output_wait_connection(po, IgnoreError());
- pulse_output_finish(&po->base);
-
+ bool success = po->WaitConnection(IgnoreError());
+ delete po;
return success;
}
+static bool
+pulse_output_test_default_device(void)
+{
+ return PulseOutput::TestDefaultDevice();
+}
+
+typedef AudioOutputWrapper<PulseOutput> Wrapper;
+
const struct AudioOutputPlugin pulse_output_plugin = {
"pulse",
pulse_output_test_default_device,
- pulse_output_init,
- pulse_output_finish,
- pulse_output_enable,
- pulse_output_disable,
- pulse_output_open,
- pulse_output_close,
- pulse_output_delay,
+ &Wrapper::Init,
+ &Wrapper::Finish,
+ &Wrapper::Enable,
+ &Wrapper::Disable,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- pulse_output_play,
+ &Wrapper::Play,
nullptr,
- pulse_output_cancel,
- pulse_output_pause,
+ &Wrapper::Cancel,
+ &Wrapper::Pause,
&pulse_mixer_plugin,
};
diff --git a/src/output/plugins/PulseOutputPlugin.hxx b/src/output/plugins/PulseOutputPlugin.hxx
index 9219780a5..f193db1d8 100644
--- a/src/output/plugins/PulseOutputPlugin.hxx
+++ b/src/output/plugins/PulseOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#ifndef MPD_PULSE_OUTPUT_PLUGIN_HXX
#define MPD_PULSE_OUTPUT_PLUGIN_HXX
-struct PulseOutput;
+class PulseOutput;
class PulseMixer;
struct pa_cvolume;
class Error;
diff --git a/src/output/plugins/RecorderOutputPlugin.cxx b/src/output/plugins/RecorderOutputPlugin.cxx
index 87e23f55a..4f9231c70 100644
--- a/src/output/plugins/RecorderOutputPlugin.cxx
+++ b/src/output/plugins/RecorderOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,21 +20,28 @@
#include "config.h"
#include "RecorderOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
+#include "tag/Format.hxx"
+#include "encoder/ToOutputStream.hxx"
+#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx"
#include "config/ConfigError.hxx"
+#include "config/ConfigPath.hxx"
+#include "Log.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "fs/io/FileOutputStream.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
-#include "system/fd_util.h"
-#include "open.h"
#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
+#include <stdlib.h>
+
+static constexpr Domain recorder_domain("recorder");
+
+class RecorderOutput {
+ friend struct AudioOutputWrapper<RecorderOutput>;
-struct RecorderOutput {
AudioOutput base;
/**
@@ -45,44 +52,77 @@ struct RecorderOutput {
/**
* The destination file name.
*/
- const char *path;
+ AllocatedPath path;
+
+ /**
+ * A string that will be used with FormatTag() to build the
+ * destination path.
+ */
+ std::string format_path;
/**
- * The destination file descriptor.
+ * The #AudioFormat that is currently active. This is used
+ * for switching to another file.
*/
- int fd;
+ AudioFormat effective_audio_format;
/**
- * The buffer for encoder_read().
+ * The destination file.
*/
- char buffer[32768];
+ FileOutputStream *file;
RecorderOutput()
- :base(recorder_output_plugin) {}
+ :base(recorder_output_plugin),
+ encoder(nullptr),
+ path(AllocatedPath::Null()) {}
- bool Initialize(const config_param &param, Error &error_r) {
- return base.Configure(param, error_r);
+ ~RecorderOutput() {
+ if (encoder != nullptr)
+ encoder->Dispose();
}
- bool Configure(const config_param &param, Error &error);
+ bool Initialize(const ConfigBlock &block, Error &error_r) {
+ return base.Configure(block, error_r);
+ }
+
+ static RecorderOutput *Create(const ConfigBlock &block, Error &error);
+
+ bool Configure(const ConfigBlock &block, Error &error);
- bool WriteToFile(const void *data, size_t length, Error &error);
+ bool Open(AudioFormat &audio_format, Error &error);
+ void Close();
/**
* Writes pending data from the encoder to the output file.
*/
bool EncoderToFile(Error &error);
-};
-static constexpr Domain recorder_output_domain("recorder_output");
+ void SendTag(const Tag &tag);
+
+ size_t Play(const void *chunk, size_t size, Error &error);
+
+private:
+ gcc_pure
+ bool HasDynamicPath() const {
+ return !format_path.empty();
+ }
+
+ /**
+ * Finish the encoder and commit the file.
+ */
+ bool Commit(Error &error);
+
+ void FinishFormat();
+ bool ReopenFormat(AllocatedPath &&new_path, Error &error);
+};
inline bool
-RecorderOutput::Configure(const config_param &param, Error &error)
+RecorderOutput::Configure(const ConfigBlock &block, Error &error)
{
/* read configuration */
const char *encoder_name =
- param.GetBlockValue("encoder", "vorbis");
+ block.GetBlockValue("encoder", "vorbis");
const auto encoder_plugin = encoder_plugin_get(encoder_name);
if (encoder_plugin == nullptr) {
error.Format(config_domain,
@@ -90,167 +130,269 @@ RecorderOutput::Configure(const config_param &param, Error &error)
return false;
}
- path = param.GetBlockValue("path");
- if (path == nullptr) {
+ path = block.GetBlockPath("path", error);
+ if (error.IsDefined())
+ return false;
+
+ const char *fmt = block.GetBlockValue("format_path", nullptr);
+ if (fmt != nullptr)
+ format_path = fmt;
+
+ if (path.IsNull() && fmt == nullptr) {
error.Set(config_domain, "'path' not configured");
return false;
}
+ if (!path.IsNull() && fmt != nullptr) {
+ error.Set(config_domain, "Cannot have both 'path' and 'format_path'");
+ return false;
+ }
+
/* initialize encoder */
- encoder = encoder_init(*encoder_plugin, param, error);
+ encoder = encoder_init(*encoder_plugin, block, error);
if (encoder == nullptr)
return false;
return true;
}
-static AudioOutput *
-recorder_output_init(const config_param &param, Error &error)
+RecorderOutput *
+RecorderOutput::Create(const ConfigBlock &block, Error &error)
{
RecorderOutput *recorder = new RecorderOutput();
- if (!recorder->Initialize(param, error)) {
+ if (!recorder->Initialize(block, error)) {
delete recorder;
return nullptr;
}
- if (!recorder->Configure(param, error)) {
+ if (!recorder->Configure(block, error)) {
delete recorder;
return nullptr;
}
- return &recorder->base;
+ return recorder;
}
-static void
-recorder_output_finish(AudioOutput *ao)
+inline bool
+RecorderOutput::EncoderToFile(Error &error)
{
- RecorderOutput *recorder = (RecorderOutput *)ao;
+ assert(file != nullptr);
+ assert(file->IsDefined());
- encoder_finish(recorder->encoder);
- delete recorder;
+ return EncoderToOutputStream(*file, *encoder, error);
}
inline bool
-RecorderOutput::WriteToFile(const void *_data, size_t length, Error &error)
+RecorderOutput::Open(AudioFormat &audio_format, Error &error)
{
- assert(length > 0);
-
- const uint8_t *data = (const uint8_t *)_data, *end = data + length;
-
- while (true) {
- ssize_t nbytes = write(fd, data, end - data);
- if (nbytes > 0) {
- data += nbytes;
- if (data == end)
- return true;
- } else if (nbytes == 0) {
- /* shouldn't happen for files */
- error.Set(recorder_output_domain,
- "write() returned 0");
+ /* create the output file */
+
+ if (!HasDynamicPath()) {
+ assert(!path.IsNull());
+
+ file = FileOutputStream::Create(path, error);
+ if (file == nullptr)
return false;
- } else if (errno != EINTR) {
- error.FormatErrno("Failed to write to '%s'", path);
+ } else {
+ /* don't open the file just yet; wait until we have
+ a tag that we can use to build the path */
+ assert(path.IsNull());
+
+ file = nullptr;
+ }
+
+ /* open the encoder */
+
+ if (!encoder->Open(audio_format, error)) {
+ delete file;
+ return false;
+ }
+
+ if (!HasDynamicPath()) {
+ if (!EncoderToFile(error)) {
+ encoder->Close();
+ delete file;
return false;
}
+ } else {
+ /* remember the AudioFormat for ReopenFormat() */
+ effective_audio_format = audio_format;
+
+ /* close the encoder for now; it will be opened as
+ soon as we have received a tag */
+ encoder->Close();
}
+
+ return true;
}
inline bool
-RecorderOutput::EncoderToFile(Error &error)
+RecorderOutput::Commit(Error &error)
{
- assert(fd >= 0);
+ assert(!path.IsNull());
- while (true) {
- /* read from the encoder */
+ /* flush the encoder and write the rest to the file */
- size_t size = encoder_read(encoder, buffer, sizeof(buffer));
- if (size == 0)
- return true;
+ bool success = encoder_end(encoder, error) &&
+ EncoderToFile(error);
- /* write everything into the file */
+ /* now really close everything */
- if (!WriteToFile(buffer, size, error))
- return false;
- }
+ encoder->Close();
+
+ if (success && !file->Commit(error))
+ success = false;
+
+ delete file;
+
+ return success;
}
-static bool
-recorder_output_open(AudioOutput *ao,
- AudioFormat &audio_format,
- Error &error)
+inline void
+RecorderOutput::Close()
{
- RecorderOutput *recorder = (RecorderOutput *)ao;
+ if (file == nullptr) {
+ /* not currently encoding to a file; nothing needs to
+ be done now */
+ assert(HasDynamicPath());
+ assert(path.IsNull());
+ return;
+ }
- /* create the output file */
+ Error error;
+ if (!Commit(error))
+ LogError(error);
- recorder->fd = open_cloexec(recorder->path,
- O_CREAT|O_WRONLY|O_TRUNC|O_BINARY,
- 0666);
- if (recorder->fd < 0) {
- error.FormatErrno("Failed to create '%s'", recorder->path);
- return false;
+ if (HasDynamicPath()) {
+ assert(!path.IsNull());
+ path.SetNull();
}
+}
- /* open the encoder */
+void
+RecorderOutput::FinishFormat()
+{
+ assert(HasDynamicPath());
+
+ if (file == nullptr)
+ return;
+
+ Error error;
+ if (!Commit(error))
+ LogError(error);
+
+ file = nullptr;
+ path.SetNull();
+}
- if (!encoder_open(recorder->encoder, audio_format, error)) {
- close(recorder->fd);
- unlink(recorder->path);
+inline bool
+RecorderOutput::ReopenFormat(AllocatedPath &&new_path, Error &error)
+{
+ assert(HasDynamicPath());
+ assert(path.IsNull());
+ assert(file == nullptr);
+
+ FileOutputStream *new_file =
+ FileOutputStream::Create(new_path, error);
+ if (new_file == nullptr)
+ return false;
+
+ AudioFormat new_audio_format = effective_audio_format;
+ if (!encoder->Open(new_audio_format, error)) {
+ delete new_file;
return false;
}
- if (!recorder->EncoderToFile(error)) {
- encoder_close(recorder->encoder);
- close(recorder->fd);
- unlink(recorder->path);
+ /* reopening the encoder must always result in the same
+ AudioFormat as before */
+ assert(new_audio_format == effective_audio_format);
+
+ if (!EncoderToOutputStream(*new_file, *encoder, error)) {
+ encoder->Close();
+ delete new_file;
return false;
}
+ path = std::move(new_path);
+ file = new_file;
+
+ FormatDebug(recorder_domain, "Recording to \"%s\"",
+ path.ToUTF8().c_str());
+
return true;
}
-static void
-recorder_output_close(AudioOutput *ao)
+inline void
+RecorderOutput::SendTag(const Tag &tag)
{
- RecorderOutput *recorder = (RecorderOutput *)ao;
-
- /* flush the encoder and write the rest to the file */
+ if (HasDynamicPath()) {
+ char *p = FormatTag(tag, format_path.c_str());
+ if (p == nullptr || *p == 0) {
+ /* no path could be composed with this tag:
+ don't write a file */
+ free(p);
+ FinishFormat();
+ return;
+ }
- if (encoder_end(recorder->encoder, IgnoreError()))
- recorder->EncoderToFile(IgnoreError());
+ Error error;
+ AllocatedPath new_path = ParsePath(p, error);
+ free(p);
+ if (new_path.IsNull()) {
+ LogError(error);
+ FinishFormat();
+ return;
+ }
- /* now really close everything */
+ if (new_path != path) {
+ FinishFormat();
- encoder_close(recorder->encoder);
+ if (!ReopenFormat(std::move(new_path), error)) {
+ LogError(error);
+ return;
+ }
+ }
+ }
- close(recorder->fd);
+ Error error;
+ if (!encoder_pre_tag(encoder, error) ||
+ !EncoderToFile(error) ||
+ !encoder_tag(encoder, tag, error))
+ LogError(error);
}
-static size_t
-recorder_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
+inline size_t
+RecorderOutput::Play(const void *chunk, size_t size, Error &error)
{
- RecorderOutput *recorder = (RecorderOutput *)ao;
+ if (file == nullptr) {
+ /* not currently encoding to a file; discard incoming
+ data */
+ assert(HasDynamicPath());
+ assert(path.IsNull());
+ return size;
+ }
- return encoder_write(recorder->encoder, chunk, size, error) &&
- recorder->EncoderToFile(error)
+ return encoder_write(encoder, chunk, size, error) &&
+ EncoderToFile(error)
? size : 0;
}
+typedef AudioOutputWrapper<RecorderOutput> Wrapper;
+
const struct AudioOutputPlugin recorder_output_plugin = {
"recorder",
nullptr,
- recorder_output_init,
- recorder_output_finish,
- nullptr,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
- recorder_output_open,
- recorder_output_close,
nullptr,
+ &Wrapper::Open,
+ &Wrapper::Close,
nullptr,
- recorder_output_play,
+ &Wrapper::SendTag,
+ &Wrapper::Play,
nullptr,
nullptr,
nullptr,
diff --git a/src/output/plugins/RecorderOutputPlugin.hxx b/src/output/plugins/RecorderOutputPlugin.hxx
index ea1044e0f..061279fba 100644
--- a/src/output/plugins/RecorderOutputPlugin.hxx
+++ b/src/output/plugins/RecorderOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/RoarOutputPlugin.cxx b/src/output/plugins/RoarOutputPlugin.cxx
index aa37c91b7..11b0f1671 100644
--- a/src/output/plugins/RoarOutputPlugin.cxx
+++ b/src/output/plugins/RoarOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
* Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
*
@@ -21,6 +21,7 @@
#include "config.h"
#include "RoarOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "../Wrapper.hxx"
#include "mixer/MixerList.hxx"
#include "thread/Mutex.hxx"
#include "util/Error.hxx"
@@ -36,6 +37,8 @@
#undef new
class RoarOutput {
+ friend struct AudioOutputWrapper<RoarOutput>;
+
AudioOutput base;
std::string host, name;
@@ -57,11 +60,11 @@ public:
return &base;
}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
}
- void Configure(const config_param &param);
+ void Configure(const ConfigBlock &block);
bool Open(AudioFormat &audio_format, Error &error);
void Close();
@@ -121,40 +124,32 @@ roar_output_set_volume(RoarOutput &roar, unsigned volume)
}
inline void
-RoarOutput::Configure(const config_param &param)
+RoarOutput::Configure(const ConfigBlock &block)
{
- host = param.GetBlockValue("server", "");
- name = param.GetBlockValue("name", "MPD");
+ host = block.GetBlockValue("server", "");
+ name = block.GetBlockValue("name", "MPD");
- const char *_role = param.GetBlockValue("role", "music");
+ const char *_role = block.GetBlockValue("role", "music");
role = _role != nullptr
? roar_str2role(_role)
: ROAR_ROLE_MUSIC;
}
static AudioOutput *
-roar_init(const config_param &param, Error &error)
+roar_init(const ConfigBlock &block, Error &error)
{
RoarOutput *self = new RoarOutput();
- if (!self->Initialize(param, error)) {
+ if (!self->Initialize(block, error)) {
delete self;
return nullptr;
}
- self->Configure(param);
+ self->Configure(block);
return *self;
}
static void
-roar_finish(AudioOutput *ao)
-{
- RoarOutput *self = (RoarOutput *)ao;
-
- delete self;
-}
-
-static void
roar_use_audio_format(struct roar_audio_info *info,
AudioFormat &audio_format)
{
@@ -221,14 +216,6 @@ RoarOutput::Open(AudioFormat &audio_format, Error &error)
return true;
}
-static bool
-roar_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
-{
- RoarOutput *self = (RoarOutput *)ao;
-
- return self->Open(audio_format, error);
-}
-
inline void
RoarOutput::Close()
{
@@ -242,13 +229,6 @@ RoarOutput::Close()
roar_disconnect(&con);
}
-static void
-roar_close(AudioOutput *ao)
-{
- RoarOutput *self = (RoarOutput *)ao;
- self->Close();
-}
-
inline void
RoarOutput::Cancel()
{
@@ -277,14 +257,6 @@ RoarOutput::Cancel()
alive = true;
}
-static void
-roar_cancel(AudioOutput *ao)
-{
- RoarOutput *self = (RoarOutput *)ao;
-
- self->Cancel();
-}
-
inline size_t
RoarOutput::Play(const void *chunk, size_t size, Error &error)
{
@@ -302,14 +274,6 @@ RoarOutput::Play(const void *chunk, size_t size, Error &error)
return nbytes;
}
-static size_t
-roar_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
-{
- RoarOutput *self = (RoarOutput *)ao;
- return self->Play(chunk, size, error);
-}
-
static const char*
roar_tag_convert(TagType type, bool *is_uuid)
{
@@ -407,26 +371,28 @@ RoarOutput::SendTag(const Tag &tag)
}
static void
-roar_send_tag(AudioOutput *ao, const Tag *meta)
+roar_send_tag(AudioOutput *ao, const Tag &meta)
{
RoarOutput *self = (RoarOutput *)ao;
- self->SendTag(*meta);
+ self->SendTag(meta);
}
+typedef AudioOutputWrapper<RoarOutput> Wrapper;
+
const struct AudioOutputPlugin roar_output_plugin = {
"roar",
nullptr,
roar_init,
- roar_finish,
+ &Wrapper::Finish,
nullptr,
nullptr,
- roar_open,
- roar_close,
+ &Wrapper::Open,
+ &Wrapper::Close,
nullptr,
roar_send_tag,
- roar_play,
+ &Wrapper::Play,
nullptr,
- roar_cancel,
+ &Wrapper::Cancel,
nullptr,
&roar_mixer_plugin,
};
diff --git a/src/output/plugins/RoarOutputPlugin.hxx b/src/output/plugins/RoarOutputPlugin.hxx
index 5f5a9246e..a9726d5c8 100644
--- a/src/output/plugins/RoarOutputPlugin.hxx
+++ b/src/output/plugins/RoarOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/ShoutOutputPlugin.cxx b/src/output/plugins/ShoutOutputPlugin.cxx
index b51f7ed82..339c4e491 100644
--- a/src/output/plugins/ShoutOutputPlugin.cxx
+++ b/src/output/plugins/ShoutOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "ShoutOutputPlugin.hxx"
#include "../OutputAPI.hxx"
+#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx"
#include "config/ConfigError.hxx"
@@ -67,11 +68,11 @@ struct ShoutOutput final {
shout_free(shout_conn);
}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
};
static int shout_init_count;
@@ -91,18 +92,18 @@ shout_encoder_plugin_get(const char *name)
gcc_pure
static const char *
-require_block_string(const config_param &param, const char *name)
+require_block_string(const ConfigBlock &block, const char *name)
{
- const char *value = param.GetBlockValue(name);
+ const char *value = block.GetBlockValue(name);
if (value == nullptr)
FormatFatalError("no \"%s\" defined for shout device defined "
- "at line %u\n", name, param.line);
+ "at line %d\n", name, block.line);
return value;
}
inline bool
-ShoutOutput::Configure(const config_param &param, Error &error)
+ShoutOutput::Configure(const ConfigBlock &block, Error &error)
{
const AudioFormat audio_format = base.config_audio_format;
@@ -112,22 +113,22 @@ ShoutOutput::Configure(const config_param &param, Error &error)
return false;
}
- const char *host = require_block_string(param, "host");
- const char *mount = require_block_string(param, "mount");
- unsigned port = param.GetBlockValue("port", 0u);
+ const char *host = require_block_string(block, "host");
+ const char *mount = require_block_string(block, "mount");
+ unsigned port = block.GetBlockValue("port", 0u);
if (port == 0) {
error.Set(config_domain, "shout port must be configured");
return false;
}
- const char *passwd = require_block_string(param, "password");
- const char *name = require_block_string(param, "name");
+ const char *passwd = require_block_string(block, "password");
+ const char *name = require_block_string(block, "name");
- bool is_public = param.GetBlockValue("public", false);
+ bool is_public = block.GetBlockValue("public", false);
- const char *user = param.GetBlockValue("user", "source");
+ const char *user = block.GetBlockValue("user", "source");
- const char *value = param.GetBlockValue("quality");
+ const char *value = block.GetBlockValue("quality");
if (value != nullptr) {
char *test;
quality = strtod(value, &test);
@@ -140,14 +141,14 @@ ShoutOutput::Configure(const config_param &param, Error &error)
return false;
}
- if (param.GetBlockValue("bitrate") != nullptr) {
+ if (block.GetBlockValue("bitrate") != nullptr) {
error.Set(config_domain,
"quality and bitrate are "
"both defined");
return false;
}
} else {
- value = param.GetBlockValue("bitrate");
+ value = block.GetBlockValue("bitrate");
if (value == nullptr) {
error.Set(config_domain,
"neither bitrate nor quality defined");
@@ -164,7 +165,7 @@ ShoutOutput::Configure(const config_param &param, Error &error)
}
}
- const char *encoding = param.GetBlockValue("encoding", "ogg");
+ const char *encoding = block.GetBlockValue("encoding", "ogg");
const auto encoder_plugin = shout_encoder_plugin_get(encoding);
if (encoder_plugin == nullptr) {
error.Format(config_domain,
@@ -173,7 +174,7 @@ ShoutOutput::Configure(const config_param &param, Error &error)
return false;
}
- encoder = encoder_init(*encoder_plugin, param, error);
+ encoder = encoder_init(*encoder_plugin, block, error);
if (encoder == nullptr)
return false;
@@ -184,7 +185,7 @@ ShoutOutput::Configure(const config_param &param, Error &error)
shout_format = SHOUT_FORMAT_OGG;
unsigned protocol;
- value = param.GetBlockValue("protocol");
+ value = block.GetBlockValue("protocol");
if (value != nullptr) {
if (0 == strcmp(value, "shoutcast") &&
0 != strcmp(encoding, "mp3")) {
@@ -225,21 +226,21 @@ ShoutOutput::Configure(const config_param &param, Error &error)
}
/* optional paramters */
- timeout = param.GetBlockValue("timeout", DEFAULT_CONN_TIMEOUT);
+ timeout = block.GetBlockValue("timeout", DEFAULT_CONN_TIMEOUT);
- value = param.GetBlockValue("genre");
+ value = block.GetBlockValue("genre");
if (value != nullptr && shout_set_genre(shout_conn, value)) {
error.Set(shout_output_domain, shout_get_error(shout_conn));
return false;
}
- value = param.GetBlockValue("description");
+ value = block.GetBlockValue("description");
if (value != nullptr && shout_set_description(shout_conn, value)) {
error.Set(shout_output_domain, shout_get_error(shout_conn));
return false;
}
- value = param.GetBlockValue("url");
+ value = block.GetBlockValue("url");
if (value != nullptr && shout_set_url(shout_conn, value)) {
error.Set(shout_output_domain, shout_get_error(shout_conn));
return false;
@@ -271,15 +272,15 @@ ShoutOutput::Configure(const config_param &param, Error &error)
}
static AudioOutput *
-my_shout_init_driver(const config_param &param, Error &error)
+my_shout_init_driver(const ConfigBlock &block, Error &error)
{
ShoutOutput *sd = new ShoutOutput();
- if (!sd->Initialize(param, error)) {
+ if (!sd->Initialize(block, error)) {
delete sd;
return nullptr;
}
- if (!sd->Configure(param, error)) {
+ if (!sd->Configure(block, error)) {
delete sd;
return nullptr;
}
@@ -345,7 +346,7 @@ static void close_shout_conn(ShoutOutput * sd)
if (encoder_end(sd->encoder, IgnoreError()))
write_page(sd, IgnoreError());
- encoder_close(sd->encoder);
+ sd->encoder->Close();
}
if (shout_get_connected(sd->shout_conn) != SHOUTERR_UNCONNECTED &&
@@ -361,7 +362,7 @@ my_shout_finish_driver(AudioOutput *ao)
{
ShoutOutput *sd = (ShoutOutput *)ao;
- encoder_finish(sd->encoder);
+ sd->encoder->Dispose();
delete sd;
@@ -415,13 +416,13 @@ my_shout_open_device(AudioOutput *ao, AudioFormat &audio_format,
if (!shout_connect(sd, error))
return false;
- if (!encoder_open(sd->encoder, audio_format, error)) {
+ if (!sd->encoder->Open(audio_format, error)) {
shout_close(sd->shout_conn);
return false;
}
if (!write_page(sd, error)) {
- encoder_close(sd->encoder);
+ sd->encoder->Close();
shout_close(sd->shout_conn);
return false;
}
@@ -462,7 +463,7 @@ my_shout_pause(AudioOutput *ao)
}
static void
-shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
+shout_tag_to_metadata(const Tag &tag, char *dest, size_t size)
{
char artist[size];
char title[size];
@@ -470,7 +471,7 @@ shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
artist[0] = 0;
title[0] = 0;
- for (const auto &item : *tag) {
+ for (const auto &item : tag) {
switch (item.type) {
case TAG_ARTIST:
strncpy(artist, item.value, size);
@@ -488,7 +489,7 @@ shout_tag_to_metadata(const Tag *tag, char *dest, size_t size)
}
static void my_shout_set_tag(AudioOutput *ao,
- const Tag *tag)
+ const Tag &tag)
{
ShoutOutput *sd = (ShoutOutput *)ao;
diff --git a/src/output/plugins/ShoutOutputPlugin.hxx b/src/output/plugins/ShoutOutputPlugin.hxx
index 9f706fc3b..b103b3bf0 100644
--- a/src/output/plugins/ShoutOutputPlugin.hxx
+++ b/src/output/plugins/ShoutOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/SolarisOutputPlugin.cxx b/src/output/plugins/SolarisOutputPlugin.cxx
index 30745f97c..18c92d361 100644
--- a/src/output/plugins/SolarisOutputPlugin.cxx
+++ b/src/output/plugins/SolarisOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -60,8 +60,8 @@ struct SolarisOutput {
SolarisOutput()
:base(solaris_output_plugin) {}
- bool Initialize(const config_param &param, Error &error_r) {
- return base.Configure(param, error_r);
+ bool Initialize(const ConfigBlock &block, Error &error_r) {
+ return base.Configure(block, error_r);
}
};
@@ -75,15 +75,15 @@ solaris_output_test_default_device(void)
}
static AudioOutput *
-solaris_output_init(const config_param &param, Error &error_r)
+solaris_output_init(const ConfigBlock &block, Error &error_r)
{
SolarisOutput *so = new SolarisOutput();
- if (!so->Initialize(param, error_r)) {
+ if (!so->Initialize(block, error_r)) {
delete so;
return nullptr;
}
- so->device = param.GetBlockValue("device", "/dev/audio");
+ so->device = block.GetBlockValue("device", "/dev/audio");
return &so->base;
}
diff --git a/src/output/plugins/SolarisOutputPlugin.hxx b/src/output/plugins/SolarisOutputPlugin.hxx
index 3f9ede7a6..f6f32504a 100644
--- a/src/output/plugins/SolarisOutputPlugin.hxx
+++ b/src/output/plugins/SolarisOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/WinmmOutputPlugin.cxx b/src/output/plugins/WinmmOutputPlugin.cxx
index e5c5a6f0c..35efb0f93 100644
--- a/src/output/plugins/WinmmOutputPlugin.cxx
+++ b/src/output/plugins/WinmmOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,9 +22,11 @@
#include "../OutputAPI.hxx"
#include "pcm/PcmBuffer.hxx"
#include "mixer/MixerList.hxx"
+#include "fs/AllocatedPath.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "util/Macros.hxx"
+#include "util/StringUtil.hxx"
#include <stdlib.h>
#include <string.h>
@@ -56,6 +58,18 @@ struct WinmmOutput {
static constexpr Domain winmm_output_domain("winmm_output");
+static void
+SetWaveOutError(Error &error, MMRESULT result, const char *prefix)
+{
+ char buffer[256];
+ if (waveOutGetErrorTextA(result, buffer,
+ ARRAY_SIZE(buffer)) == MMSYSERR_NOERROR)
+ error.Format(winmm_output_domain, int(result),
+ "%s: %s", prefix, buffer);
+ else
+ error.Set(winmm_output_domain, int(result), prefix);
+}
+
HWAVEOUT
winmm_output_get_handle(WinmmOutput &output)
{
@@ -83,13 +97,23 @@ get_device_id(const char *device_name, UINT *device_id, Error &error)
char *endptr;
UINT id = strtoul(device_name, &endptr, 0);
if (endptr > device_name && *endptr == 0) {
- if (id >= numdevs)
- goto fail;
+ if (id >= numdevs) {
+ error.Format(winmm_output_domain,
+ "device \"%s\" is not found",
+ device_name);
+ return false;
+ }
+
*device_id = id;
return true;
}
/* check for device name */
+ const AllocatedPath device_name_fs =
+ AllocatedPath::FromUTF8(device_name, error);
+ if (device_name_fs.IsNull())
+ return false;
+
for (UINT i = 0; i < numdevs; i++) {
WAVEOUTCAPS caps;
MMRESULT result = waveOutGetDevCaps(i, &caps, sizeof(caps));
@@ -97,28 +121,27 @@ get_device_id(const char *device_name, UINT *device_id, Error &error)
continue;
/* szPname is only 32 chars long, so it is often truncated.
Use partial match to work around this. */
- if (strstr(device_name, caps.szPname) == device_name) {
+ if (StringStartsWith(device_name_fs.c_str(), caps.szPname)) {
*device_id = i;
return true;
}
}
-fail:
error.Format(winmm_output_domain,
"device \"%s\" is not found", device_name);
return false;
}
static AudioOutput *
-winmm_output_init(const config_param &param, Error &error)
+winmm_output_init(const ConfigBlock &block, Error &error)
{
WinmmOutput *wo = new WinmmOutput();
- if (!wo->base.Configure(param, error)) {
+ if (!wo->base.Configure(block, error)) {
delete wo;
return nullptr;
}
- const char *device = param.GetBlockValue("device");
+ const char *device = block.GetBlockValue("device");
if (!get_device_id(device, &wo->device_id, error)) {
delete wo;
return nullptr;
@@ -179,7 +202,7 @@ winmm_output_open(AudioOutput *ao, AudioFormat &audio_format,
(DWORD_PTR)wo->event, 0, CALLBACK_EVENT);
if (result != MMSYSERR_NOERROR) {
CloseHandle(wo->event);
- error.Set(winmm_output_domain, "waveOutOpen() failed");
+ SetWaveOutError(error, result, "waveOutOpen() failed");
return false;
}
@@ -225,8 +248,8 @@ winmm_set_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
MMRESULT result = waveOutPrepareHeader(wo->handle, &buffer->hdr,
sizeof(buffer->hdr));
if (result != MMSYSERR_NOERROR) {
- error.Set(winmm_output_domain, result,
- "waveOutPrepareHeader() failed");
+ SetWaveOutError(error, result,
+ "waveOutPrepareHeader() failed");
return false;
}
@@ -251,8 +274,8 @@ winmm_drain_buffer(WinmmOutput *wo, WinmmBuffer *buffer,
if (result == MMSYSERR_NOERROR)
return true;
else if (result != WAVERR_STILLPLAYING) {
- error.Set(winmm_output_domain, result,
- "waveOutUnprepareHeader() failed");
+ SetWaveOutError(error, result,
+ "waveOutUnprepareHeader() failed");
return false;
}
@@ -278,8 +301,7 @@ winmm_output_play(AudioOutput *ao, const void *chunk, size_t size, Error &error)
if (result != MMSYSERR_NOERROR) {
waveOutUnprepareHeader(wo->handle, &buffer->hdr,
sizeof(buffer->hdr));
- error.Set(winmm_output_domain, result,
- "waveOutWrite() failed");
+ SetWaveOutError(error, result, "waveOutWrite() failed");
return 0;
}
diff --git a/src/output/plugins/WinmmOutputPlugin.hxx b/src/output/plugins/WinmmOutputPlugin.hxx
index 50fae4f2f..6c8fcc627 100644
--- a/src/output/plugins/WinmmOutputPlugin.hxx
+++ b/src/output/plugins/WinmmOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx
index 3797c3d26..99210c1fd 100644
--- a/src/output/plugins/httpd/HttpdClient.cxx
+++ b/src/output/plugins/httpd/HttpdClient.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,7 @@
#include "util/ASCII.hxx"
#include "Page.hxx"
#include "IcyMetaDataServer.hxx"
-#include "system/SocketError.hxx"
+#include "net/SocketError.hxx"
#include "Log.hxx"
#include <assert.h>
diff --git a/src/output/plugins/httpd/HttpdClient.hxx b/src/output/plugins/httpd/HttpdClient.hxx
index f94f05769..6646ddf4c 100644
--- a/src/output/plugins/httpd/HttpdClient.hxx
+++ b/src/output/plugins/httpd/HttpdClient.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,8 @@
#include "event/BufferedSocket.hxx"
#include "Compiler.h"
+#include <boost/intrusive/list.hpp>
+
#include <queue>
#include <list>
@@ -31,7 +33,9 @@
class HttpdOutput;
class Page;
-class HttpdClient final : BufferedSocket {
+class HttpdClient final
+ : BufferedSocket,
+ public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
/**
* The httpd output object this client is connected to.
*/
@@ -124,7 +128,7 @@ class HttpdClient final : BufferedSocket {
public:
/**
* @param httpd the HTTP output device
- * @param fd the socket file descriptor
+ * @param _fd the socket file descriptor
*/
HttpdClient(HttpdOutput &httpd, int _fd, EventLoop &_loop,
bool _metadata_supported);
diff --git a/src/output/plugins/httpd/HttpdInternal.hxx b/src/output/plugins/httpd/HttpdInternal.hxx
index 20ff15e42..01498dfcd 100644
--- a/src/output/plugins/httpd/HttpdInternal.hxx
+++ b/src/output/plugins/httpd/HttpdInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#ifndef MPD_OUTPUT_HTTPD_INTERNAL_H
#define MPD_OUTPUT_HTTPD_INTERNAL_H
+#include "HttpdClient.hxx"
#include "output/Internal.hxx"
#include "output/Timer.hxx"
#include "thread/Mutex.hxx"
@@ -33,16 +34,10 @@
#include "util/Cast.hxx"
#include "Compiler.h"
-#ifdef _LIBCPP_VERSION
-/* can't use incomplete template arguments with libc++ */
-#include "HttpdClient.hxx"
-#endif
-
-#include <forward_list>
#include <queue>
#include <list>
-struct config_param;
+struct ConfigBlock;
class Error;
class EventLoop;
class ServerSocket;
@@ -135,7 +130,8 @@ private:
* A linked list containing all clients which are currently
* connected.
*/
- std::forward_list<HttpdClient> clients;
+ boost::intrusive::list<HttpdClient,
+ boost::intrusive::constant_time_size<true>> clients;
/**
* A temporary buffer for the httpd_output_read_page()
@@ -147,13 +143,13 @@ private:
* The maximum and current number of clients connected
* at the same time.
*/
- unsigned clients_max, clients_cnt;
+ unsigned clients_max;
public:
HttpdOutput(EventLoop &_loop);
~HttpdOutput();
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static HttpdOutput *Cast(AudioOutput *ao) {
@@ -162,16 +158,16 @@ public:
using DeferredMonitor::GetEventLoop;
- bool Init(const config_param &param, Error &error);
+ bool Init(const ConfigBlock &block, Error &error);
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
- AudioOutput *InitAndConfigure(const config_param &param,
+ AudioOutput *InitAndConfigure(const ConfigBlock &block,
Error &error) {
- if (!Init(param, error))
+ if (!Init(block, error))
return nullptr;
- if (!Configure(param, error))
+ if (!Configure(block, error))
return nullptr;
return &base;
@@ -250,7 +246,7 @@ public:
bool EncodeAndPlay(const void *chunk, size_t size, Error &error);
- void SendTag(const Tag *tag);
+ void SendTag(const Tag &tag);
size_t Play(const void *chunk, size_t size, Error &error);
@@ -259,8 +255,7 @@ public:
private:
virtual void RunDeferred() override;
- virtual void OnAccept(int fd, const sockaddr &address,
- size_t address_length, int uid) override;
+ void OnAccept(int fd, SocketAddress address, int uid) override;
};
extern const class Domain httpd_output_domain;
diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.cxx b/src/output/plugins/httpd/HttpdOutputPlugin.cxx
index e3ba7727d..765a72d92 100644
--- a/src/output/plugins/httpd/HttpdOutputPlugin.cxx
+++ b/src/output/plugins/httpd/HttpdOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,9 +22,11 @@
#include "HttpdInternal.hxx"
#include "HttpdClient.hxx"
#include "output/OutputAPI.hxx"
+#include "encoder/EncoderInterface.hxx"
#include "encoder/EncoderPlugin.hxx"
#include "encoder/EncoderList.hxx"
-#include "system/Resolver.hxx"
+#include "net/SocketAddress.hxx"
+#include "net/ToString.hxx"
#include "Page.hxx"
#include "IcyMetaDataServer.hxx"
#include "system/fd_util.h"
@@ -32,6 +34,7 @@
#include "event/Call.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
+#include "util/DeleteDisposer.hxx"
#include "Log.hxx"
#include <assert.h>
@@ -63,7 +66,7 @@ HttpdOutput::~HttpdOutput()
metadata->Unref();
if (encoder != nullptr)
- encoder_finish(encoder);
+ encoder->Dispose();
}
@@ -90,17 +93,17 @@ HttpdOutput::Unbind()
}
inline bool
-HttpdOutput::Configure(const config_param &param, Error &error)
+HttpdOutput::Configure(const ConfigBlock &block, Error &error)
{
/* read configuration */
- name = param.GetBlockValue("name", "Set name in config");
- genre = param.GetBlockValue("genre", "Set genre in config");
- website = param.GetBlockValue("website", "Set website in config");
+ name = block.GetBlockValue("name", "Set name in config");
+ genre = block.GetBlockValue("genre", "Set genre in config");
+ website = block.GetBlockValue("website", "Set website in config");
- unsigned port = param.GetBlockValue("port", 8000u);
+ unsigned port = block.GetBlockValue("port", 8000u);
const char *encoder_name =
- param.GetBlockValue("encoder", "vorbis");
+ block.GetBlockValue("encoder", "vorbis");
const auto encoder_plugin = encoder_plugin_get(encoder_name);
if (encoder_plugin == nullptr) {
error.Format(httpd_output_domain,
@@ -108,11 +111,11 @@ HttpdOutput::Configure(const config_param &param, Error &error)
return false;
}
- clients_max = param.GetBlockValue("max_clients", 0u);
+ clients_max = block.GetBlockValue("max_clients", 0u);
/* set up bind_to_address */
- const char *bind_to_address = param.GetBlockValue("bind_to_address");
+ const char *bind_to_address = block.GetBlockValue("bind_to_address");
bool success = bind_to_address != nullptr &&
strcmp(bind_to_address, "any") != 0
? AddHost(bind_to_address, port, error)
@@ -122,7 +125,7 @@ HttpdOutput::Configure(const config_param &param, Error &error)
/* initialize encoder */
- encoder = encoder_init(*encoder_plugin, param, error);
+ encoder = encoder_init(*encoder_plugin, block, error);
if (encoder == nullptr)
return false;
@@ -135,17 +138,17 @@ HttpdOutput::Configure(const config_param &param, Error &error)
}
inline bool
-HttpdOutput::Init(const config_param &param, Error &error)
+HttpdOutput::Init(const ConfigBlock &block, Error &error)
{
- return base.Configure(param, error);
+ return base.Configure(block, error);
}
static AudioOutput *
-httpd_output_init(const config_param &param, Error &error)
+httpd_output_init(const ConfigBlock &block, Error &error)
{
HttpdOutput *httpd = new HttpdOutput(io_thread_get());
- AudioOutput *result = httpd->InitAndConfigure(param, error);
+ AudioOutput *result = httpd->InitAndConfigure(block, error);
if (result == nullptr)
delete httpd;
@@ -167,9 +170,9 @@ httpd_output_finish(AudioOutput *ao)
inline void
HttpdOutput::AddClient(int fd)
{
- clients.emplace_front(*this, fd, GetEventLoop(),
- encoder->plugin.tag == nullptr);
- ++clients_cnt;
+ auto *client = new HttpdClient(*this, fd, GetEventLoop(),
+ encoder->plugin.tag == nullptr);
+ clients.push_front(*client);
/* pass metadata to client */
if (metadata != nullptr)
@@ -200,16 +203,14 @@ HttpdOutput::RunDeferred()
}
void
-HttpdOutput::OnAccept(int fd, const sockaddr &address,
- size_t address_length, gcc_unused int uid)
+HttpdOutput::OnAccept(int fd, SocketAddress address, gcc_unused int uid)
{
/* the listener socket has become readable - a client has
connected */
#ifdef HAVE_LIBWRAP
- if (address.sa_family != AF_UNIX) {
- const auto hostaddr = sockaddr_to_string(&address,
- address_length);
+ if (address.GetFamily() != AF_UNIX) {
+ const auto hostaddr = ToString(address);
// TODO: shall we obtain the program name from argv[0]?
const char *progname = "mpd";
@@ -229,14 +230,13 @@ HttpdOutput::OnAccept(int fd, const sockaddr &address,
}
#else
(void)address;
- (void)address_length;
#endif /* HAVE_WRAP */
const ScopeLock protect(mutex);
if (fd >= 0) {
/* can we allow additional client */
- if (open && (clients_max == 0 || clients_cnt < clients_max))
+ if (open && (clients_max == 0 || clients.size() < clients_max))
AddClient(fd);
else
close_socket(fd);
@@ -294,7 +294,7 @@ httpd_output_disable(AudioOutput *ao)
inline bool
HttpdOutput::OpenEncoder(AudioFormat &audio_format, Error &error)
{
- if (!encoder_open(encoder, audio_format, error))
+ if (!encoder->Open(audio_format, error))
return false;
/* we have to remember the encoder header, i.e. the first
@@ -320,7 +320,6 @@ HttpdOutput::Open(AudioFormat &audio_format, Error &error)
/* initialize other attributes */
- clients_cnt = 0;
timer = new Timer(audio_format);
open = true;
@@ -348,13 +347,13 @@ HttpdOutput::Close()
delete timer;
BlockingCall(GetEventLoop(), [this](){
- clients.clear();
+ clients.clear_and_dispose(DeleteDisposer());
});
if (header != nullptr)
header->Unref();
- encoder_close(encoder);
+ encoder->Close();
}
static void
@@ -369,17 +368,10 @@ httpd_output_close(AudioOutput *ao)
void
HttpdOutput::RemoveClient(HttpdClient &client)
{
- assert(clients_cnt > 0);
+ assert(!clients.empty());
- for (auto prev = clients.before_begin(), i = std::next(prev);;
- prev = i, i = std::next(prev)) {
- assert(i != clients.end());
- if (&*i == &client) {
- clients.erase_after(prev);
- clients_cnt--;
- break;
- }
- }
+ clients.erase_and_dispose(clients.iterator_to(client),
+ DeleteDisposer());
}
void
@@ -499,10 +491,8 @@ httpd_output_pause(AudioOutput *ao)
}
inline void
-HttpdOutput::SendTag(const Tag *tag)
+HttpdOutput::SendTag(const Tag &tag)
{
- assert(tag != nullptr);
-
if (encoder->plugin.tag != nullptr) {
/* embed encoder tags */
@@ -538,7 +528,7 @@ HttpdOutput::SendTag(const Tag *tag)
TAG_NUM_OF_ITEM_TYPES
};
- metadata = icy_server_metadata_page(*tag, &types[0]);
+ metadata = icy_server_metadata_page(tag, &types[0]);
if (metadata != nullptr) {
const ScopeLock protect(mutex);
for (auto &client : clients)
@@ -548,7 +538,7 @@ HttpdOutput::SendTag(const Tag *tag)
}
static void
-httpd_output_tag(AudioOutput *ao, const Tag *tag)
+httpd_output_tag(AudioOutput *ao, const Tag &tag)
{
HttpdOutput *httpd = HttpdOutput::Cast(ao);
diff --git a/src/output/plugins/httpd/HttpdOutputPlugin.hxx b/src/output/plugins/httpd/HttpdOutputPlugin.hxx
index df99e2b43..8280d9fb2 100644
--- a/src/output/plugins/httpd/HttpdOutputPlugin.hxx
+++ b/src/output/plugins/httpd/HttpdOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/httpd/IcyMetaDataServer.cxx b/src/output/plugins/httpd/IcyMetaDataServer.cxx
index 146df23d1..fe841ac11 100644
--- a/src/output/plugins/httpd/IcyMetaDataServer.cxx
+++ b/src/output/plugins/httpd/IcyMetaDataServer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,8 +22,8 @@
#include "Page.hxx"
#include "tag/Tag.hxx"
#include "util/FormatString.hxx"
-
-#include <glib.h>
+#include "util/StringUtil.hxx"
+#include "util/Macros.hxx"
#include <string.h>
@@ -57,16 +57,13 @@ icy_server_metadata_header(const char *name,
static char *
icy_server_metadata_string(const char *stream_title, const char* stream_url)
{
- gchar *icy_metadata;
- guint meta_length;
-
// The leading n is a placeholder for the length information
- icy_metadata = FormatNew("nStreamTitle='%s';"
- "StreamUrl='%s';",
- stream_title,
- stream_url);
+ char *icy_metadata = FormatNew("nStreamTitle='%s';"
+ "StreamUrl='%s';",
+ stream_title,
+ stream_url);
- meta_length = strlen(icy_metadata);
+ size_t meta_length = strlen(icy_metadata);
meta_length--; // subtract placeholder
@@ -85,43 +82,30 @@ icy_server_metadata_string(const char *stream_title, const char* stream_url)
Page *
icy_server_metadata_page(const Tag &tag, const TagType *types)
{
- const gchar *tag_items[TAG_NUM_OF_ITEM_TYPES];
- gint last_item, item;
- guint position;
- gchar *icy_string;
- gchar stream_title[(1 + 255 - 28) * 16]; // Length + Metadata -
- // "StreamTitle='';StreamUrl='';"
- // = 4081 - 28
- stream_title[0] = '\0';
-
- last_item = -1;
+ const char *tag_items[TAG_NUM_OF_ITEM_TYPES];
+ int last_item = -1;
while (*types != TAG_NUM_OF_ITEM_TYPES) {
- const gchar *tag_item = tag.GetValue(*types++);
+ const char *tag_item = tag.GetValue(*types++);
if (tag_item)
tag_items[++last_item] = tag_item;
}
- position = item = 0;
- while (position < sizeof(stream_title) && item <= last_item) {
- gint length = 0;
-
- length = g_strlcpy(stream_title + position,
- tag_items[item++],
- sizeof(stream_title) - position);
+ int item = 0;
- position += length;
+ // Length + Metadata - "StreamTitle='';StreamUrl='';" = 4081 - 28
+ char stream_title[(1 + 255 - 28) * 16];
+ char *p = stream_title, *const end = stream_title + ARRAY_SIZE(stream_title);
+ stream_title[0] = '\0';
- if (item <= last_item) {
- length = g_strlcpy(stream_title + position,
- " - ",
- sizeof(stream_title) - position);
+ while (p < end && item <= last_item) {
+ p = CopyString(p, tag_items[item++], end - p);
- position += length;
- }
+ if (item <= last_item)
+ p = CopyString(p, " - ", end - p);
}
- icy_string = icy_server_metadata_string(stream_title, "");
+ char *icy_string = icy_server_metadata_string(stream_title, "");
if (icy_string == nullptr)
return nullptr;
diff --git a/src/output/plugins/httpd/IcyMetaDataServer.hxx b/src/output/plugins/httpd/IcyMetaDataServer.hxx
index 773b46641..38415e5bd 100644
--- a/src/output/plugins/httpd/IcyMetaDataServer.hxx
+++ b/src/output/plugins/httpd/IcyMetaDataServer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/httpd/Page.cxx b/src/output/plugins/httpd/Page.cxx
index e22134bbc..ff7036645 100644
--- a/src/output/plugins/httpd/Page.cxx
+++ b/src/output/plugins/httpd/Page.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/httpd/Page.hxx b/src/output/plugins/httpd/Page.hxx
index 95f35d06a..88b7c2d85 100644
--- a/src/output/plugins/httpd/Page.hxx
+++ b/src/output/plugins/httpd/Page.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/output/plugins/sles/SlesOutputPlugin.cxx b/src/output/plugins/sles/SlesOutputPlugin.cxx
index 85fd9f2f2..1e23cd2cc 100644
--- a/src/output/plugins/sles/SlesOutputPlugin.cxx
+++ b/src/output/plugins/sles/SlesOutputPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "Play.hxx"
#include "AndroidSimpleBufferQueue.hxx"
#include "../../OutputAPI.hxx"
+#include "../../Wrapper.hxx"
#include "util/Macros.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -34,6 +35,8 @@
#include <SLES/OpenSLES_Android.h>
class SlesOutput {
+ friend struct AudioOutputWrapper<SlesOutput>;
+
static constexpr unsigned N_BUFFERS = 3;
static constexpr size_t BUFFER_SIZE = 65536;
@@ -88,11 +91,13 @@ public:
return &base;
}
- bool Initialize(const config_param &param, Error &error) {
- return base.Configure(param, error);
+ bool Initialize(const ConfigBlock &block, Error &error) {
+ return base.Configure(block, error);
}
- bool Configure(const config_param &param, Error &error);
+ bool Configure(const ConfigBlock &block, Error &error);
+
+ static SlesOutput *Create(const ConfigBlock &block, Error &error);
bool Open(AudioFormat &audio_format, Error &error);
void Close();
@@ -126,7 +131,7 @@ private:
static constexpr Domain sles_domain("sles");
inline bool
-SlesOutput::Configure(const config_param &, Error &)
+SlesOutput::Configure(const ConfigBlock &, Error &)
{
return true;
}
@@ -441,99 +446,36 @@ sles_test_default_device()
return true;
}
-static AudioOutput *
-sles_output_init(const config_param &param, Error &error)
+inline SlesOutput *
+SlesOutput::Create(const ConfigBlock &block, Error &error)
{
SlesOutput *sles = new SlesOutput();
- if (!sles->Initialize(param, error) ||
- !sles->Configure(param, error)) {
+ if (!sles->Initialize(block, error) ||
+ !sles->Configure(block, error)) {
delete sles;
return nullptr;
}
- return *sles;
-}
-
-static void
-sles_output_finish(AudioOutput *ao)
-{
- SlesOutput *sles = (SlesOutput *)ao;
-
- delete sles;
-}
-
-static bool
-sles_output_open(AudioOutput *ao, AudioFormat &audio_format, Error &error)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- return sles.Open(audio_format, error);
+ return sles;
}
-static void
-sles_output_close(AudioOutput *ao)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- sles.Close();
-}
-
-static unsigned
-sles_output_delay(AudioOutput *ao)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- return sles.Delay();
-}
-
-static size_t
-sles_output_play(AudioOutput *ao, const void *chunk, size_t size,
- Error &error)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- return sles.Play(chunk, size, error);
-}
-
-static void
-sles_output_drain(AudioOutput *ao)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- sles.Drain();
-}
-
-static void
-sles_output_cancel(AudioOutput *ao)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- sles.Cancel();
-}
-
-static bool
-sles_output_pause(AudioOutput *ao)
-{
- SlesOutput &sles = *(SlesOutput *)ao;
-
- return sles.Pause();
-}
+typedef AudioOutputWrapper<SlesOutput> Wrapper;
const struct AudioOutputPlugin sles_output_plugin = {
"sles",
sles_test_default_device,
- sles_output_init,
- sles_output_finish,
+ &Wrapper::Init,
+ &Wrapper::Finish,
nullptr,
nullptr,
- sles_output_open,
- sles_output_close,
- sles_output_delay,
+ &Wrapper::Open,
+ &Wrapper::Close,
+ &Wrapper::Delay,
nullptr,
- sles_output_play,
- sles_output_drain,
- sles_output_cancel,
- sles_output_pause,
+ &Wrapper::Play,
+ &Wrapper::Drain,
+ &Wrapper::Cancel,
+ &Wrapper::Pause,
nullptr,
};
diff --git a/src/output/plugins/sles/SlesOutputPlugin.hxx b/src/output/plugins/sles/SlesOutputPlugin.hxx
index 5424dec2e..5a7595c24 100644
--- a/src/output/plugins/sles/SlesOutputPlugin.hxx
+++ b/src/output/plugins/sles/SlesOutputPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/ChannelsConverter.cxx b/src/pcm/ChannelsConverter.cxx
index 714613788..261af77ca 100644
--- a/src/pcm/ChannelsConverter.cxx
+++ b/src/pcm/ChannelsConverter.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/ChannelsConverter.hxx b/src/pcm/ChannelsConverter.hxx
index 1374f9f5d..aba230a86 100644
--- a/src/pcm/ChannelsConverter.hxx
+++ b/src/pcm/ChannelsConverter.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/ConfiguredResampler.cxx b/src/pcm/ConfiguredResampler.cxx
index f6aec3f95..30cb801c7 100644
--- a/src/pcm/ConfiguredResampler.cxx
+++ b/src/pcm/ConfiguredResampler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,13 +23,15 @@
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
#include "config/ConfigError.hxx"
+#include "config/Block.hxx"
+#include "config/Param.hxx"
#include "util/Error.hxx"
-#ifdef HAVE_LIBSAMPLERATE
+#ifdef ENABLE_LIBSAMPLERATE
#include "LibsamplerateResampler.hxx"
#endif
-#ifdef HAVE_SOXR
+#ifdef ENABLE_SOXR
#include "SoxrResampler.hxx"
#endif
@@ -38,45 +40,130 @@
enum class SelectedResampler {
FALLBACK,
-#ifdef HAVE_LIBSAMPLERATE
+#ifdef ENABLE_LIBSAMPLERATE
LIBSAMPLERATE,
#endif
-#ifdef HAVE_SOXR
+#ifdef ENABLE_SOXR
SOXR,
#endif
};
static SelectedResampler selected_resampler = SelectedResampler::FALLBACK;
-bool
-pcm_resampler_global_init(Error &error)
+static const ConfigBlock *
+MakeResamplerDefaultConfig(ConfigBlock &block)
{
- const char *converter =
- config_get_string(CONF_SAMPLERATE_CONVERTER, "");
+ assert(block.IsEmpty());
+
+#ifdef ENABLE_LIBSAMPLERATE
+ block.AddBlockParam("plugin", "libsamplerate");
+#elif defined(ENABLE_SOXR)
+ block.AddBlockParam("plugin", "soxr");
+#else
+ block.AddBlockParam("plugin", "internal");
+#endif
+ return &block;
+}
- if (strcmp(converter, "internal") == 0)
- return true;
+/**
+ * Convert the old "samplerate_converter" setting to a new-style
+ * "resampler" block.
+ */
+static const ConfigBlock *
+MigrateResamplerConfig(const config_param &param, ConfigBlock &block)
+{
+ assert(block.IsEmpty());
-#ifdef HAVE_SOXR
- if (memcmp(converter, "soxr", 4) == 0) {
- selected_resampler = SelectedResampler::SOXR;
- return pcm_resample_soxr_global_init(converter, error);
+ block.line = param.line;
+
+ const char *converter = param.value.c_str();
+ if (*converter == 0 || strcmp(converter, "internal") == 0) {
+ block.AddBlockParam("plugin", "internal");
+ return &block;
+ }
+
+#ifdef ENABLE_SOXR
+ if (strcmp(converter, "soxr") == 0) {
+ block.AddBlockParam("plugin", "soxr");
+ return &block;
}
-#endif
-#ifdef HAVE_LIBSAMPLERATE
- selected_resampler = SelectedResampler::LIBSAMPLERATE;
- return pcm_resample_lsr_global_init(converter, error);
+ if (memcmp(converter, "soxr ", 5) == 0) {
+ block.AddBlockParam("plugin", "soxr");
+ block.AddBlockParam("quality", converter + 5);
+ return &block;
+ }
#endif
- if (*converter == 0)
- return true;
+ block.AddBlockParam("plugin", "libsamplerate");
+ block.AddBlockParam("type", converter);
+ return &block;
+}
+
+static const ConfigBlock *
+MigrateResamplerConfig(const config_param *param, ConfigBlock &buffer)
+{
+ assert(buffer.IsEmpty());
- error.Format(config_domain,
- "The samplerate_converter '%s' is not available",
- converter);
- return false;
+ return param == nullptr
+ ? MakeResamplerDefaultConfig(buffer)
+ : MigrateResamplerConfig(*param, buffer);
+}
+
+static const ConfigBlock *
+GetResamplerConfig(ConfigBlock &buffer, Error &error)
+{
+ const auto *old_param =
+ config_get_param(ConfigOption::SAMPLERATE_CONVERTER);
+ const auto *block = config_get_block(ConfigBlockOption::RESAMPLER);
+ if (block == nullptr)
+ return MigrateResamplerConfig(old_param, buffer);
+
+ if (old_param != nullptr) {
+ error.Format(config_domain,
+ "Cannot use both 'resampler' (line %d) and 'samplerate_converter' (line %d)",
+ block->line, old_param->line);
+ return nullptr;
+ }
+
+ return block;
+}
+
+bool
+pcm_resampler_global_init(Error &error)
+{
+ ConfigBlock buffer;
+ const auto *block = GetResamplerConfig(buffer, error);
+ if (block == nullptr)
+ return false;
+
+ const char *plugin_name = block->GetBlockValue("plugin");
+ if (plugin_name == nullptr) {
+ error.Format(config_domain,
+ "'plugin' missing in line %d", block->line);
+ return false;
+ }
+
+ if (strcmp(plugin_name, "internal") == 0) {
+ selected_resampler = SelectedResampler::FALLBACK;
+ return true;
+#ifdef ENABLE_SOXR
+ } else if (strcmp(plugin_name, "soxr") == 0) {
+ selected_resampler = SelectedResampler::SOXR;
+ return pcm_resample_soxr_global_init(*block, error);
+#endif
+#ifdef ENABLE_LIBSAMPLERATE
+ } else if (strcmp(plugin_name, "libsamplerate") == 0) {
+ selected_resampler = SelectedResampler::LIBSAMPLERATE;
+ return pcm_resample_lsr_global_init(*block, error);
+#endif
+ } else {
+ error.Format(config_domain,
+ "No such resampler plugin: %s",
+ plugin_name);
+ return false;
+ }
}
PcmResampler *
@@ -86,12 +173,12 @@ pcm_resampler_create()
case SelectedResampler::FALLBACK:
return new FallbackPcmResampler();
-#ifdef HAVE_LIBSAMPLERATE
+#ifdef ENABLE_LIBSAMPLERATE
case SelectedResampler::LIBSAMPLERATE:
return new LibsampleratePcmResampler();
#endif
-#ifdef HAVE_SOXR
+#ifdef ENABLE_SOXR
case SelectedResampler::SOXR:
return new SoxrPcmResampler();
#endif
diff --git a/src/pcm/ConfiguredResampler.hxx b/src/pcm/ConfiguredResampler.hxx
index 2b14b381e..090f2ae0a 100644
--- a/src/pcm/ConfiguredResampler.hxx
+++ b/src/pcm/ConfiguredResampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Domain.cxx b/src/pcm/Domain.cxx
index ecd5c22a4..8673e5a10 100644
--- a/src/pcm/Domain.cxx
+++ b/src/pcm/Domain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Domain.hxx b/src/pcm/Domain.hxx
index 781d5c71b..47d5ef8b9 100644
--- a/src/pcm/Domain.hxx
+++ b/src/pcm/Domain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/FallbackResampler.cxx b/src/pcm/FallbackResampler.cxx
index bd3f20d86..74fbc29bd 100644
--- a/src/pcm/FallbackResampler.cxx
+++ b/src/pcm/FallbackResampler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/FallbackResampler.hxx b/src/pcm/FallbackResampler.hxx
index 38273f53f..d96b89d4f 100644
--- a/src/pcm/FallbackResampler.hxx
+++ b/src/pcm/FallbackResampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/FloatConvert.hxx b/src/pcm/FloatConvert.hxx
index 93e867159..47fe8d65a 100644
--- a/src/pcm/FloatConvert.hxx
+++ b/src/pcm/FloatConvert.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/FormatConverter.cxx b/src/pcm/FormatConverter.cxx
index 8874e1b3c..28e585e70 100644
--- a/src/pcm/FormatConverter.cxx
+++ b/src/pcm/FormatConverter.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/FormatConverter.hxx b/src/pcm/FormatConverter.hxx
index 3d8b6fb75..a67fcd7d6 100644
--- a/src/pcm/FormatConverter.hxx
+++ b/src/pcm/FormatConverter.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/GlueResampler.cxx b/src/pcm/GlueResampler.cxx
index 0f5fe0271..3b1b61c3b 100644
--- a/src/pcm/GlueResampler.cxx
+++ b/src/pcm/GlueResampler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/GlueResampler.hxx b/src/pcm/GlueResampler.hxx
index aff07823e..7471d39b7 100644
--- a/src/pcm/GlueResampler.hxx
+++ b/src/pcm/GlueResampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Interleave.cxx b/src/pcm/Interleave.cxx
new file mode 100644
index 000000000..ed9fc125d
--- /dev/null
+++ b/src/pcm/Interleave.cxx
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Interleave.hxx"
+
+#include <string.h>
+
+static void
+GenericPcmInterleave(uint8_t *gcc_restrict dest,
+ ConstBuffer<const uint8_t *> src,
+ size_t n_frames, size_t sample_size)
+{
+ for (size_t frame = 0; frame < n_frames; ++frame) {
+ for (size_t channel = 0; channel < src.size; ++channel) {
+ memcpy(dest, src[channel] + frame * sample_size,
+ sample_size);
+ dest += sample_size;
+ }
+ }
+}
+
+template<typename T>
+static void
+PcmInterleaveStereo(T *gcc_restrict dest,
+ const T *gcc_restrict src1,
+ const T *gcc_restrict src2,
+ size_t n_frames)
+{
+ for (size_t i = 0; i != n_frames; ++i) {
+ *dest++ = *src1++;
+ *dest++ = *src2++;
+ }
+}
+
+template<typename T>
+static void
+PcmInterleaveT(T *gcc_restrict dest,
+ const ConstBuffer<const T *> src,
+ size_t n_frames)
+{
+ switch (src.size) {
+ case 2:
+ PcmInterleaveStereo(dest, src[0], src[1], n_frames);
+ return;
+ }
+
+ for (const auto *s : src) {
+ auto *d = dest++;
+
+ for (const auto *const s_end = s + n_frames;
+ s != s_end; ++s, d += src.size)
+ *d = *s;
+ }
+}
+
+static void
+PcmInterleave16(int16_t *gcc_restrict dest,
+ const ConstBuffer<const int16_t *> src,
+ size_t n_frames)
+{
+ PcmInterleaveT(dest, src, n_frames);
+}
+
+void
+PcmInterleave32(int32_t *gcc_restrict dest,
+ const ConstBuffer<const int32_t *> src,
+ size_t n_frames)
+{
+ PcmInterleaveT(dest, src, n_frames);
+}
+
+void
+PcmInterleave(void *gcc_restrict dest,
+ ConstBuffer<const void *> src,
+ size_t n_frames, size_t sample_size)
+{
+ switch (sample_size) {
+ case 2:
+ PcmInterleave16((int16_t *)dest,
+ ConstBuffer<const int16_t *>((const int16_t *const*)src.data,
+ src.size),
+ n_frames);
+ break;
+
+ case 4:
+ PcmInterleave32((int32_t *)dest,
+ ConstBuffer<const int32_t *>((const int32_t *const*)src.data,
+ src.size),
+ n_frames);
+ break;
+
+ default:
+ GenericPcmInterleave((uint8_t *)dest,
+ ConstBuffer<const uint8_t *>((const uint8_t *const*)src.data,
+ src.size),
+ n_frames, sample_size);
+ }
+}
diff --git a/src/pcm/Interleave.hxx b/src/pcm/Interleave.hxx
new file mode 100644
index 000000000..3cb117d80
--- /dev/null
+++ b/src/pcm/Interleave.hxx
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PCM_INTERLEAVE_HXX
+#define MPD_PCM_INTERLEAVE_HXX
+
+#include "check.h"
+#include "Compiler.h"
+#include "util/ConstBuffer.hxx"
+
+#include <stdint.h>
+
+/**
+ * Interleave planar PCM samples from #src to #dest.
+ */
+void
+PcmInterleave(void *gcc_restrict dest, ConstBuffer<const void *> src,
+ size_t n_frames, size_t sample_size);
+
+/**
+ * A variant of PcmInterleave() that assumes 32 bit samples (4 bytes
+ * per sample).
+ */
+void
+PcmInterleave32(int32_t *gcc_restrict dest, ConstBuffer<const int32_t *> src,
+ size_t n_frames);
+
+static inline void
+PcmInterleaveFloat(float *gcc_restrict dest, ConstBuffer<const float *> src,
+ size_t n_frames)
+{
+ PcmInterleave32((int32_t *)dest,
+ ConstBuffer<const int32_t *>((const int32_t *const*)src.data,
+ src.size),
+ n_frames);
+}
+
+#endif
diff --git a/src/pcm/LibsamplerateResampler.cxx b/src/pcm/LibsamplerateResampler.cxx
index 8b22f1e32..cc6f3d43f 100644
--- a/src/pcm/LibsamplerateResampler.cxx
+++ b/src/pcm/LibsamplerateResampler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,6 +19,7 @@
#include "config.h"
#include "LibsamplerateResampler.hxx"
+#include "config/Block.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -63,8 +64,9 @@ lsr_parse_converter(const char *s)
}
bool
-pcm_resample_lsr_global_init(const char *converter, Error &error)
+pcm_resample_lsr_global_init(const ConfigBlock &block, Error &error)
{
+ const char *converter = block.GetBlockValue("type", "2");
if (!lsr_parse_converter(converter)) {
error.Format(libsamplerate_domain,
"unknown samplerate converter '%s'", converter);
diff --git a/src/pcm/LibsamplerateResampler.hxx b/src/pcm/LibsamplerateResampler.hxx
index 4f4e645e6..f19dc19eb 100644
--- a/src/pcm/LibsamplerateResampler.hxx
+++ b/src/pcm/LibsamplerateResampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,8 @@
#include <samplerate.h>
+struct ConfigBlock;
+
/**
* A resampler using libsamplerate.
*/
@@ -51,6 +53,6 @@ private:
};
bool
-pcm_resample_lsr_global_init(const char *converter, Error &error);
+pcm_resample_lsr_global_init(const ConfigBlock &block, Error &error);
#endif
diff --git a/src/pcm/Neon.hxx b/src/pcm/Neon.hxx
index 7109778ab..a2a92eea6 100644
--- a/src/pcm/Neon.hxx
+++ b/src/pcm/Neon.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmBuffer.cxx b/src/pcm/PcmBuffer.cxx
index 7bba2de47..e767872bd 100644
--- a/src/pcm/PcmBuffer.cxx
+++ b/src/pcm/PcmBuffer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmBuffer.hxx b/src/pcm/PcmBuffer.hxx
index f56a85985..eafdc649e 100644
--- a/src/pcm/PcmBuffer.hxx
+++ b/src/pcm/PcmBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmChannels.cxx b/src/pcm/PcmChannels.cxx
index 276f31045..5cf730e6c 100644
--- a/src/pcm/PcmChannels.cxx
+++ b/src/pcm/PcmChannels.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmChannels.hxx b/src/pcm/PcmChannels.hxx
index 6ad093c3b..eb6aa4828 100644
--- a/src/pcm/PcmChannels.hxx
+++ b/src/pcm/PcmChannels.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmConvert.cxx b/src/pcm/PcmConvert.cxx
index 438566759..ccc45c246 100644
--- a/src/pcm/PcmConvert.cxx
+++ b/src/pcm/PcmConvert.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmConvert.hxx b/src/pcm/PcmConvert.hxx
index 26ab02923..1f5e41bc6 100644
--- a/src/pcm/PcmConvert.hxx
+++ b/src/pcm/PcmConvert.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -74,11 +74,8 @@ public:
/**
* Converts PCM data between two audio formats.
*
- * @param src_format the source audio format
* @param src the source PCM buffer
- * @param dest_format the requested destination audio format
- * @param error_r location to store the error occurring, or nullptr to
- * ignore errors
+ * @param error location to store the error occurring
* @return the destination buffer, or nullptr on error
*/
ConstBuffer<void> Convert(ConstBuffer<void> src, Error &error);
diff --git a/src/pcm/PcmDither.cxx b/src/pcm/PcmDither.cxx
index 7b2a9e900..25252458b 100644
--- a/src/pcm/PcmDither.cxx
+++ b/src/pcm/PcmDither.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmDither.hxx b/src/pcm/PcmDither.hxx
index 54b0f7315..491f22601 100644
--- a/src/pcm/PcmDither.hxx
+++ b/src/pcm/PcmDither.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,9 +36,9 @@ public:
* Shift the given sample by #SBITS-#DBITS to the right, and
* apply dithering.
*
- * @param ST the input sample type
- * @param SBITS the input bit width
- * @param DBITS the output bit width
+ * @tparam ST the input sample type
+ * @tparam SBITS the input bit width
+ * @tparam DBITS the output bit width
* @param sample the input sample value
*/
template<typename ST, unsigned SBITS, unsigned DBITS>
diff --git a/src/pcm/PcmDop.cxx b/src/pcm/PcmDop.cxx
index b2096d9e4..e60c6d14d 100644
--- a/src/pcm/PcmDop.cxx
+++ b/src/pcm/PcmDop.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmDop.hxx b/src/pcm/PcmDop.hxx
index 03161c456..82c045911 100644
--- a/src/pcm/PcmDop.hxx
+++ b/src/pcm/PcmDop.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmDsd.cxx b/src/pcm/PcmDsd.cxx
index 53d26d480..f27c63f33 100644
--- a/src/pcm/PcmDsd.cxx
+++ b/src/pcm/PcmDsd.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmDsd.hxx b/src/pcm/PcmDsd.hxx
index e3e3a3cb1..89654ebe6 100644
--- a/src/pcm/PcmDsd.hxx
+++ b/src/pcm/PcmDsd.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmExport.cxx b/src/pcm/PcmExport.cxx
index ef099ba71..af2eb7d9f 100644
--- a/src/pcm/PcmExport.cxx
+++ b/src/pcm/PcmExport.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmExport.hxx b/src/pcm/PcmExport.hxx
index b99a35835..7265ca07d 100644
--- a/src/pcm/PcmExport.hxx
+++ b/src/pcm/PcmExport.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -86,7 +86,7 @@ struct PcmExport {
uint8_t reverse_endian;
/**
- * Open the #pcm_export_state object.
+ * Open the object.
*
* There is no "close" method. This function may be called multiple
* times to reuse the object.
diff --git a/src/pcm/PcmFormat.cxx b/src/pcm/PcmFormat.cxx
index 4cabc05a0..a70a38982 100644
--- a/src/pcm/PcmFormat.cxx
+++ b/src/pcm/PcmFormat.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmFormat.hxx b/src/pcm/PcmFormat.hxx
index da182e771..9d15011a7 100644
--- a/src/pcm/PcmFormat.hxx
+++ b/src/pcm/PcmFormat.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,9 +33,8 @@ class PcmDither;
* Converts PCM samples to 16 bit. If the source format is 24 bit,
* then dithering is applied.
*
- * @param buffer a PcmBuffer object
- * @param dither a pcm_dither object for 24-to-16 conversion
- * @param bits the number of in the source buffer
+ * @param buffer a #PcmBuffer object
+ * @param dither a #PcmDither object for 24-to-16 conversion
* @param src the source PCM buffer
* @return the destination buffer
*/
@@ -47,8 +46,7 @@ pcm_convert_to_16(PcmBuffer &buffer, PcmDither &dither,
/**
* Converts PCM samples to 24 bit (32 bit alignment).
*
- * @param buffer a PcmBuffer object
- * @param bits the number of in the source buffer
+ * @param buffer a #PcmBuffer object
* @param src the source PCM buffer
* @return the destination buffer
*/
@@ -60,8 +58,7 @@ pcm_convert_to_24(PcmBuffer &buffer,
/**
* Converts PCM samples to 32 bit.
*
- * @param buffer a PcmBuffer object
- * @param bits the number of in the source buffer
+ * @param buffer a #PcmBuffer object
* @param src the source PCM buffer
* @return the destination buffer
*/
@@ -73,11 +70,8 @@ pcm_convert_to_32(PcmBuffer &buffer,
/**
* Converts PCM samples to 32 bit floating point.
*
- * @param buffer a PcmBuffer object
- * @param bits the number of in the source buffer
+ * @param buffer a #PcmBuffer object
* @param src the source PCM buffer
- * @param src_size the size of #src in bytes
- * @param dest_size_r returns the number of bytes of the destination buffer
* @return the destination buffer
*/
gcc_pure
diff --git a/src/pcm/PcmMix.cxx b/src/pcm/PcmMix.cxx
index d21b5f04b..b67a4ec24 100644
--- a/src/pcm/PcmMix.cxx
+++ b/src/pcm/PcmMix.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmMix.hxx b/src/pcm/PcmMix.hxx
index 4e22a33f1..a906dc402 100644
--- a/src/pcm/PcmMix.hxx
+++ b/src/pcm/PcmMix.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmPack.cxx b/src/pcm/PcmPack.cxx
index 7a3379ad0..ef4406b82 100644
--- a/src/pcm/PcmPack.cxx
+++ b/src/pcm/PcmPack.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmPack.hxx b/src/pcm/PcmPack.hxx
index 271a3cd25..e05601986 100644
--- a/src/pcm/PcmPack.hxx
+++ b/src/pcm/PcmPack.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,7 +35,6 @@
*
* @param dest the destination buffer (array of triples)
* @param src the source buffer
- * @param num_samples the number of samples to convert
*/
void
pcm_pack_24(uint8_t *dest, const int32_t *src, const int32_t *src_end);
@@ -46,7 +45,6 @@ pcm_pack_24(uint8_t *dest, const int32_t *src, const int32_t *src_end);
*
* @param dest the destination buffer
* @param src the source buffer (array of triples)
- * @param num_samples the number of samples to convert
*/
void
pcm_unpack_24(int32_t *dest, const uint8_t *src, const uint8_t *src_end);
diff --git a/src/pcm/PcmPrng.hxx b/src/pcm/PcmPrng.hxx
index 5233caba6..38b48de7f 100644
--- a/src/pcm/PcmPrng.hxx
+++ b/src/pcm/PcmPrng.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/PcmUtils.hxx b/src/pcm/PcmUtils.hxx
index 23870a729..9ea9cf3b3 100644
--- a/src/pcm/PcmUtils.hxx
+++ b/src/pcm/PcmUtils.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Resampler.hxx b/src/pcm/Resampler.hxx
index 9b6ccbbc7..75f91b6ab 100644
--- a/src/pcm/Resampler.hxx
+++ b/src/pcm/Resampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -58,10 +58,7 @@ public:
* Resamples a block of PCM data.
*
* @param src the input buffer
- * @param src_size the size of #src_buffer in bytes
- * @param dest_size_r the size of the returned buffer
- * @param error location to store the error occurring, or nullptr
- * to ignore errors.
+ * @param error location to store the error occurring
* @return the destination buffer on success (will be
* invalidated by filter_close() or filter_filter()), nullptr on
* error
diff --git a/src/pcm/ShiftConvert.hxx b/src/pcm/ShiftConvert.hxx
index 92f96b7ba..e678abc56 100644
--- a/src/pcm/ShiftConvert.hxx
+++ b/src/pcm/ShiftConvert.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/SoxrResampler.cxx b/src/pcm/SoxrResampler.cxx
index b9d6fc099..f335e92e6 100644
--- a/src/pcm/SoxrResampler.cxx
+++ b/src/pcm/SoxrResampler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include "config.h"
#include "SoxrResampler.hxx"
#include "AudioFormat.hxx"
+#include "config/Block.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -32,68 +33,76 @@
static constexpr Domain soxr_domain("soxr");
-static unsigned long soxr_quality_recipe = SOXR_HQ;
+static constexpr unsigned long SOXR_DEFAULT_RECIPE = SOXR_HQ;
+/**
+ * Special value for "invalid argument".
+ */
+static constexpr unsigned long SOXR_INVALID_RECIPE = -1;
+
+static soxr_quality_spec_t soxr_quality;
+static soxr_runtime_spec_t soxr_runtime;
+
+static constexpr struct {
+ unsigned long recipe;
+ const char *name;
+} soxr_quality_table[] = {
+ { SOXR_VHQ, "very high" },
+ { SOXR_HQ, "high" },
+ { SOXR_MQ, "medium" },
+ { SOXR_LQ, "low" },
+ { SOXR_QQ, "quick" },
+ { SOXR_INVALID_RECIPE, nullptr }
+};
+
+gcc_const
static const char *
soxr_quality_name(unsigned long recipe)
{
- switch (recipe) {
- case SOXR_VHQ:
- return "Very High Quality";
- case SOXR_HQ:
- return "High Quality";
- case SOXR_MQ:
- return "Medium Quality";
- case SOXR_LQ:
- return "Low Quality";
- case SOXR_QQ:
- return "Quick";
- }
+ for (const auto *i = soxr_quality_table;; ++i) {
+ assert(i->name != nullptr);
- gcc_unreachable();
+ if (i->recipe == recipe)
+ return i->name;
+ }
}
-static bool
-soxr_parse_converter(const char *converter)
+gcc_pure
+static unsigned long
+soxr_parse_quality(const char *quality)
{
- assert(converter != nullptr);
-
- assert(memcmp(converter, "soxr", 4) == 0);
- if (converter[4] == '\0')
- return true;
- if (converter[4] != ' ')
- return false;
+ if (quality == nullptr)
+ return SOXR_DEFAULT_RECIPE;
- // converter example is "soxr very high", we want the "very high" part
- const char *quality = converter + 5;
- if (strcmp(quality, "very high") == 0)
- soxr_quality_recipe = SOXR_VHQ;
- else if (strcmp(quality, "high") == 0)
- soxr_quality_recipe = SOXR_HQ;
- else if (strcmp(quality, "medium") == 0)
- soxr_quality_recipe = SOXR_MQ;
- else if (strcmp(quality, "low") == 0)
- soxr_quality_recipe = SOXR_LQ;
- else if (strcmp(quality, "quick") == 0)
- soxr_quality_recipe = SOXR_QQ;
- else
- return false;
+ for (const auto *i = soxr_quality_table; i->name != nullptr; ++i)
+ if (strcmp(i->name, quality) == 0)
+ return i->recipe;
- return true;
+ return SOXR_INVALID_RECIPE;
}
bool
-pcm_resample_soxr_global_init(const char *converter, Error &error)
+pcm_resample_soxr_global_init(const ConfigBlock &block, Error &error)
{
- if (!soxr_parse_converter(converter)) {
+ const char *quality_string = block.GetBlockValue("quality");
+ unsigned long recipe = soxr_parse_quality(quality_string);
+ if (recipe == SOXR_INVALID_RECIPE) {
+ assert(quality_string != nullptr);
+
error.Format(soxr_domain,
- "unknown samplerate converter '%s'", converter);
+ "unknown quality setting '%s' in line %d",
+ quality_string, block.line);
return false;
}
+ soxr_quality = soxr_quality_spec(recipe, 0);
+
FormatDebug(soxr_domain,
"soxr converter '%s'",
- soxr_quality_name(soxr_quality_recipe));
+ soxr_quality_name(recipe));
+
+ const unsigned n_threads = block.GetBlockValue("threads", 1);
+ soxr_runtime = soxr_runtime_spec(n_threads);
return true;
}
@@ -106,10 +115,9 @@ SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
assert(audio_valid_sample_rate(new_sample_rate));
soxr_error_t e;
- soxr_quality_spec_t quality = soxr_quality_spec(soxr_quality_recipe, 0);
soxr = soxr_create(af.sample_rate, new_sample_rate,
af.channels, &e,
- nullptr, &quality, nullptr);
+ nullptr, &soxr_quality, &soxr_runtime);
if (soxr == nullptr) {
error.Format(soxr_domain,
"soxr initialization has failed: %s", e);
diff --git a/src/pcm/SoxrResampler.hxx b/src/pcm/SoxrResampler.hxx
index e4cba4a64..6c31ca45a 100644
--- a/src/pcm/SoxrResampler.hxx
+++ b/src/pcm/SoxrResampler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "Compiler.h"
struct AudioFormat;
+struct ConfigBlock;
/**
* A resampler using soxr.
@@ -46,6 +47,6 @@ public:
};
bool
-pcm_resample_soxr_global_init(const char *converter, Error &error);
+pcm_resample_soxr_global_init(const ConfigBlock &block, Error &error);
#endif
diff --git a/src/pcm/Traits.hxx b/src/pcm/Traits.hxx
index 97259ac73..3d124ea2f 100644
--- a/src/pcm/Traits.hxx
+++ b/src/pcm/Traits.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Volume.cxx b/src/pcm/Volume.cxx
index b12d8fd41..86dd8bd71 100644
--- a/src/pcm/Volume.cxx
+++ b/src/pcm/Volume.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/pcm/Volume.hxx b/src/pcm/Volume.hxx
index a156fc72e..5d51343b3 100644
--- a/src/pcm/Volume.hxx
+++ b/src/pcm/Volume.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlayerControl.cxx b/src/player/Control.cxx
index 4f1c3d2ac..d7352ad57 100644
--- a/src/PlayerControl.cxx
+++ b/src/player/Control.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,7 @@
*/
#include "config.h"
-#include "PlayerControl.hxx"
+#include "Control.hxx"
#include "Idle.hxx"
#include "DetachedSong.hxx"
diff --git a/src/PlayerControl.hxx b/src/player/Control.hxx
index 4d06a1827..a2807a9a1 100644
--- a/src/PlayerControl.hxx
+++ b/src/player/Control.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/CrossFade.cxx b/src/player/CrossFade.cxx
index e3cc95b0d..6d7b41440 100644
--- a/src/CrossFade.cxx
+++ b/src/player/CrossFade.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/CrossFade.hxx b/src/player/CrossFade.hxx
index 81e96e8d3..672abb718 100644
--- a/src/CrossFade.hxx
+++ b/src/player/CrossFade.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlayerListener.hxx b/src/player/Listener.hxx
index 06f00a4f5..e10f2547b 100644
--- a/src/PlayerListener.hxx
+++ b/src/player/Listener.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/PlayerThread.cxx b/src/player/Thread.cxx
index eeebcdb96..60e253f4c 100644
--- a/src/PlayerThread.cxx
+++ b/src/player/Thread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
*/
#include "config.h"
-#include "PlayerThread.hxx"
-#include "PlayerListener.hxx"
+#include "Thread.hxx"
+#include "Listener.hxx"
#include "decoder/DecoderThread.hxx"
#include "decoder/DecoderControl.hxx"
#include "MusicPipe.hxx"
@@ -28,7 +28,7 @@
#include "DetachedSong.hxx"
#include "system/FatalError.hxx"
#include "CrossFade.hxx"
-#include "PlayerControl.hxx"
+#include "Control.hxx"
#include "output/MultipleOutputs.hxx"
#include "tag/Tag.hxx"
#include "Idle.hxx"
diff --git a/src/PlayerThread.hxx b/src/player/Thread.hxx
index 537e38399..fc6ea4364 100644
--- a/src/PlayerThread.hxx
+++ b/src/player/Thread.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
* audio outputs via audio_output_all_play().
*
* It is controlled by the main thread (the playlist code), see
- * PlayerControl.hxx. The playlist enqueues new songs into the player
+ * Control.hxx. The playlist enqueues new songs into the player
* thread and sends it commands.
*
* The player thread itself does not do any I/O. It synchronizes with
diff --git a/src/playlist/CloseSongEnumerator.cxx b/src/playlist/CloseSongEnumerator.cxx
index 2dddef823..6a95fd66e 100644
--- a/src/playlist/CloseSongEnumerator.cxx
+++ b/src/playlist/CloseSongEnumerator.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/CloseSongEnumerator.hxx b/src/playlist/CloseSongEnumerator.hxx
index 17f015394..f8e352f9b 100644
--- a/src/playlist/CloseSongEnumerator.hxx
+++ b/src/playlist/CloseSongEnumerator.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/MemorySongEnumerator.cxx b/src/playlist/MemorySongEnumerator.cxx
index c3127c2bf..e34a8d628 100644
--- a/src/playlist/MemorySongEnumerator.cxx
+++ b/src/playlist/MemorySongEnumerator.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/MemorySongEnumerator.hxx b/src/playlist/MemorySongEnumerator.hxx
index d1259f011..5a1493810 100644
--- a/src/playlist/MemorySongEnumerator.hxx
+++ b/src/playlist/MemorySongEnumerator.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistAny.cxx b/src/playlist/PlaylistAny.cxx
index 7093fb99a..be59d6b0c 100644
--- a/src/playlist/PlaylistAny.cxx
+++ b/src/playlist/PlaylistAny.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistAny.hxx b/src/playlist/PlaylistAny.hxx
index 23b0075b6..ca9bf662d 100644
--- a/src/playlist/PlaylistAny.hxx
+++ b/src/playlist/PlaylistAny.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistMapper.cxx b/src/playlist/PlaylistMapper.cxx
index 042a39d34..dbac3ccc7 100644
--- a/src/playlist/PlaylistMapper.cxx
+++ b/src/playlist/PlaylistMapper.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistMapper.hxx b/src/playlist/PlaylistMapper.hxx
index 29ce45083..e5309d649 100644
--- a/src/playlist/PlaylistMapper.hxx
+++ b/src/playlist/PlaylistMapper.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistPlugin.hxx b/src/playlist/PlaylistPlugin.hxx
index fd779ad8d..8d232d2cc 100644
--- a/src/playlist/PlaylistPlugin.hxx
+++ b/src/playlist/PlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#ifndef MPD_PLAYLIST_PLUGIN_HXX
#define MPD_PLAYLIST_PLUGIN_HXX
-struct config_param;
+struct ConfigBlock;
class InputStream;
struct Tag;
class Mutex;
@@ -33,18 +33,18 @@ struct playlist_plugin {
/**
* Initialize the plugin. Optional method.
*
- * @param param a configuration block for this plugin, or nullptr
+ * @param block a configuration block for this plugin, or nullptr
* if none is configured
* @return true if the plugin was initialized successfully,
* false if the plugin is not available
*/
- bool (*init)(const config_param &param);
+ bool (*init)(const ConfigBlock &block);
/**
* Deinitialize a plugin which was initialized successfully.
* Optional method.
*/
- void (*finish)(void);
+ void (*finish)();
/**
* Opens the playlist on the specified URI. This URI has
@@ -68,17 +68,17 @@ struct playlist_plugin {
/**
* Initialize a plugin.
*
- * @param param a configuration block for this plugin, or nullptr if none
+ * @param block a configuration block for this plugin, or nullptr if none
* is configured
* @return true if the plugin was initialized successfully, false if
* the plugin is not available
*/
static inline bool
playlist_plugin_init(const struct playlist_plugin *plugin,
- const config_param &param)
+ const ConfigBlock &block)
{
return plugin->init != nullptr
- ? plugin->init(param)
+ ? plugin->init(block)
: true;
}
diff --git a/src/playlist/PlaylistQueue.cxx b/src/playlist/PlaylistQueue.cxx
index b10a26172..b6f85f586 100644
--- a/src/playlist/PlaylistQueue.cxx
+++ b/src/playlist/PlaylistQueue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistQueue.hxx b/src/playlist/PlaylistQueue.hxx
index 28eb86fcc..16bafaecf 100644
--- a/src/playlist/PlaylistQueue.hxx
+++ b/src/playlist/PlaylistQueue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistRegistry.cxx b/src/playlist/PlaylistRegistry.cxx
index 600f32b31..2156414be 100644
--- a/src/playlist/PlaylistRegistry.cxx
+++ b/src/playlist/PlaylistRegistry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +27,7 @@
#include "plugins/PlsPlaylistPlugin.hxx"
#include "plugins/AsxPlaylistPlugin.hxx"
#include "plugins/RssPlaylistPlugin.hxx"
+#include "plugins/FlacPlaylistPlugin.hxx"
#include "plugins/CuePlaylistPlugin.hxx"
#include "plugins/EmbeddedCuePlaylistPlugin.hxx"
#include "input/InputStream.hxx"
@@ -35,7 +36,7 @@
#include "util/Error.hxx"
#include "util/Macros.hxx"
#include "config/ConfigGlobal.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "Log.hxx"
#include <assert.h>
@@ -44,11 +45,8 @@
const struct playlist_plugin *const playlist_plugins[] = {
&extm3u_playlist_plugin,
&m3u_playlist_plugin,
-#ifdef HAVE_GLIB
- // TODO: enable without GLib
&pls_playlist_plugin,
-#endif
-#ifdef HAVE_EXPAT
+#ifdef ENABLE_EXPAT
&xspf_playlist_plugin,
&asx_playlist_plugin,
&rss_playlist_plugin,
@@ -56,8 +54,13 @@ const struct playlist_plugin *const playlist_plugins[] = {
#ifdef ENABLE_SOUNDCLOUD
&soundcloud_playlist_plugin,
#endif
+#ifdef ENABLE_FLAC
+ &flac_playlist_plugin,
+#endif
+#ifdef ENABLE_CUE
&cue_playlist_plugin,
&embcue_playlist_plugin,
+#endif
nullptr
};
@@ -74,13 +77,13 @@ static bool playlist_plugins_enabled[n_playlist_plugins];
void
playlist_list_global_init(void)
{
- const config_param empty;
+ const ConfigBlock empty;
for (unsigned i = 0; playlist_plugins[i] != nullptr; ++i) {
const struct playlist_plugin *plugin = playlist_plugins[i];
- const struct config_param *param =
- config_find_block(CONF_PLAYLIST_PLUGIN, "name",
- plugin->name);
+ const auto *param =
+ config_find_block(ConfigBlockOption::PLAYLIST_PLUGIN,
+ "name", plugin->name);
if (param == nullptr)
param = &empty;
else if (!param->GetBlockValue("enabled", true))
diff --git a/src/playlist/PlaylistRegistry.hxx b/src/playlist/PlaylistRegistry.hxx
index 7ce559baa..09e842b13 100644
--- a/src/playlist/PlaylistRegistry.hxx
+++ b/src/playlist/PlaylistRegistry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,13 +37,13 @@ extern const struct playlist_plugin *const playlist_plugins[];
* Initializes all playlist plugins.
*/
void
-playlist_list_global_init(void);
+playlist_list_global_init();
/**
* Deinitializes all playlist plugins.
*/
void
-playlist_list_global_finish(void);
+playlist_list_global_finish();
/**
* Opens a playlist by its URI.
@@ -57,7 +57,7 @@ playlist_list_open_stream_suffix(InputStream &is, const char *suffix);
/**
* Opens a playlist from an input stream.
*
- * @param is an #input_stream object which is open and ready
+ * @param is an #InputStream object which is open and ready
* @param uri optional URI which was used to open the stream; may be
* used to select the appropriate playlist plugin
*/
diff --git a/src/playlist/PlaylistSong.cxx b/src/playlist/PlaylistSong.cxx
index 3603c1add..72f913418 100644
--- a/src/playlist/PlaylistSong.cxx
+++ b/src/playlist/PlaylistSong.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistSong.hxx b/src/playlist/PlaylistSong.hxx
index 278df46a8..0674c02c9 100644
--- a/src/playlist/PlaylistSong.hxx
+++ b/src/playlist/PlaylistSong.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/PlaylistStream.cxx b/src/playlist/PlaylistStream.cxx
index 074f39d66..99e1c3182 100644
--- a/src/playlist/PlaylistStream.cxx
+++ b/src/playlist/PlaylistStream.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -35,8 +35,12 @@ playlist_open_path_suffix(Path path, Mutex &mutex, Cond &cond)
{
assert(!path.IsNull());
- const char *suffix = uri_get_suffix(path.c_str());
- if (suffix == nullptr || !playlist_suffix_supported(suffix))
+ const auto *suffix = path.GetSuffix();
+ if (suffix == nullptr)
+ return nullptr;
+
+ const auto suffix_utf8 = Path::FromFS(suffix).ToUTF8();
+ if (!playlist_suffix_supported(suffix_utf8.c_str()))
return nullptr;
Error error;
@@ -46,7 +50,8 @@ playlist_open_path_suffix(Path path, Mutex &mutex, Cond &cond)
return nullptr;
}
- auto playlist = playlist_list_open_stream_suffix(*is, suffix);
+ auto playlist = playlist_list_open_stream_suffix(*is,
+ suffix_utf8.c_str());
if (playlist != nullptr)
playlist = new CloseSongEnumerator(playlist, is);
else
diff --git a/src/playlist/PlaylistStream.hxx b/src/playlist/PlaylistStream.hxx
index c07ae0b09..f9bba7722 100644
--- a/src/playlist/PlaylistStream.hxx
+++ b/src/playlist/PlaylistStream.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -31,8 +31,6 @@ class Path;
* Opens a playlist from a local file.
*
* @param path the path of the playlist file
- * @param is_r on success, an input_stream object is returned here,
- * which must be closed after the playlist_provider object is freed
* @return a playlist, or nullptr on error
*/
gcc_nonnull_all
diff --git a/src/playlist/Print.cxx b/src/playlist/Print.cxx
index 8f743f56d..13e45d160 100644
--- a/src/playlist/Print.cxx
+++ b/src/playlist/Print.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,48 +28,51 @@
#include "fs/Traits.hxx"
#include "thread/Mutex.hxx"
#include "thread/Cond.hxx"
-#include "client/Client.hxx"
+#include "Partition.hxx"
+#include "Instance.hxx"
static void
-playlist_provider_print(Client &client, const char *uri,
+playlist_provider_print(Response &r, Partition &partition,
+ const SongLoader &loader,
+ const char *uri,
SongEnumerator &e, bool detail)
{
const std::string base_uri = uri != nullptr
? PathTraitsUTF8::GetParent(uri)
: std::string(".");
- const SongLoader loader(client);
-
DetachedSong *song;
while ((song = e.NextSong()) != nullptr) {
if (playlist_check_translate_song(*song, base_uri.c_str(),
loader) &&
detail)
- song_print_info(client, *song);
+ song_print_info(r, partition, *song);
else
/* fallback if no detail was requested or no
detail was available */
- song_print_uri(client, *song);
+ song_print_uri(r, partition, *song);
delete song;
}
}
bool
-playlist_file_print(Client &client, const char *uri, bool detail)
+playlist_file_print(Response &r, Partition &partition,
+ const SongLoader &loader,
+ const char *uri, bool detail)
{
Mutex mutex;
Cond cond;
SongEnumerator *playlist = playlist_open_any(uri,
#ifdef ENABLE_DATABASE
- client.GetStorage(),
+ partition.instance.storage,
#endif
mutex, cond);
if (playlist == nullptr)
return false;
- playlist_provider_print(client, uri, *playlist, detail);
+ playlist_provider_print(r, partition, loader, uri, *playlist, detail);
delete playlist;
return true;
}
diff --git a/src/playlist/Print.hxx b/src/playlist/Print.hxx
index c2fff5475..3b356d4ce 100644
--- a/src/playlist/Print.hxx
+++ b/src/playlist/Print.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,17 +20,20 @@
#ifndef MPD_PLAYLIST__PRINT_HXX
#define MPD_PLAYLIST__PRINT_HXX
-class Client;
+class Response;
+class SongLoader;
+struct Partition;
/**
* Send the playlist file to the client.
*
- * @param client the client which requested the playlist
* @param uri the URI of the playlist file in UTF-8 encoding
* @param detail true if all details should be printed
* @return true on success, false if the playlist does not exist
*/
bool
-playlist_file_print(Client &client, const char *uri, bool detail);
+playlist_file_print(Response &r, Partition &partition,
+ const SongLoader &loader,
+ const char *uri, bool detail);
#endif
diff --git a/src/playlist/SongEnumerator.hxx b/src/playlist/SongEnumerator.hxx
index 75295add1..0f6997785 100644
--- a/src/playlist/SongEnumerator.hxx
+++ b/src/playlist/SongEnumerator.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/cue/CueParser.cxx b/src/playlist/cue/CueParser.cxx
index 372c90b78..81797fe28 100644
--- a/src/playlist/cue/CueParser.cxx
+++ b/src/playlist/cue/CueParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -250,7 +250,6 @@ CueParser::Feed2(char *p)
song_tag = header_tag;
song_tag.AddItem(TAG_TRACK, nr);
- last_updated = false;
} else if (state == IGNORE_TRACK) {
return;
} else if (state == TRACK && strcmp(command, "INDEX") == 0) {
@@ -266,13 +265,12 @@ CueParser::Feed2(char *p)
if (position_ms < 0)
return;
- if (!last_updated && previous != nullptr &&
- previous->GetStartTime().ToMS() < (unsigned)position_ms) {
- last_updated = true;
+ if (previous != nullptr && previous->GetStartTime().ToMS() < (unsigned)position_ms)
previous->SetEndTime(SongTime::FromMS(position_ms));
- }
current->SetStartTime(SongTime::FromMS(position_ms));
+ if(strcmp(nr, "00") != 0 || previous == nullptr)
+ state = IGNORE_TRACK;
}
}
diff --git a/src/playlist/cue/CueParser.hxx b/src/playlist/cue/CueParser.hxx
index 7e040169b..925f1234c 100644
--- a/src/playlist/cue/CueParser.hxx
+++ b/src/playlist/cue/CueParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -89,12 +89,6 @@ class CueParser {
DetachedSong *finished;
/**
- * Set to true after previous.end_time has been updated to the
- * start time of the current song.
- */
- bool last_updated;
-
- /**
* Tracks whether cue_parser_finish() has been called. If
* true, then all remaining (partial) results will be
* delivered by cue_parser_get().
diff --git a/src/playlist/plugins/AsxPlaylistPlugin.cxx b/src/playlist/plugins/AsxPlaylistPlugin.cxx
index 3185a8144..1a0334237 100644
--- a/src/playlist/plugins/AsxPlaylistPlugin.cxx
+++ b/src/playlist/plugins/AsxPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,11 +24,12 @@
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
+#include "util/StringView.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "Log.hxx"
/**
- * This is the state object for the GLib XML parser.
+ * This is the state object for our XML parser.
*/
struct AsxParser {
/**
@@ -130,7 +131,8 @@ asx_char_data(void *user_data, const XML_Char *s, int len)
case AsxParser::ENTRY:
if (parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
- parser->tag_builder.AddItem(parser->tag_type, s, len);
+ parser->tag_builder.AddItem(parser->tag_type,
+ StringView(s, len));
break;
}
diff --git a/src/playlist/plugins/AsxPlaylistPlugin.hxx b/src/playlist/plugins/AsxPlaylistPlugin.hxx
index 63371be0f..b14eeda87 100644
--- a/src/playlist/plugins/AsxPlaylistPlugin.hxx
+++ b/src/playlist/plugins/AsxPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/CuePlaylistPlugin.cxx b/src/playlist/plugins/CuePlaylistPlugin.cxx
index b907d34d0..df6946abc 100644
--- a/src/playlist/plugins/CuePlaylistPlugin.cxx
+++ b/src/playlist/plugins/CuePlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/CuePlaylistPlugin.hxx b/src/playlist/plugins/CuePlaylistPlugin.hxx
index 4d833bfc2..6daad4241 100644
--- a/src/playlist/plugins/CuePlaylistPlugin.hxx
+++ b/src/playlist/plugins/CuePlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
index 8baa11c03..e12dc2df0 100644
--- a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
+++ b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -128,8 +128,10 @@ DetachedSong *
EmbeddedCuePlaylist::NextSong()
{
DetachedSong *song = parser->Get();
- if (song != nullptr)
+ if (song != nullptr) {
+ song->SetURI(filename);
return song;
+ }
while (*next != 0) {
const char *line = next;
diff --git a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx
index 5eedf3f13..9721481d5 100644
--- a/src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx
+++ b/src/playlist/plugins/EmbeddedCuePlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
index 93316ca6c..e60ef4aa6 100644
--- a/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
+++ b/src/playlist/plugins/ExtM3uPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/ExtM3uPlaylistPlugin.hxx b/src/playlist/plugins/ExtM3uPlaylistPlugin.hxx
index 5743ded43..625afcd2d 100644
--- a/src/playlist/plugins/ExtM3uPlaylistPlugin.hxx
+++ b/src/playlist/plugins/ExtM3uPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/FlacPlaylistPlugin.cxx b/src/playlist/plugins/FlacPlaylistPlugin.cxx
new file mode 100644
index 000000000..19b77ef32
--- /dev/null
+++ b/src/playlist/plugins/FlacPlaylistPlugin.cxx
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/** \file
+ *
+ * Playlist plugin that reads embedded cue sheets from the "CUESHEET"
+ * tag of a music file.
+ */
+
+#include "config.h"
+#include "FlacPlaylistPlugin.hxx"
+#include "../PlaylistPlugin.hxx"
+#include "../SongEnumerator.hxx"
+#include "DetachedSong.hxx"
+#include "fs/Traits.hxx"
+#include "fs/AllocatedPath.hxx"
+#include "fs/NarrowPath.hxx"
+
+#include <FLAC/metadata.h>
+
+#include <string.h>
+
+class FlacPlaylist final : public SongEnumerator {
+ const char *const uri;
+
+ FLAC__StreamMetadata *const cuesheet;
+ const unsigned sample_rate;
+ const FLAC__uint64 total_samples;
+
+ unsigned next_track = 0;
+
+public:
+ FlacPlaylist(const char *_uri,
+ FLAC__StreamMetadata *_cuesheet,
+ const FLAC__StreamMetadata &streaminfo)
+ :uri(_uri), cuesheet(_cuesheet),
+ sample_rate(streaminfo.data.stream_info.sample_rate),
+ total_samples(streaminfo.data.stream_info.total_samples) {
+ }
+
+ virtual ~FlacPlaylist() {
+ FLAC__metadata_object_delete(cuesheet);
+ }
+
+ virtual DetachedSong *NextSong() override;
+};
+
+DetachedSong *
+FlacPlaylist::NextSong()
+{
+ const FLAC__StreamMetadata_CueSheet &c = cuesheet->data.cue_sheet;
+
+ /* find the next audio track */
+
+ while (next_track < c.num_tracks &&
+ (c.tracks[next_track].number > c.num_tracks ||
+ c.tracks[next_track].type != 0))
+ ++next_track;
+
+ if (next_track >= c.num_tracks)
+ return nullptr;
+
+ FLAC__uint64 start = c.tracks[next_track].offset;
+ ++next_track;
+ FLAC__uint64 end = next_track < c.num_tracks
+ ? c.tracks[next_track].offset
+ : total_samples;
+
+ auto *song = new DetachedSong(uri);
+ song->SetStartTime(SongTime::FromScale(start, sample_rate));
+ song->SetEndTime(SongTime::FromScale(end, sample_rate));
+ return song;
+}
+
+static SongEnumerator *
+flac_playlist_open_uri(const char *uri,
+ gcc_unused Mutex &mutex, gcc_unused Cond &cond)
+{
+ if (!PathTraitsUTF8::IsAbsolute(uri))
+ /* only local files supported */
+ return nullptr;
+
+ const auto path_fs = AllocatedPath::FromUTF8(uri);
+ if (path_fs.IsNull())
+ return nullptr;
+
+ const NarrowPath narrow_path_fs(path_fs);
+
+ FLAC__StreamMetadata *cuesheet;
+ if (!FLAC__metadata_get_cuesheet(narrow_path_fs, &cuesheet))
+ return nullptr;
+
+ FLAC__StreamMetadata streaminfo;
+ if (!FLAC__metadata_get_streaminfo(uri, &streaminfo) ||
+ streaminfo.data.stream_info.sample_rate == 0) {
+ FLAC__metadata_object_delete(cuesheet);
+ return nullptr;
+ }
+
+ return new FlacPlaylist(uri, cuesheet, streaminfo);
+}
+
+static const char *const flac_playlist_suffixes[] = {
+ "flac",
+ nullptr
+};
+
+const struct playlist_plugin flac_playlist_plugin = {
+ "flac",
+
+ nullptr,
+ nullptr,
+ flac_playlist_open_uri,
+ nullptr,
+
+ nullptr,
+ flac_playlist_suffixes,
+ nullptr,
+};
diff --git a/src/playlist/plugins/FlacPlaylistPlugin.hxx b/src/playlist/plugins/FlacPlaylistPlugin.hxx
new file mode 100644
index 000000000..632be6b12
--- /dev/null
+++ b/src/playlist/plugins/FlacPlaylistPlugin.hxx
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_FLAC_PLAYLIST_PLUGIN_HXX
+#define MPD_FLAC_PLAYLIST_PLUGIN_HXX
+
+extern const struct playlist_plugin flac_playlist_plugin;
+
+#endif
diff --git a/src/playlist/plugins/M3uPlaylistPlugin.cxx b/src/playlist/plugins/M3uPlaylistPlugin.cxx
index 0428d291a..9e7647dd7 100644
--- a/src/playlist/plugins/M3uPlaylistPlugin.cxx
+++ b/src/playlist/plugins/M3uPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/M3uPlaylistPlugin.hxx b/src/playlist/plugins/M3uPlaylistPlugin.hxx
index f1ad14069..9df4482d9 100644
--- a/src/playlist/plugins/M3uPlaylistPlugin.hxx
+++ b/src/playlist/plugins/M3uPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/PlsPlaylistPlugin.cxx b/src/playlist/plugins/PlsPlaylistPlugin.cxx
index f7724f522..7d2579cd3 100644
--- a/src/playlist/plugins/PlsPlaylistPlugin.cxx
+++ b/src/playlist/plugins/PlsPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,121 +21,139 @@
#include "PlsPlaylistPlugin.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
-#include "input/InputStream.hxx"
+#include "input/TextInputStream.hxx"
#include "DetachedSong.hxx"
#include "tag/TagBuilder.hxx"
+#include "util/ASCII.hxx"
+#include "util/StringUtil.hxx"
+#include "util/DivideString.hxx"
#include "util/Error.hxx"
-#include "util/Domain.hxx"
-#include "Log.hxx"
-
-#include <glib.h>
#include <string>
-#include <stdio.h>
-
-#include <stdio.h>
-static constexpr Domain pls_domain("pls");
+#include <stdlib.h>
-static void
-pls_parser(GKeyFile *keyfile, std::forward_list<DetachedSong> &songs)
+static bool
+FindPlaylistSection(TextInputStream &is)
{
- gchar *value;
- GError *error = nullptr;
- int num_entries = g_key_file_get_integer(keyfile, "playlist",
- "NumberOfEntries", &error);
- if (error) {
- FormatError(pls_domain,
- "Invalid PLS file: '%s'", error->message);
- g_error_free(error);
- error = nullptr;
-
- /* Hack to work around shoutcast failure to comform to spec */
- num_entries = g_key_file_get_integer(keyfile, "playlist",
- "numberofentries", &error);
- if (error) {
- g_error_free(error);
- error = nullptr;
- }
+ char *line;
+ while ((line = is.ReadLine()) != nullptr) {
+ line = Strip(line);
+ if (StringEqualsCaseASCII(line, "[playlist]"))
+ return true;
}
- for (; num_entries > 0; --num_entries) {
- char key[64];
- sprintf(key, "File%u", num_entries);
- char *uri = g_key_file_get_string(keyfile, "playlist", key,
- &error);
- if(error) {
- FormatError(pls_domain, "Invalid PLS entry %s: '%s'",
- key, error->message);
- g_error_free(error);
- return;
- }
+ return false;
+}
- TagBuilder tag;
+static bool
+ParsePls(TextInputStream &is, std::forward_list<DetachedSong> &songs)
+{
+ assert(songs.empty());
- sprintf(key, "Title%u", num_entries);
- value = g_key_file_get_string(keyfile, "playlist", key,
- nullptr);
- if (value != nullptr)
- tag.AddItem(TAG_TITLE, value);
+ if (!FindPlaylistSection(is))
+ return false;
- g_free(value);
+ unsigned n_entries = 0;
- sprintf(key, "Length%u", num_entries);
- int length = g_key_file_get_integer(keyfile, "playlist", key,
- nullptr);
- if (length > 0)
- tag.SetDuration(SignedSongTime::FromS(length));
+ struct Entry {
+ std::string file, title;
+ int length;
- songs.emplace_front(uri, tag.Commit());
- g_free(uri);
- }
+ Entry():length(-1) {}
+ };
-}
+ static constexpr unsigned MAX_ENTRIES = 65536;
-static SongEnumerator *
-pls_open_stream(InputStream &is)
-{
- GError *error = nullptr;
- Error error2;
-
- std::string kf_data;
-
- do {
- char buffer[1024];
- size_t nbytes = is.LockRead(buffer, sizeof(buffer), error2);
- if (nbytes == 0) {
- if (error2.IsDefined()) {
- LogError(error2);
- return nullptr;
- }
+ std::vector<Entry> entries;
+
+ char *line;
+ while ((line = is.ReadLine()) != nullptr) {
+ line = Strip(line);
+ if (*line == 0 || *line == ';')
+ continue;
+
+ if (*line == '[')
+ /* another section starts; we only want
+ [Playlist], so stop here */
break;
+
+ const DivideString ds(line, '=', true);
+ if (!ds.IsDefined())
+ continue;
+
+ const char *const name = ds.GetFirst();
+ const char *const value = ds.GetSecond();
+
+ if (StringEqualsCaseASCII(name, "NumberOfEntries")) {
+ n_entries = strtoul(value, nullptr, 10);
+ if (n_entries == 0)
+ /* empty file - nothing remains to be
+ done */
+ return true;
+
+ if (n_entries > MAX_ENTRIES)
+ n_entries = MAX_ENTRIES;
+ entries.resize(n_entries);
+ } else if (StringEqualsCaseASCII(name, "File", 4)) {
+ unsigned i = strtoul(name + 4, nullptr, 10);
+ if (i >= 1 && i <= (n_entries > 0 ? n_entries : MAX_ENTRIES)) {
+ if (entries.size() < i)
+ entries.resize(i);
+ entries[i - 1].file = value;
+ }
+ } else if (StringEqualsCaseASCII(name, "Title", 5)) {
+ unsigned i = strtoul(name + 5, nullptr, 10);
+ if (i >= 1 && i <= (n_entries > 0 ? n_entries : MAX_ENTRIES)) {
+ if (entries.size() < i)
+ entries.resize(i);
+ entries[i - 1].title = value;
+ }
+ } else if (StringEqualsCaseASCII(name, "Length", 6)) {
+ unsigned i = strtoul(name + 6, nullptr, 10);
+ if (i >= 1 && i <= (n_entries > 0 ? n_entries : MAX_ENTRIES)) {
+ if (entries.size() < i)
+ entries.resize(i);
+ entries[i - 1].length = atoi(value);
+ }
}
+ }
- kf_data.append(buffer, nbytes);
- /* Limit to 64k */
- } while (kf_data.length() < 65536);
+ if (n_entries == 0)
+ /* no "NumberOfEntries" found */
+ return false;
- if (kf_data.empty()) {
- LogWarning(pls_domain, "KeyFile parser failed: No Data");
- return nullptr;
- }
+ auto i = songs.before_begin();
+ for (const auto &entry : entries) {
+ const char *uri = entry.file.c_str();
- GKeyFile *keyfile = g_key_file_new();
- if (!g_key_file_load_from_data(keyfile,
- kf_data.data(), kf_data.length(),
- G_KEY_FILE_NONE, &error)) {
- FormatError(pls_domain,
- "KeyFile parser failed: %s", error->message);
- g_error_free(error);
- g_key_file_free(keyfile);
- return nullptr;
+ TagBuilder tag;
+ if (!entry.title.empty())
+ tag.AddItem(TAG_TITLE, entry.title.c_str());
+
+ if (entry.length > 0)
+ tag.SetDuration(SignedSongTime::FromS(entry.length));
+
+ i = songs.emplace_after(i, uri, tag.Commit());
}
+ return true;
+}
+
+static bool
+ParsePls(InputStream &is, std::forward_list<DetachedSong> &songs)
+{
+ TextInputStream tis(is);
+ return ParsePls(tis, songs);
+}
+
+static SongEnumerator *
+pls_open_stream(InputStream &is)
+{
std::forward_list<DetachedSong> songs;
- pls_parser(keyfile, songs);
- g_key_file_free(keyfile);
+ if (!ParsePls(is, songs))
+ return nullptr;
return new MemorySongEnumerator(std::move(songs));
}
diff --git a/src/playlist/plugins/PlsPlaylistPlugin.hxx b/src/playlist/plugins/PlsPlaylistPlugin.hxx
index 1a3f33873..c7a1e331c 100644
--- a/src/playlist/plugins/PlsPlaylistPlugin.hxx
+++ b/src/playlist/plugins/PlsPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/RssPlaylistPlugin.cxx b/src/playlist/plugins/RssPlaylistPlugin.cxx
index 6f9aad54b..a2d8e7a42 100644
--- a/src/playlist/plugins/RssPlaylistPlugin.cxx
+++ b/src/playlist/plugins/RssPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,11 +24,12 @@
#include "tag/TagBuilder.hxx"
#include "util/ASCII.hxx"
#include "util/Error.hxx"
+#include "util/StringView.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "Log.hxx"
/**
- * This is the state object for the GLib XML parser.
+ * This is the state object for the our XML parser.
*/
struct RssParser {
/**
@@ -128,7 +129,8 @@ rss_char_data(void *user_data, const XML_Char *s, int len)
case RssParser::ITEM:
if (parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
- parser->tag_builder.AddItem(parser->tag_type, s, len);
+ parser->tag_builder.AddItem(parser->tag_type,
+ StringView(s, len));
break;
}
diff --git a/src/playlist/plugins/RssPlaylistPlugin.hxx b/src/playlist/plugins/RssPlaylistPlugin.hxx
index a00a5a898..4928df904 100644
--- a/src/playlist/plugins/RssPlaylistPlugin.hxx
+++ b/src/playlist/plugins/RssPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
index ec4d240a5..d6f25f48c 100644
--- a/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
+++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,20 +21,21 @@
#include "SoundCloudPlaylistPlugin.hxx"
#include "../PlaylistPlugin.hxx"
#include "../MemorySongEnumerator.hxx"
-#include "config/ConfigData.hxx"
+#include "config/Block.hxx"
#include "input/InputStream.hxx"
#include "tag/TagBuilder.hxx"
#include "util/StringUtil.hxx"
+#include "util/Alloc.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
#include "Log.hxx"
-#include <glib.h>
#include <yajl/yajl_parse.h>
#include <string>
#include <string.h>
+#include <stdlib.h>
static struct {
std::string apikey;
@@ -43,10 +44,10 @@ static struct {
static constexpr Domain soundcloud_domain("soundcloud");
static bool
-soundcloud_init(const config_param &param)
+soundcloud_init(const ConfigBlock &block)
{
// APIKEY for MPD application, registered under DarkFox' account.
- soundcloud_config.apikey = param.GetBlockValue("apikey", "a25e51780f7f86af0afa91f241d091f8");
+ soundcloud_config.apikey = block.GetBlockValue("apikey", "a25e51780f7f86af0afa91f241d091f8");
if (soundcloud_config.apikey.empty()) {
LogDebug(soundcloud_domain,
"disabling the soundcloud playlist plugin "
@@ -60,7 +61,7 @@ soundcloud_init(const config_param &param)
/**
* Construct a full soundcloud resolver URL from the given fragment.
* @param uri uri of a soundcloud page (or just the path)
- * @return Constructed URL. Must be freed with g_free.
+ * @return Constructed URL. Must be freed with free().
*/
static char *
soundcloud_resolve(const char* uri)
@@ -68,18 +69,18 @@ soundcloud_resolve(const char* uri)
char *u, *ru;
if (StringStartsWith(uri, "https://")) {
- u = g_strdup(uri);
+ u = xstrdup(uri);
} else if (StringStartsWith(uri, "soundcloud.com")) {
- u = g_strconcat("https://", uri, nullptr);
+ u = xstrcatdup("https://", uri);
} else {
/* assume it's just a path on soundcloud.com */
- u = g_strconcat("https://soundcloud.com/", uri, nullptr);
+ u = xstrcatdup("https://soundcloud.com/", uri);
}
- ru = g_strconcat("https://api.soundcloud.com/resolve.json?url=",
- u, "&client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
- g_free(u);
+ ru = xstrcatdup("https://api.soundcloud.com/resolve.json?url=",
+ u, "&client_id=",
+ soundcloud_config.apikey.c_str());
+ free(u);
return ru;
}
@@ -111,12 +112,7 @@ struct parse_data {
};
static int
-handle_integer(void *ctx,
- long
-#ifndef HAVE_YAJL1
- long
-#endif
- intval)
+handle_integer(void *ctx, long long intval)
{
struct parse_data *data = (struct parse_data *) ctx;
@@ -132,25 +128,19 @@ handle_integer(void *ctx,
}
static int
-handle_string(void *ctx, const unsigned char* stringval,
-#ifdef HAVE_YAJL1
- unsigned int
-#else
- size_t
-#endif
- stringlen)
+handle_string(void *ctx, const unsigned char *stringval, size_t stringlen)
{
struct parse_data *data = (struct parse_data *) ctx;
const char *s = (const char *) stringval;
switch (data->key) {
case Title:
- g_free(data->title);
- data->title = g_strndup(s, stringlen);
+ free(data->title);
+ data->title = xstrndup(s, stringlen);
break;
case Stream_URL:
- g_free(data->stream_url);
- data->stream_url = g_strndup(s, stringlen);
+ free(data->stream_url);
+ data->stream_url = xstrndup(s, stringlen);
data->got_url = 1;
break;
default:
@@ -161,13 +151,7 @@ handle_string(void *ctx, const unsigned char* stringval,
}
static int
-handle_mapkey(void *ctx, const unsigned char* stringval,
-#ifdef HAVE_YAJL1
- unsigned int
-#else
- size_t
-#endif
- stringlen)
+handle_mapkey(void *ctx, const unsigned char *stringval, size_t stringlen)
{
struct parse_data *data = (struct parse_data *) ctx;
@@ -211,8 +195,8 @@ handle_end_map(void *ctx)
/* got_url == 1, track finished, make it into a song */
data->got_url = 0;
- char *u = g_strconcat(data->stream_url, "?client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
+ char *u = xstrcatdup(data->stream_url, "?client_id=",
+ soundcloud_config.apikey.c_str());
TagBuilder tag;
tag.SetDuration(SignedSongTime::FromMS(data->duration));
@@ -220,7 +204,7 @@ handle_end_map(void *ctx)
tag.AddItem(TAG_NAME, data->title);
data->songs.emplace_front(u, tag.Commit());
- g_free(u);
+ free(u);
return 1;
}
@@ -282,20 +266,11 @@ soundcloud_parse_json(const char *url, yajl_handle hand,
}
if (done) {
-#ifdef HAVE_YAJL1
- stat = yajl_parse_complete(hand);
-#else
stat = yajl_complete_parse(hand);
-#endif
} else
stat = yajl_parse(hand, ubuffer, nbytes);
- if (stat != yajl_status_ok
-#ifdef HAVE_YAJL1
- && stat != yajl_status_insufficient_data
-#endif
- )
- {
+ if (stat != yajl_status_ok) {
unsigned char *str = yajl_get_error(hand, 1, ubuffer, nbytes);
LogError(soundcloud_domain, (const char *)str);
yajl_free_error(hand, str);
@@ -325,24 +300,24 @@ soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
char *u = nullptr;
if (memcmp(uri, "track/", 6) == 0) {
const char *rest = uri + 6;
- u = g_strconcat("https://api.soundcloud.com/tracks/",
- rest, ".json?client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
+ u = xstrcatdup("https://api.soundcloud.com/tracks/",
+ rest, ".json?client_id=",
+ soundcloud_config.apikey.c_str());
} else if (memcmp(uri, "playlist/", 9) == 0) {
const char *rest = uri + 9;
- u = g_strconcat("https://api.soundcloud.com/playlists/",
- rest, ".json?client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
+ u = xstrcatdup("https://api.soundcloud.com/playlists/",
+ rest, ".json?client_id=",
+ soundcloud_config.apikey.c_str());
} else if (memcmp(uri, "user/", 5) == 0) {
const char *rest = uri + 5;
- u = g_strconcat("https://api.soundcloud.com/users/",
- rest, "/tracks.json?client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
+ u = xstrcatdup("https://api.soundcloud.com/users/",
+ rest, "/tracks.json?client_id=",
+ soundcloud_config.apikey.c_str());
} else if (memcmp(uri, "search/", 7) == 0) {
const char *rest = uri + 7;
- u = g_strconcat("https://api.soundcloud.com/tracks.json?q=",
- rest, "&client_id=",
- soundcloud_config.apikey.c_str(), nullptr);
+ u = xstrcatdup("https://api.soundcloud.com/tracks.json?q=",
+ rest, "&client_id=",
+ soundcloud_config.apikey.c_str());
} else if (memcmp(uri, "url/", 4) == 0) {
const char *rest = uri + 4;
/* Translate to soundcloud resolver call. libcurl will automatically
@@ -359,19 +334,14 @@ soundcloud_open_uri(const char *uri, Mutex &mutex, Cond &cond)
data.got_url = 0;
data.title = nullptr;
data.stream_url = nullptr;
-#ifdef HAVE_YAJL1
- yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, nullptr,
- &data);
-#else
yajl_handle hand = yajl_alloc(&parse_callbacks, nullptr, &data);
-#endif
int ret = soundcloud_parse_json(u, hand, mutex, cond);
- g_free(u);
+ free(u);
yajl_free(hand);
- g_free(data.title);
- g_free(data.stream_url);
+ free(data.title);
+ free(data.stream_url);
if (ret == -1)
return nullptr;
diff --git a/src/playlist/plugins/SoundCloudPlaylistPlugin.hxx b/src/playlist/plugins/SoundCloudPlaylistPlugin.hxx
index b355b477a..199d21e56 100644
--- a/src/playlist/plugins/SoundCloudPlaylistPlugin.hxx
+++ b/src/playlist/plugins/SoundCloudPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/playlist/plugins/XspfPlaylistPlugin.cxx b/src/playlist/plugins/XspfPlaylistPlugin.cxx
index d25d6dc28..0b7358e15 100644
--- a/src/playlist/plugins/XspfPlaylistPlugin.cxx
+++ b/src/playlist/plugins/XspfPlaylistPlugin.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,13 +25,14 @@
#include "input/InputStream.hxx"
#include "tag/TagBuilder.hxx"
#include "util/Error.hxx"
+#include "util/StringView.hxx"
#include "lib/expat/ExpatParser.hxx"
#include "Log.hxx"
#include <string.h>
/**
- * This is the state object for the GLib XML parser.
+ * This is the state object for our XML parser.
*/
struct XspfParser {
/**
@@ -170,7 +171,8 @@ xspf_char_data(void *user_data, const XML_Char *s, int len)
case XspfParser::TRACK:
if (!parser->location.empty() &&
parser->tag_type != TAG_NUM_OF_ITEM_TYPES)
- parser->tag_builder.AddItem(parser->tag_type, s, len);
+ parser->tag_builder.AddItem(parser->tag_type,
+ StringView(s, len));
break;
diff --git a/src/playlist/plugins/XspfPlaylistPlugin.hxx b/src/playlist/plugins/XspfPlaylistPlugin.hxx
index 6b08a6be6..0e95a1445 100644
--- a/src/playlist/plugins/XspfPlaylistPlugin.hxx
+++ b/src/playlist/plugins/XspfPlaylistPlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/poison.h b/src/poison.h
index c112f6e19..96972cd2e 100644
--- a/src/poison.h
+++ b/src/poison.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/protocol/Ack.cxx b/src/protocol/Ack.cxx
index 56f0f0b5d..9e0c06614 100644
--- a/src/protocol/Ack.cxx
+++ b/src/protocol/Ack.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/protocol/Ack.hxx b/src/protocol/Ack.hxx
index e2c4dd9d1..c8457c5b4 100644
--- a/src/protocol/Ack.hxx
+++ b/src/protocol/Ack.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/protocol/ArgParser.cxx b/src/protocol/ArgParser.cxx
index e373827b4..31756f53e 100644
--- a/src/protocol/ArgParser.cxx
+++ b/src/protocol/ArgParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,61 +19,63 @@
#include "config.h"
#include "ArgParser.hxx"
-#include "Result.hxx"
#include "Chrono.hxx"
-
-#include <limits>
+#include "client/Response.hxx"
#include <stdlib.h>
bool
-check_uint32(Client &client, uint32_t *dst, const char *s)
+ParseCommandArg32(Response &r, uint32_t &value_r, const char *s)
{
char *test;
- *dst = strtoul(s, &test, 10);
+ value_r = strtoul(s, &test, 10);
if (test == s || *test != '\0') {
- command_error(client, ACK_ERROR_ARG,
- "Integer expected: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Integer expected: %s", s);
return false;
}
return true;
}
bool
-check_int(Client &client, int *value_r, const char *s)
+ParseCommandArg(Response &r, int &value_r, const char *s,
+ int min_value, int max_value)
{
char *test;
long value;
value = strtol(s, &test, 10);
if (test == s || *test != '\0') {
- command_error(client, ACK_ERROR_ARG,
- "Integer expected: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Integer expected: %s", s);
return false;
}
- if (value < std::numeric_limits<int>::min() ||
- value > std::numeric_limits<int>::max()) {
- command_error(client, ACK_ERROR_ARG,
- "Number too large: %s", s);
+ if (value < min_value || value > max_value) {
+ r.FormatError(ACK_ERROR_ARG, "Number too large: %s", s);
return false;
}
- *value_r = (int)value;
+ value_r = (int)value;
return true;
}
bool
-check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
- const char *s)
+ParseCommandArg(Response &r, int &value_r, const char *s)
+{
+ return ParseCommandArg(r, value_r, s,
+ std::numeric_limits<int>::min(),
+ std::numeric_limits<int>::max());
+}
+
+bool
+ParseCommandArg(Response &r, RangeArg &value_r, const char *s)
{
char *test, *test2;
long value;
value = strtol(s, &test, 10);
if (test == s || (*test != '\0' && *test != ':')) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Integer or range expected: %s", s);
return false;
}
@@ -81,29 +83,27 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
if (value == -1 && *test == 0) {
/* compatibility with older MPD versions: specifying
"-1" makes MPD display the whole list */
- *value_r1 = 0;
- *value_r2 = std::numeric_limits<int>::max();
+ value_r.start = 0;
+ value_r.end = std::numeric_limits<int>::max();
return true;
}
if (value < 0) {
- command_error(client, ACK_ERROR_ARG,
- "Number is negative: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Number is negative: %s", s);
return false;
}
if (unsigned(value) > std::numeric_limits<unsigned>::max()) {
- command_error(client, ACK_ERROR_ARG,
- "Number too large: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Number too large: %s", s);
return false;
}
- *value_r1 = (unsigned)value;
+ value_r.start = (unsigned)value;
if (*test == ':') {
value = strtol(++test, &test2, 10);
if (*test2 != '\0') {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Integer or range expected: %s", s);
return false;
}
@@ -112,87 +112,93 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
value = std::numeric_limits<int>::max();
if (value < 0) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Number is negative: %s", s);
return false;
}
if (unsigned(value) > std::numeric_limits<unsigned>::max()) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Number too large: %s", s);
return false;
}
- *value_r2 = (unsigned)value;
+ value_r.end = (unsigned)value;
} else {
- *value_r2 = (unsigned)value + 1;
+ value_r.end = (unsigned)value + 1;
}
return true;
}
bool
-check_unsigned(Client &client, unsigned *value_r, const char *s)
+ParseCommandArg(Response &r, unsigned &value_r, const char *s,
+ unsigned max_value)
{
unsigned long value;
char *endptr;
value = strtoul(s, &endptr, 10);
if (endptr == s || *endptr != 0) {
- command_error(client, ACK_ERROR_ARG,
- "Integer expected: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Integer expected: %s", s);
return false;
}
- if (value > std::numeric_limits<unsigned>::max()) {
- command_error(client, ACK_ERROR_ARG,
+ if (value > max_value) {
+ r.FormatError(ACK_ERROR_ARG,
"Number too large: %s", s);
return false;
}
- *value_r = (unsigned)value;
+ value_r = (unsigned)value;
return true;
}
bool
-check_bool(Client &client, bool *value_r, const char *s)
+ParseCommandArg(Response &r, unsigned &value_r, const char *s)
+{
+ return ParseCommandArg(r, value_r, s,
+ std::numeric_limits<unsigned>::max());
+}
+
+bool
+ParseCommandArg(Response &r, bool &value_r, const char *s)
{
long value;
char *endptr;
value = strtol(s, &endptr, 10);
if (endptr == s || *endptr != 0 || (value != 0 && value != 1)) {
- command_error(client, ACK_ERROR_ARG,
+ r.FormatError(ACK_ERROR_ARG,
"Boolean (0/1) expected: %s", s);
return false;
}
- *value_r = !!value;
+ value_r = !!value;
return true;
}
bool
-check_float(Client &client, float *value_r, const char *s)
+ParseCommandArg(Response &r, float &value_r, const char *s)
{
float value;
char *endptr;
value = strtof(s, &endptr);
if (endptr == s || *endptr != 0) {
- command_error(client, ACK_ERROR_ARG,
- "Float expected: %s", s);
+ r.FormatError(ACK_ERROR_ARG, "Float expected: %s", s);
return false;
}
- *value_r = value;
+ value_r = value;
return true;
}
bool
-ParseCommandArg(Client &client, SongTime &value_r, const char *s)
+ParseCommandArg(Response &r, SongTime &value_r, const char *s)
{
float value;
- bool success = check_float(client, &value, s) && value >= 0;
+ bool success = ParseCommandArg(r, value, s) && value >= 0;
if (success)
value_r = SongTime::FromS(value);
@@ -200,10 +206,10 @@ ParseCommandArg(Client &client, SongTime &value_r, const char *s)
}
bool
-ParseCommandArg(Client &client, SignedSongTime &value_r, const char *s)
+ParseCommandArg(Response &r, SignedSongTime &value_r, const char *s)
{
float value;
- bool success = check_float(client, &value, s);
+ bool success = ParseCommandArg(r, value, s);
if (success)
value_r = SignedSongTime::FromS(value);
diff --git a/src/protocol/ArgParser.hxx b/src/protocol/ArgParser.hxx
index 0f79e7ab2..f60dbdf50 100644
--- a/src/protocol/ArgParser.hxx
+++ b/src/protocol/ArgParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,35 +22,57 @@
#include "check.h"
+#include <limits>
+
#include <stdint.h>
-class Client;
+class Response;
class SongTime;
class SignedSongTime;
bool
-check_uint32(Client &client, uint32_t *dst, const char *s);
+ParseCommandArg32(Response &r, uint32_t &value_r, const char *s);
+
+bool
+ParseCommandArg(Response &r, int &value_r, const char *s,
+ int min_value, int max_value);
+
+bool
+ParseCommandArg(Response &r, int &value_r, const char *s);
+
+struct RangeArg {
+ unsigned start, end;
+
+ void SetAll() {
+ start = 0;
+ end = std::numeric_limits<unsigned>::max();
+ }
+
+ static constexpr RangeArg All() {
+ return { 0, std::numeric_limits<unsigned>::max() };
+ }
+};
bool
-check_int(Client &client, int *value_r, const char *s);
+ParseCommandArg(Response &r, RangeArg &value_r, const char *s);
bool
-check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
- const char *s);
+ParseCommandArg(Response &r, unsigned &value_r, const char *s,
+ unsigned max_value);
bool
-check_unsigned(Client &client, unsigned *value_r, const char *s);
+ParseCommandArg(Response &r, unsigned &value_r, const char *s);
bool
-check_bool(Client &client, bool *value_r, const char *s);
+ParseCommandArg(Response &r, bool &value_r, const char *s);
bool
-check_float(Client &client, float *value_r, const char *s);
+ParseCommandArg(Response &r, float &value_r, const char *s);
bool
-ParseCommandArg(Client &client, SongTime &value_r, const char *s);
+ParseCommandArg(Response &r, SongTime &value_r, const char *s);
bool
-ParseCommandArg(Client &client, SignedSongTime &value_r, const char *s);
+ParseCommandArg(Response &r, SignedSongTime &value_r, const char *s);
#endif
diff --git a/src/protocol/Result.cxx b/src/protocol/Result.cxx
index 3cc5fc33e..6a0da1665 100644
--- a/src/protocol/Result.cxx
+++ b/src/protocol/Result.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,36 +21,8 @@
#include "Result.hxx"
#include "client/Client.hxx"
-#include <assert.h>
-
-const char *current_command;
-int command_list_num;
-
void
command_success(Client &client)
{
client_puts(client, "OK\n");
}
-
-void
-command_error_v(Client &client, enum ack error,
- const char *fmt, va_list args)
-{
- assert(current_command != nullptr);
-
- client_printf(client, "ACK [%i@%i] {%s} ",
- (int)error, command_list_num, current_command);
- client_vprintf(client, fmt, args);
- client_puts(client, "\n");
-
- current_command = nullptr;
-}
-
-void
-command_error(Client &client, enum ack error, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- command_error_v(client, error, fmt, args);
- va_end(args);
-}
diff --git a/src/protocol/Result.hxx b/src/protocol/Result.hxx
index 0ac9d1e6b..d75bbe51b 100644
--- a/src/protocol/Result.hxx
+++ b/src/protocol/Result.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,25 +21,10 @@
#define MPD_PROTOCOL_RESULT_HXX
#include "check.h"
-#include "Compiler.h"
-#include "Ack.hxx"
-
-#include <stdarg.h>
class Client;
-extern const char *current_command;
-extern int command_list_num;
-
void
command_success(Client &client);
-void
-command_error_v(Client &client, enum ack error,
- const char *fmt, va_list args);
-
-gcc_printf(3,4)
-void
-command_error(Client &client, enum ack error, const char *fmt, ...);
-
#endif
diff --git a/src/queue/IdTable.hxx b/src/queue/IdTable.hxx
index 8e445243d..d1a0008fb 100644
--- a/src/queue/IdTable.hxx
+++ b/src/queue/IdTable.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue/Playlist.cxx b/src/queue/Playlist.cxx
index b2fd673b4..841684272 100644
--- a/src/queue/Playlist.cxx
+++ b/src/queue/Playlist.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "Playlist.hxx"
#include "PlaylistError.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "DetachedSong.hxx"
#include "Idle.hxx"
#include "Log.hxx"
@@ -44,45 +44,52 @@ playlist::TagModified(DetachedSong &&song)
idle_add(IDLE_PLAYLIST);
}
-/**
- * Queue a song, addressed by its order number.
- */
-static void
-playlist_queue_song_order(playlist &playlist, PlayerControl &pc,
- unsigned order)
+inline void
+playlist::QueueSongOrder(PlayerControl &pc, unsigned order)
+
{
- assert(playlist.queue.IsValidOrder(order));
+ assert(queue.IsValidOrder(order));
- playlist.queued = order;
+ queued = order;
- const DetachedSong &song = playlist.queue.GetOrder(order);
+ const DetachedSong &song = queue.GetOrder(order);
FormatDebug(playlist_domain, "queue song %i:\"%s\"",
- playlist.queued, song.GetURI());
+ queued, song.GetURI());
pc.EnqueueSong(new DetachedSong(song));
}
-/**
- * Called if the player thread has started playing the "queued" song.
- */
-static void
-playlist_song_started(playlist &playlist, PlayerControl &pc)
+void
+playlist::SongStarted()
+{
+ assert(current >= 0);
+
+ /* reset a song's "priority" when playback starts */
+ if (queue.SetPriority(queue.OrderToPosition(current), 0, -1, false))
+ OnModified();
+}
+
+inline void
+playlist::QueuedSongStarted(PlayerControl &pc)
{
assert(pc.next_song == nullptr);
- assert(playlist.queued >= -1);
+ assert(queued >= -1);
+ assert(current >= 0);
/* queued song has started: copy queued to current,
and notify the clients */
- int current = playlist.current;
- playlist.current = playlist.queued;
- playlist.queued = -1;
+ const int old_current = current;
+ current = queued;
+ queued = -1;
- if(playlist.queue.consume)
- playlist.DeleteOrder(pc, current);
+ if (queue.consume)
+ DeleteOrder(pc, old_current);
idle_add(IDLE_PLAYER);
+
+ SongStarted();
}
const DetachedSong *
@@ -139,7 +146,7 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const DetachedSong *prev)
if (next_order >= 0) {
if (next_song != prev)
- playlist_queue_song_order(*this, pc, next_order);
+ QueueSongOrder(pc, next_order);
else
queued = next_order;
}
@@ -157,10 +164,9 @@ playlist::PlayOrder(PlayerControl &pc, int order)
pc.Play(new DetachedSong(song));
current = order;
-}
-static void
-playlist_resume_playback(playlist &playlist, PlayerControl &pc);
+ SongStarted();
+}
void
playlist::SyncWithPlayer(PlayerControl &pc)
@@ -180,12 +186,12 @@ playlist::SyncWithPlayer(PlayerControl &pc)
should be restarted with the next song. That can
happen if the playlist isn't filling the queue fast
enough */
- playlist_resume_playback(*this, pc);
+ ResumePlayback(pc);
else {
/* check if the player thread has already started
playing the queued song */
if (pc_next_song == nullptr && queued != -1)
- playlist_song_started(*this, pc);
+ QueuedSongStarted(pc);
pc.Lock();
pc_next_song = pc.next_song;
@@ -198,31 +204,27 @@ playlist::SyncWithPlayer(PlayerControl &pc)
}
}
-/**
- * The player has stopped for some reason. Check the error, and
- * decide whether to re-start playback
- */
-static void
-playlist_resume_playback(playlist &playlist, PlayerControl &pc)
+inline void
+playlist::ResumePlayback(PlayerControl &pc)
{
- assert(playlist.playing);
+ assert(playing);
assert(pc.GetState() == PlayerState::STOP);
const auto error = pc.GetErrorType();
if (error == PlayerError::NONE)
- playlist.error_count = 0;
+ error_count = 0;
else
- ++playlist.error_count;
+ ++error_count;
- if ((playlist.stop_on_error && error != PlayerError::NONE) ||
+ if ((stop_on_error && error != PlayerError::NONE) ||
error == PlayerError::OUTPUT ||
- playlist.error_count >= playlist.queue.GetLength())
+ error_count >= queue.GetLength())
/* too many errors, or critical error: stop
playback */
- playlist.Stop(pc);
+ Stop(pc);
else
/* continue playback at the next song */
- playlist.PlayNext(pc);
+ PlayNext(pc);
}
void
diff --git a/src/queue/Playlist.hxx b/src/queue/Playlist.hxx
index ea19d9bba..a185a79c8 100644
--- a/src/queue/Playlist.hxx
+++ b/src/queue/Playlist.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -135,6 +135,17 @@ protected:
void OnModified();
/**
+ * Called when playback of a new song starts. Unlike
+ * QueuedSongStarted(), this also gets called when the user
+ * manually switches to another song. It may be used for
+ * playlist fixups.
+ *
+ * The song being started is specified by the #current
+ * attribute.
+ */
+ void SongStarted();
+
+ /**
* Updates the "queued song". Calculates the next song
* according to the current one (if MPD isn't playing, it
* takes the first song), and queues this song. Clears the
@@ -145,6 +156,24 @@ protected:
*/
void UpdateQueuedSong(PlayerControl &pc, const DetachedSong *prev);
+ /**
+ * Queue a song, addressed by its order number.
+ */
+ void QueueSongOrder(PlayerControl &pc, unsigned order);
+
+ /**
+ * Called when the player thread has started playing the
+ * "queued" song, i.e. it has switched from one song to the
+ * next automatically.
+ */
+ void QueuedSongStarted(PlayerControl &pc);
+
+ /**
+ * The player has stopped for some reason. Check the error,
+ * and decide whether to re-start playback.
+ */
+ void ResumePlayback(PlayerControl &pc);
+
public:
void BeginBulk();
void CommitBulk(PlayerControl &pc);
@@ -266,7 +295,7 @@ public:
* Seek within the current song. Fails if MPD is not currently
* playing.
*
- * @param time the time in seconds
+ * @param seek_time the time
* @param relative if true, then the specified time is relative to the
* current position
*/
diff --git a/src/queue/PlaylistControl.cxx b/src/queue/PlaylistControl.cxx
index f7e80dc46..f7f0a4225 100644
--- a/src/queue/PlaylistControl.cxx
+++ b/src/queue/PlaylistControl.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
#include "config.h"
#include "Playlist.hxx"
#include "PlaylistError.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "DetachedSong.hxx"
#include "Log.hxx"
diff --git a/src/queue/PlaylistEdit.cxx b/src/queue/PlaylistEdit.cxx
index 22a88dc46..0d15f6a04 100644
--- a/src/queue/PlaylistEdit.cxx
+++ b/src/queue/PlaylistEdit.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@
#include "config.h"
#include "Playlist.hxx"
#include "PlaylistError.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "util/UriUtil.hxx"
#include "util/Error.hxx"
#include "DetachedSong.hxx"
diff --git a/src/queue/PlaylistState.cxx b/src/queue/PlaylistState.cxx
index 6ea86166e..fa51b1519 100644
--- a/src/queue/PlaylistState.cxx
+++ b/src/queue/PlaylistState.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,10 +29,9 @@
#include "queue/QueueSave.hxx"
#include "fs/io/TextFile.hxx"
#include "fs/io/BufferedOutputStream.hxx"
-#include "PlayerControl.hxx"
+#include "player/Control.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
-#include "fs/Limits.hxx"
#include "util/CharUtil.hxx"
#include "util/StringUtil.hxx"
#include "Log.hxx"
@@ -57,8 +56,6 @@
#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
#define PLAYLIST_STATE_FILE_STATE_STOP "stop"
-#define PLAYLIST_BUFFER_SIZE 2*MPD_PATH_MAX
-
void
playlist_state_save(BufferedOutputStream &os, const struct playlist &playlist,
PlayerControl &pc)
@@ -195,7 +192,7 @@ playlist_state_restore(const char *line, TextFile &file,
current = 0;
if (state == PlayerState::PLAY &&
- config_get_bool(CONF_RESTORE_PAUSED, false))
+ config_get_bool(ConfigOption::RESTORE_PAUSED, false))
/* the user doesn't want MPD to auto-start
playback after startup; fall back to
"pause" */
diff --git a/src/queue/PlaylistState.hxx b/src/queue/PlaylistState.hxx
index 3211b1178..9af9ff1f9 100644
--- a/src/queue/PlaylistState.hxx
+++ b/src/queue/PlaylistState.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue/PlaylistTag.cxx b/src/queue/PlaylistTag.cxx
index 556e7f4e9..69b6abae8 100644
--- a/src/queue/PlaylistTag.cxx
+++ b/src/queue/PlaylistTag.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue/PlaylistUpdate.cxx b/src/queue/PlaylistUpdate.cxx
index 8876711ef..9fcd2f911 100644
--- a/src/queue/PlaylistUpdate.cxx
+++ b/src/queue/PlaylistUpdate.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue/Queue.cxx b/src/queue/Queue.cxx
index 99b545ab1..72837e3f4 100644
--- a/src/queue/Queue.cxx
+++ b/src/queue/Queue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -402,7 +402,8 @@ Queue::CountSamePriority(unsigned start_order, uint8_t priority) const
}
bool
-Queue::SetPriority(unsigned position, uint8_t priority, int after_order)
+Queue::SetPriority(unsigned position, uint8_t priority, int after_order,
+ bool reorder)
{
assert(position < length);
@@ -414,7 +415,7 @@ Queue::SetPriority(unsigned position, uint8_t priority, int after_order)
item->version = version;
item->priority = priority;
- if (!random)
+ if (!random || !reorder)
/* don't reorder if not in random mode */
return true;
diff --git a/src/queue/Queue.hxx b/src/queue/Queue.hxx
index 016619e65..770357e3a 100644
--- a/src/queue/Queue.hxx
+++ b/src/queue/Queue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -343,7 +343,8 @@ struct Queue {
*/
void ShuffleRange(unsigned start, unsigned end);
- bool SetPriority(unsigned position, uint8_t priority, int after_order);
+ bool SetPriority(unsigned position, uint8_t priority, int after_order,
+ bool reorder=true);
bool SetPriorityRange(unsigned start_position, unsigned end_position,
uint8_t priority, int after_order);
diff --git a/src/queue/QueuePrint.cxx b/src/queue/QueuePrint.cxx
index 831ecafb9..5ae1a3036 100644
--- a/src/queue/QueuePrint.cxx
+++ b/src/queue/QueuePrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@
#include "Queue.hxx"
#include "SongFilter.hxx"
#include "SongPrint.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
/**
* Send detailed information about a range of songs in the queue to a
@@ -33,70 +33,70 @@
* @param end the index of the last song (excluding)
*/
static void
-queue_print_song_info(Client &client, const Queue &queue,
+queue_print_song_info(Response &r, Partition &partition, const Queue &queue,
unsigned position)
{
- song_print_info(client, queue.Get(position));
- client_printf(client, "Pos: %u\nId: %u\n",
- position, queue.PositionToId(position));
+ song_print_info(r, partition, queue.Get(position));
+ r.Format("Pos: %u\nId: %u\n",
+ position, queue.PositionToId(position));
uint8_t priority = queue.GetPriorityAtPosition(position);
if (priority != 0)
- client_printf(client, "Prio: %u\n", priority);
+ r.Format("Prio: %u\n", priority);
}
void
-queue_print_info(Client &client, const Queue &queue,
+queue_print_info(Response &r, Partition &partition, const Queue &queue,
unsigned start, unsigned end)
{
assert(start <= end);
assert(end <= queue.GetLength());
for (unsigned i = start; i < end; ++i)
- queue_print_song_info(client, queue, i);
+ queue_print_song_info(r, partition, queue, i);
}
void
-queue_print_uris(Client &client, const Queue &queue,
+queue_print_uris(Response &r, Partition &partition, const Queue &queue,
unsigned start, unsigned end)
{
assert(start <= end);
assert(end <= queue.GetLength());
for (unsigned i = start; i < end; ++i) {
- client_printf(client, "%i:", i);
- song_print_uri(client, queue.Get(i));
+ r.Format("%i:", i);
+ song_print_uri(r, partition, queue.Get(i));
}
}
void
-queue_print_changes_info(Client &client, const Queue &queue,
+queue_print_changes_info(Response &r, Partition &partition, const Queue &queue,
uint32_t version)
{
for (unsigned i = 0; i < queue.GetLength(); i++) {
if (queue.IsNewerAtPosition(i, version))
- queue_print_song_info(client, queue, i);
+ queue_print_song_info(r, partition, queue, i);
}
}
void
-queue_print_changes_position(Client &client, const Queue &queue,
+queue_print_changes_position(Response &r, const Queue &queue,
uint32_t version)
{
for (unsigned i = 0; i < queue.GetLength(); i++)
if (queue.IsNewerAtPosition(i, version))
- client_printf(client, "cpos: %i\nId: %i\n",
- i, queue.PositionToId(i));
+ r.Format("cpos: %i\nId: %i\n",
+ i, queue.PositionToId(i));
}
void
-queue_find(Client &client, const Queue &queue,
+queue_find(Response &r, Partition &partition, const Queue &queue,
const SongFilter &filter)
{
for (unsigned i = 0; i < queue.GetLength(); i++) {
const DetachedSong &song = queue.Get(i);
if (filter.Match(song))
- queue_print_song_info(client, queue, i);
+ queue_print_song_info(r, partition, queue, i);
}
}
diff --git a/src/queue/QueuePrint.hxx b/src/queue/QueuePrint.hxx
index 1aa876219..88d28e8ca 100644
--- a/src/queue/QueuePrint.hxx
+++ b/src/queue/QueuePrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,27 +28,28 @@
#include <stdint.h>
struct Queue;
+struct Partition;
class SongFilter;
-class Client;
+class Response;
void
-queue_print_info(Client &client, const Queue &queue,
+queue_print_info(Response &r, Partition &partition, const Queue &queue,
unsigned start, unsigned end);
void
-queue_print_uris(Client &client, const Queue &queue,
+queue_print_uris(Response &r, Partition &partition, const Queue &queue,
unsigned start, unsigned end);
void
-queue_print_changes_info(Client &client, const Queue &queue,
+queue_print_changes_info(Response &r, Partition &partition, const Queue &queue,
uint32_t version);
void
-queue_print_changes_position(Client &client, const Queue &queue,
+queue_print_changes_position(Response &r, const Queue &queue,
uint32_t version);
void
-queue_find(Client &client, const Queue &queue,
+queue_find(Response &response, Partition &partition, const Queue &queue,
const SongFilter &filter);
#endif
diff --git a/src/queue/QueueSave.cxx b/src/queue/QueueSave.cxx
index bc2702572..f5c49549e 100644
--- a/src/queue/QueueSave.cxx
+++ b/src/queue/QueueSave.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/queue/QueueSave.hxx b/src/queue/QueueSave.hxx
index 3fb4dc1a6..3eeacb418 100644
--- a/src/queue/QueueSave.hxx
+++ b/src/queue/QueueSave.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/sticker/Match.hxx b/src/sticker/Match.hxx
new file mode 100644
index 000000000..4ac2ac383
--- /dev/null
+++ b/src/sticker/Match.hxx
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_STICKER_MATCH_HXX
+#define MPD_STICKER_MATCH_HXX
+
+enum class StickerOperator {
+ /**
+ * Matches if a sticker with the specified name exists. The
+ * "value" parameter is ignored (must be nullptr).
+ */
+ EXISTS,
+
+ /**
+ * Matches if a sticker with the specified name and value
+ * exists.
+ */
+ EQUALS,
+
+ /**
+ * Matches if a sticker with the specified name exists with a
+ * value smaller than the specified one.
+ */
+ LESS_THAN,
+
+ /**
+ * Matches if a sticker with the specified name exists with a
+ * value bigger than the specified one.
+ */
+ GREATER_THAN,
+};
+
+#endif
diff --git a/src/sticker/SongSticker.cxx b/src/sticker/SongSticker.cxx
index b6f46f167..b4ca6a398 100644
--- a/src/sticker/SongSticker.cxx
+++ b/src/sticker/SongSticker.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,46 +23,48 @@
#include "db/LightSong.hxx"
#include "db/Interface.hxx"
#include "util/Error.hxx"
-
-#include <glib.h>
+#include "util/Alloc.hxx"
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
std::string
-sticker_song_get_value(const LightSong &song, const char *name)
+sticker_song_get_value(const LightSong &song, const char *name, Error &error)
{
const auto uri = song.GetURI();
- return sticker_load_value("song", uri.c_str(), name);
+ return sticker_load_value("song", uri.c_str(), name, error);
}
bool
sticker_song_set_value(const LightSong &song,
- const char *name, const char *value)
+ const char *name, const char *value,
+ Error &error)
{
const auto uri = song.GetURI();
- return sticker_store_value("song", uri.c_str(), name, value);
+ return sticker_store_value("song", uri.c_str(), name, value, error);
}
bool
-sticker_song_delete(const LightSong &song)
+sticker_song_delete(const LightSong &song, Error &error)
{
const auto uri = song.GetURI();
- return sticker_delete("song", uri.c_str());
+ return sticker_delete("song", uri.c_str(), error);
}
bool
-sticker_song_delete_value(const LightSong &song, const char *name)
+sticker_song_delete_value(const LightSong &song, const char *name,
+ Error &error)
{
const auto uri = song.GetURI();
- return sticker_delete_value("song", uri.c_str(), name);
+ return sticker_delete_value("song", uri.c_str(), name, error);
}
-struct sticker *
-sticker_song_get(const LightSong &song)
+Sticker *
+sticker_song_get(const LightSong &song, Error &error)
{
const auto uri = song.GetURI();
- return sticker_load("song", uri.c_str());
+ return sticker_load("song", uri.c_str(), error);
}
struct sticker_song_find_data {
@@ -95,9 +97,11 @@ sticker_song_find_cb(const char *uri, const char *value, void *user_data)
bool
sticker_song_find(const Database &db, const char *base_uri, const char *name,
+ StickerOperator op, const char *value,
void (*func)(const LightSong &song, const char *value,
void *user_data),
- void *user_data)
+ void *user_data,
+ Error &error)
{
struct sticker_song_find_data data;
data.db = &db;
@@ -109,16 +113,17 @@ sticker_song_find(const Database &db, const char *base_uri, const char *name,
if (*data.base_uri != 0)
/* append slash to base_uri */
data.base_uri = allocated =
- g_strconcat(data.base_uri, "/", nullptr);
+ xstrcatdup(data.base_uri, "/");
else
/* searching in root directory - no trailing slash */
allocated = nullptr;
data.base_uri_length = strlen(data.base_uri);
- bool success = sticker_find("song", data.base_uri, name,
- sticker_song_find_cb, &data);
- g_free(allocated);
+ bool success = sticker_find("song", data.base_uri, name, op, value,
+ sticker_song_find_cb, &data,
+ error);
+ free(allocated);
return success;
}
diff --git a/src/sticker/SongSticker.hxx b/src/sticker/SongSticker.hxx
index 5956cd6f9..3eaa1d776 100644
--- a/src/sticker/SongSticker.hxx
+++ b/src/sticker/SongSticker.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,13 +20,15 @@
#ifndef MPD_SONG_STICKER_HXX
#define MPD_SONG_STICKER_HXX
+#include "Match.hxx"
#include "Compiler.h"
#include <string>
struct LightSong;
-struct sticker;
+struct Sticker;
class Database;
+class Error;
/**
* Returns one value from a song's sticker record. The caller must
@@ -34,7 +36,7 @@ class Database;
*/
gcc_pure
std::string
-sticker_song_get_value(const LightSong &song, const char *name);
+sticker_song_get_value(const LightSong &song, const char *name, Error &error);
/**
* Sets a sticker value in the specified song. Overwrites existing
@@ -42,20 +44,22 @@ sticker_song_get_value(const LightSong &song, const char *name);
*/
bool
sticker_song_set_value(const LightSong &song,
- const char *name, const char *value);
+ const char *name, const char *value,
+ Error &error);
/**
* Deletes a sticker from the database. All values are deleted.
*/
bool
-sticker_song_delete(const LightSong &song);
+sticker_song_delete(const LightSong &song, Error &error);
/**
* Deletes a sticker value. Does nothing if the sticker did not
* exist.
*/
bool
-sticker_song_delete_value(const LightSong &song, const char *name);
+sticker_song_delete_value(const LightSong &song, const char *name,
+ Error &error);
/**
* Loads the sticker for the specified song.
@@ -63,8 +67,8 @@ sticker_song_delete_value(const LightSong &song, const char *name);
* @param song the song object
* @return a sticker object, or NULL on error or if there is no sticker
*/
-sticker *
-sticker_song_get(const LightSong &song);
+Sticker *
+sticker_song_get(const LightSong &song, Error &error);
/**
* Finds stickers with the specified name below the specified
@@ -79,8 +83,10 @@ sticker_song_get(const LightSong &song);
*/
bool
sticker_song_find(const Database &db, const char *base_uri, const char *name,
+ StickerOperator op, const char *value,
void (*func)(const LightSong &song, const char *value,
void *user_data),
- void *user_data);
+ void *user_data,
+ Error &error);
#endif
diff --git a/src/sticker/StickerDatabase.cxx b/src/sticker/StickerDatabase.cxx
index 93eaa900d..02eed362e 100644
--- a/src/sticker/StickerDatabase.cxx
+++ b/src/sticker/StickerDatabase.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,24 +19,19 @@
#include "config.h"
#include "StickerDatabase.hxx"
+#include "lib/sqlite/Domain.hxx"
+#include "lib/sqlite/Util.hxx"
#include "fs/Path.hxx"
#include "Idle.hxx"
#include "util/Error.hxx"
-#include "util/Domain.hxx"
#include "util/Macros.hxx"
-#include "Log.hxx"
#include <string>
#include <map>
-#include <sqlite3.h>
#include <assert.h>
-#if SQLITE_VERSION_NUMBER < 3003009
-#define sqlite3_prepare_v2 sqlite3_prepare
-#endif
-
-struct sticker {
+struct Sticker {
std::map<std::string, std::string> table;
};
@@ -48,6 +43,9 @@ enum sticker_sql {
STICKER_SQL_DELETE,
STICKER_SQL_DELETE_VALUE,
STICKER_SQL_FIND,
+ STICKER_SQL_FIND_VALUE,
+ STICKER_SQL_FIND_LT,
+ STICKER_SQL_FIND_GT,
};
static const char *const sticker_sql[] = {
@@ -65,6 +63,15 @@ static const char *const sticker_sql[] = {
"DELETE FROM sticker WHERE type=? AND uri=? AND name=?",
//[STICKER_SQL_FIND] =
"SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=?",
+
+ //[STICKER_SQL_FIND_VALUE] =
+ "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND value=?",
+
+ //[STICKER_SQL_FIND_LT] =
+ "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND value<?",
+
+ //[STICKER_SQL_FIND_GT] =
+ "SELECT uri,value FROM sticker WHERE type=? AND uri LIKE (? || '%') AND name=? AND value>?",
};
static const char sticker_sql_create[] =
@@ -81,23 +88,13 @@ static const char sticker_sql_create[] =
static sqlite3 *sticker_db;
static sqlite3_stmt *sticker_stmt[ARRAY_SIZE(sticker_sql)];
-static constexpr Domain sticker_domain("sticker");
-
-static void
-LogError(sqlite3 *db, const char *msg)
-{
- FormatError(sticker_domain, "%s: %s", msg, sqlite3_errmsg(db));
-}
-
static sqlite3_stmt *
sticker_prepare(const char *sql, Error &error)
{
- int ret;
sqlite3_stmt *stmt;
-
- ret = sqlite3_prepare_v2(sticker_db, sql, -1, &stmt, nullptr);
+ int ret = sqlite3_prepare_v2(sticker_db, sql, -1, &stmt, nullptr);
if (ret != SQLITE_OK) {
- error.Format(sticker_domain, ret,
+ error.Format(sqlite_domain, ret,
"sqlite3_prepare_v2() failed: %s",
sqlite3_errmsg(sticker_db));
return nullptr;
@@ -118,9 +115,9 @@ sticker_global_init(Path path, Error &error)
ret = sqlite3_open(path.c_str(), &sticker_db);
if (ret != SQLITE_OK) {
const std::string utf8 = path.ToUTF8();
- error.Format(sticker_domain, ret,
- "Failed to open sqlite database '%s': %s",
- utf8.c_str(), sqlite3_errmsg(sticker_db));
+ error.Format(sqlite_domain, ret,
+ "Failed to open sqlite database '%s': %s",
+ utf8.c_str(), sqlite3_errmsg(sticker_db));
return false;
}
@@ -129,7 +126,7 @@ sticker_global_init(Path path, Error &error)
ret = sqlite3_exec(sticker_db, sticker_sql_create,
nullptr, nullptr, nullptr);
if (ret != SQLITE_OK) {
- error.Format(sticker_domain, ret,
+ error.Format(sqlite_domain, ret,
"Failed to create sticker table: %s",
sqlite3_errmsg(sticker_db));
return false;
@@ -149,7 +146,7 @@ sticker_global_init(Path path, Error &error)
}
void
-sticker_global_finish(void)
+sticker_global_finish()
{
if (sticker_db == nullptr)
/* not configured */
@@ -165,16 +162,16 @@ sticker_global_finish(void)
}
bool
-sticker_enabled(void)
+sticker_enabled()
{
return sticker_db != nullptr;
}
std::string
-sticker_load_value(const char *type, const char *uri, const char *name)
+sticker_load_value(const char *type, const char *uri, const char *name,
+ Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_GET];
- int ret;
assert(sticker_enabled());
assert(type != nullptr);
@@ -184,40 +181,12 @@ sticker_load_value(const char *type, const char *uri, const char *name)
if (*name == 0)
return std::string();
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return std::string();
- }
-
- ret = sqlite3_bind_text(stmt, 2, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return std::string();
- }
-
- ret = sqlite3_bind_text(stmt, 3, name, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, type, uri, name))
return std::string();
- }
-
- do {
- ret = sqlite3_step(stmt);
- } while (ret == SQLITE_BUSY);
std::string value;
- if (ret == SQLITE_ROW) {
- /* record found */
+ if (ExecuteRow(stmt, error))
value = (const char*)sqlite3_column_text(stmt, 0);
- } else if (ret == SQLITE_DONE) {
- /* no record found */
- } else {
- /* error */
- LogError(sticker_db, "sqlite3_step() failed");
- }
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
@@ -227,63 +196,36 @@ sticker_load_value(const char *type, const char *uri, const char *name)
static bool
sticker_list_values(std::map<std::string, std::string> &table,
- const char *type, const char *uri)
+ const char *type, const char *uri,
+ Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_LIST];
- int ret;
assert(type != nullptr);
assert(uri != nullptr);
assert(sticker_enabled());
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, type, uri))
return false;
- }
-
- ret = sqlite3_bind_text(stmt, 2, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- do {
- ret = sqlite3_step(stmt);
- switch (ret) {
- const char *name, *value;
-
- case SQLITE_ROW:
- name = (const char*)sqlite3_column_text(stmt, 0);
- value = (const char*)sqlite3_column_text(stmt, 1);
+ const bool success = ExecuteForEach(stmt, error, [stmt, &table](){
+ const char *name = (const char *)sqlite3_column_text(stmt, 0);
+ const char *value = (const char *)sqlite3_column_text(stmt, 1);
table.insert(std::make_pair(name, value));
- break;
- case SQLITE_DONE:
- break;
- case SQLITE_BUSY:
- /* no op */
- break;
- default:
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
- } while (ret != SQLITE_DONE);
+ });
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
- return true;
+ return success;
}
static bool
sticker_update_value(const char *type, const char *uri,
- const char *name, const char *value)
+ const char *name, const char *value,
+ Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_UPDATE];
- int ret;
assert(type != nullptr);
assert(uri != nullptr);
@@ -293,56 +235,25 @@ sticker_update_value(const char *type, const char *uri,
assert(sticker_enabled());
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, value, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 2, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, value, type, uri, name))
return false;
- }
- ret = sqlite3_bind_text(stmt, 3, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 4, name, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- do {
- ret = sqlite3_step(stmt);
- } while (ret == SQLITE_BUSY);
-
- if (ret != SQLITE_DONE) {
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
-
- ret = sqlite3_changes(sticker_db);
+ bool modified = ExecuteModified(stmt, error);
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
- idle_add(IDLE_STICKER);
- return ret > 0;
+ if (modified)
+ idle_add(IDLE_STICKER);
+ return modified;
}
static bool
sticker_insert_value(const char *type, const char *uri,
- const char *name, const char *value)
+ const char *name, const char *value,
+ Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_INSERT];
- int ret;
assert(type != nullptr);
assert(uri != nullptr);
@@ -352,52 +263,23 @@ sticker_insert_value(const char *type, const char *uri,
assert(sticker_enabled());
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 2, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 3, name, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 4, value, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, type, uri, name, value))
return false;
- }
- do {
- ret = sqlite3_step(stmt);
- } while (ret == SQLITE_BUSY);
-
- if (ret != SQLITE_DONE) {
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
+ bool success = ExecuteCommand(stmt, error);
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
-
- idle_add(IDLE_STICKER);
- return true;
+ if (success)
+ idle_add(IDLE_STICKER);
+ return success;
}
bool
sticker_store_value(const char *type, const char *uri,
- const char *name, const char *value)
+ const char *name, const char *value,
+ Error &error)
{
assert(sticker_enabled());
assert(type != nullptr);
@@ -408,106 +290,63 @@ sticker_store_value(const char *type, const char *uri,
if (*name == 0)
return false;
- return sticker_update_value(type, uri, name, value) ||
- sticker_insert_value(type, uri, name, value);
+ return sticker_update_value(type, uri, name, value, error) ||
+ sticker_insert_value(type, uri, name, value, error);
}
bool
-sticker_delete(const char *type, const char *uri)
+sticker_delete(const char *type, const char *uri, Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE];
- int ret;
assert(sticker_enabled());
assert(type != nullptr);
assert(uri != nullptr);
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 2, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, type, uri))
return false;
- }
- do {
- ret = sqlite3_step(stmt);
- } while (ret == SQLITE_BUSY);
-
- if (ret != SQLITE_DONE) {
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
+ bool modified = ExecuteModified(stmt, error);
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
- idle_add(IDLE_STICKER);
- return true;
+ if (modified)
+ idle_add(IDLE_STICKER);
+ return modified;
}
bool
-sticker_delete_value(const char *type, const char *uri, const char *name)
+sticker_delete_value(const char *type, const char *uri, const char *name,
+ Error &error)
{
sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_DELETE_VALUE];
- int ret;
assert(sticker_enabled());
assert(type != nullptr);
assert(uri != nullptr);
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
-
- ret = sqlite3_bind_text(stmt, 2, uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ if (!BindAll(error, stmt, type, uri, name))
return false;
- }
-
- ret = sqlite3_bind_text(stmt, 3, name, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
- do {
- ret = sqlite3_step(stmt);
- } while (ret == SQLITE_BUSY);
-
- if (ret != SQLITE_DONE) {
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
-
- ret = sqlite3_changes(sticker_db);
+ bool modified = ExecuteModified(stmt, error);
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
- idle_add(IDLE_STICKER);
- return ret > 0;
+ if (modified)
+ idle_add(IDLE_STICKER);
+ return modified;
}
void
-sticker_free(struct sticker *sticker)
+sticker_free(Sticker *sticker)
{
delete sticker;
}
const char *
-sticker_get_value(const struct sticker &sticker, const char *name)
+sticker_get_value(const Sticker &sticker, const char *name)
{
auto i = sticker.table.find(name);
if (i == sticker.table.end())
@@ -517,7 +356,7 @@ sticker_get_value(const struct sticker &sticker, const char *name)
}
void
-sticker_foreach(const sticker &sticker,
+sticker_foreach(const Sticker &sticker,
void (*func)(const char *name, const char *value,
void *user_data),
void *user_data)
@@ -526,79 +365,82 @@ sticker_foreach(const sticker &sticker,
func(i.first.c_str(), i.second.c_str(), user_data);
}
-struct sticker *
-sticker_load(const char *type, const char *uri)
+Sticker *
+sticker_load(const char *type, const char *uri, Error &error)
{
- sticker s;
+ Sticker s;
- if (!sticker_list_values(s.table, type, uri))
+ if (!sticker_list_values(s.table, type, uri, error))
return nullptr;
if (s.table.empty())
/* don't return empty sticker objects */
return nullptr;
- return new sticker(std::move(s));
+ return new Sticker(std::move(s));
}
-bool
-sticker_find(const char *type, const char *base_uri, const char *name,
- void (*func)(const char *uri, const char *value,
- void *user_data),
- void *user_data)
+static sqlite3_stmt *
+BindFind(const char *type, const char *base_uri, const char *name,
+ StickerOperator op, const char *value,
+ Error &error)
{
- sqlite3_stmt *const stmt = sticker_stmt[STICKER_SQL_FIND];
- int ret;
-
assert(type != nullptr);
assert(name != nullptr);
- assert(func != nullptr);
- assert(sticker_enabled());
-
- sqlite3_reset(stmt);
-
- ret = sqlite3_bind_text(stmt, 1, type, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
- }
if (base_uri == nullptr)
base_uri = "";
- ret = sqlite3_bind_text(stmt, 2, base_uri, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
- return false;
+ switch (op) {
+ case StickerOperator::EXISTS:
+ return BindAllOrNull(error, sticker_stmt[STICKER_SQL_FIND],
+ type, base_uri, name);
+
+ case StickerOperator::EQUALS:
+ return BindAllOrNull(error,
+ sticker_stmt[STICKER_SQL_FIND_VALUE],
+ type, base_uri, name, value);
+
+ case StickerOperator::LESS_THAN:
+ return BindAllOrNull(error,
+ sticker_stmt[STICKER_SQL_FIND_LT],
+ type, base_uri, name, value);
+
+ case StickerOperator::GREATER_THAN:
+ return BindAllOrNull(error,
+ sticker_stmt[STICKER_SQL_FIND_GT],
+ type, base_uri, name, value);
}
- ret = sqlite3_bind_text(stmt, 3, name, -1, nullptr);
- if (ret != SQLITE_OK) {
- LogError(sticker_db, "sqlite3_bind_text() failed");
+ assert(false);
+ gcc_unreachable();
+}
+
+bool
+sticker_find(const char *type, const char *base_uri, const char *name,
+ StickerOperator op, const char *value,
+ void (*func)(const char *uri, const char *value,
+ void *user_data),
+ void *user_data,
+ Error &error)
+{
+ assert(func != nullptr);
+ assert(sticker_enabled());
+
+ sqlite3_stmt *const stmt = BindFind(type, base_uri, name, op, value,
+ error);
+ if (stmt == nullptr)
return false;
- }
- do {
- ret = sqlite3_step(stmt);
- switch (ret) {
- case SQLITE_ROW:
+ const bool success = ExecuteForEach(stmt, error,
+ [stmt, func, user_data](){
func((const char*)sqlite3_column_text(stmt, 0),
(const char*)sqlite3_column_text(stmt, 1),
user_data);
- break;
- case SQLITE_DONE:
- break;
- case SQLITE_BUSY:
- /* no op */
- break;
- default:
- LogError(sticker_db, "sqlite3_step() failed");
- return false;
- }
- } while (ret != SQLITE_DONE);
+ });
sqlite3_reset(stmt);
sqlite3_clear_bindings(stmt);
- return true;
+ return success;
}
diff --git a/src/sticker/StickerDatabase.hxx b/src/sticker/StickerDatabase.hxx
index 8993489c4..d9a5ecf11 100644
--- a/src/sticker/StickerDatabase.hxx
+++ b/src/sticker/StickerDatabase.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -42,13 +42,14 @@
#ifndef MPD_STICKER_DATABASE_HXX
#define MPD_STICKER_DATABASE_HXX
+#include "Match.hxx"
#include "Compiler.h"
#include <string>
class Error;
class Path;
-struct sticker;
+struct Sticker;
/**
* Opens the sticker database.
@@ -62,21 +63,22 @@ sticker_global_init(Path path, Error &error);
* Close the sticker database.
*/
void
-sticker_global_finish(void);
+sticker_global_finish();
/**
* Returns true if the sticker database is configured and available.
*/
gcc_const
bool
-sticker_enabled(void);
+sticker_enabled();
/**
* Returns one value from an object's sticker record. Returns an
* empty string if the value doesn't exist.
*/
std::string
-sticker_load_value(const char *type, const char *uri, const char *name);
+sticker_load_value(const char *type, const char *uri, const char *name,
+ Error &error);
/**
* Sets a sticker value in the specified object. Overwrites existing
@@ -84,21 +86,24 @@ sticker_load_value(const char *type, const char *uri, const char *name);
*/
bool
sticker_store_value(const char *type, const char *uri,
- const char *name, const char *value);
+ const char *name, const char *value,
+ Error &error);
/**
* Deletes a sticker from the database. All sticker values of the
* specified object are deleted.
*/
bool
-sticker_delete(const char *type, const char *uri);
+sticker_delete(const char *type, const char *uri,
+ Error &error);
/**
* Deletes a sticker value. Fails if no sticker with this name
* exists.
*/
bool
-sticker_delete_value(const char *type, const char *uri, const char *name);
+sticker_delete_value(const char *type, const char *uri, const char *name,
+ Error &error);
/**
* Frees resources held by the sticker object.
@@ -106,7 +111,7 @@ sticker_delete_value(const char *type, const char *uri, const char *name);
* @param sticker the sticker object to be freed
*/
void
-sticker_free(sticker *sticker);
+sticker_free(Sticker *sticker);
/**
* Determines a single value in a sticker.
@@ -117,7 +122,7 @@ sticker_free(sticker *sticker);
*/
gcc_pure
const char *
-sticker_get_value(const sticker &sticker, const char *name);
+sticker_get_value(const Sticker &sticker, const char *name);
/**
* Iterates over all sticker items in a sticker.
@@ -127,7 +132,7 @@ sticker_get_value(const sticker &sticker, const char *name);
* @param user_data an opaque pointer for the callback function
*/
void
-sticker_foreach(const sticker &sticker,
+sticker_foreach(const Sticker &sticker,
void (*func)(const char *name, const char *value,
void *user_data),
void *user_data);
@@ -139,8 +144,9 @@ sticker_foreach(const sticker &sticker,
* @param uri the URI of the resource, e.g. the song path
* @return a sticker object, or nullptr on error or if there is no sticker
*/
-sticker *
-sticker_load(const char *type, const char *uri);
+Sticker *
+sticker_load(const char *type, const char *uri,
+ Error &error);
/**
* Finds stickers with the specified name below the specified URI.
@@ -149,13 +155,17 @@ sticker_load(const char *type, const char *uri);
* @param base_uri the URI prefix of the resources, or nullptr if all
* resources should be searched
* @param name the name of the sticker
+ * @param op the comparison operator
+ * @param value the operand
* @return true on success (even if no sticker was found), false on
* failure
*/
bool
sticker_find(const char *type, const char *base_uri, const char *name,
+ StickerOperator op, const char *value,
void (*func)(const char *uri, const char *value,
void *user_data),
- void *user_data);
+ void *user_data,
+ Error &error);
#endif
diff --git a/src/sticker/StickerPrint.cxx b/src/sticker/StickerPrint.cxx
index a952ff203..f0043ebc8 100644
--- a/src/sticker/StickerPrint.cxx
+++ b/src/sticker/StickerPrint.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,25 +20,25 @@
#include "config.h"
#include "StickerPrint.hxx"
#include "StickerDatabase.hxx"
-#include "client/Client.hxx"
+#include "client/Response.hxx"
void
-sticker_print_value(Client &client,
+sticker_print_value(Response &r,
const char *name, const char *value)
{
- client_printf(client, "sticker: %s=%s\n", name, value);
+ r.Format("sticker: %s=%s\n", name, value);
}
static void
print_sticker_cb(const char *name, const char *value, void *data)
{
- Client &client = *(Client *)data;
+ auto &r = *(Response *)data;
- sticker_print_value(client, name, value);
+ sticker_print_value(r, name, value);
}
void
-sticker_print(Client &client, const sticker &sticker)
+sticker_print(Response &r, const Sticker &sticker)
{
- sticker_foreach(sticker, print_sticker_cb, &client);
+ sticker_foreach(sticker, print_sticker_cb, &r);
}
diff --git a/src/sticker/StickerPrint.hxx b/src/sticker/StickerPrint.hxx
index 39f3dc09e..e431245e4 100644
--- a/src/sticker/StickerPrint.hxx
+++ b/src/sticker/StickerPrint.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,19 +20,19 @@
#ifndef MPD_STICKER_PRINT_HXX
#define MPD_STICKER_PRINT_HXX
-struct sticker;
-class Client;
+struct Sticker;
+class Response;
/**
* Sends one sticker value to the client.
*/
void
-sticker_print_value(Client &client, const char *name, const char *value);
+sticker_print_value(Response &r, const char *name, const char *value);
/**
* Sends all sticker values to the client.
*/
void
-sticker_print(Client &client, const sticker &sticker);
+sticker_print(Response &r, const Sticker &sticker);
#endif
diff --git a/src/storage/CompositeStorage.cxx b/src/storage/CompositeStorage.cxx
index 89a2fc756..10a478c0d 100644
--- a/src/storage/CompositeStorage.cxx
+++ b/src/storage/CompositeStorage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -56,7 +56,7 @@ public:
/* virtual methods from class StorageDirectoryReader */
const char *Read() override;
- bool GetInfo(bool follow, FileInfo &info, Error &error) override;
+ bool GetInfo(bool follow, StorageFileInfo &info, Error &error) override;
};
const char *
@@ -81,7 +81,7 @@ CompositeDirectoryReader::Read()
}
bool
-CompositeDirectoryReader::GetInfo(bool follow, FileInfo &info,
+CompositeDirectoryReader::GetInfo(bool follow, StorageFileInfo &info,
Error &error)
{
if (other != nullptr)
@@ -89,7 +89,7 @@ CompositeDirectoryReader::GetInfo(bool follow, FileInfo &info,
assert(current != names.end());
- info.type = FileInfo::Type::DIRECTORY;
+ info.type = StorageFileInfo::Type::DIRECTORY;
info.mtime = 0;
info.device = 0;
info.inode = 0;
@@ -137,7 +137,7 @@ CompositeStorage::Directory::Make(const char *uri)
Directory *directory = this;
while (*uri != 0) {
const std::string name = NextSegment(uri);
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
auto i = directory->children.emplace(std::move(name),
Directory());
#else
@@ -275,7 +275,7 @@ CompositeStorage::FindStorage(const char *uri, Error &error) const
}
bool
-CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
+CompositeStorage::GetInfo(const char *uri, bool follow, StorageFileInfo &info,
Error &error)
{
const ScopeLock protect(mutex);
@@ -288,7 +288,7 @@ CompositeStorage::GetInfo(const char *uri, bool follow, FileInfo &info,
const Directory *directory = f.directory->Find(f.uri);
if (directory != nullptr) {
error.Clear();
- info.type = FileInfo::Type::DIRECTORY;
+ info.type = StorageFileInfo::Type::DIRECTORY;
info.mtime = 0;
info.device = 0;
info.inode = 0;
diff --git a/src/storage/CompositeStorage.hxx b/src/storage/CompositeStorage.hxx
index c3695c79d..08717edef 100644
--- a/src/storage/CompositeStorage.hxx
+++ b/src/storage/CompositeStorage.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -122,7 +122,7 @@ public:
bool Unmount(const char *uri);
/* virtual methods from class Storage */
- bool GetInfo(const char *uri, bool follow, FileInfo &info,
+ bool GetInfo(const char *uri, bool follow, StorageFileInfo &info,
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri,
diff --git a/src/storage/Configured.cxx b/src/storage/Configured.cxx
index 41541673b..d3a55eab8 100644
--- a/src/storage/Configured.cxx
+++ b/src/storage/Configured.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -44,7 +44,7 @@ CreateConfiguredStorageUri(EventLoop &event_loop, const char *uri,
static AllocatedPath
GetConfiguredMusicDirectory(Error &error)
{
- AllocatedPath path = config_get_path(CONF_MUSIC_DIR, error);
+ AllocatedPath path = config_get_path(ConfigOption::MUSIC_DIR, error);
if (path.IsNull() && !error.IsDefined())
path = GetUserMusicDir();
@@ -68,7 +68,7 @@ CreateConfiguredStorage(EventLoop &event_loop, Error &error)
{
assert(!error.IsDefined());
- auto uri = config_get_string(CONF_MUSIC_DIR, nullptr);
+ auto uri = config_get_string(ConfigOption::MUSIC_DIR);
if (uri != nullptr && uri_has_scheme(uri))
return CreateConfiguredStorageUri(event_loop, uri, error);
@@ -78,5 +78,5 @@ CreateConfiguredStorage(EventLoop &event_loop, Error &error)
bool
IsStorageConfigured()
{
- return config_get_string(CONF_MUSIC_DIR, nullptr) != nullptr;
+ return config_get_string(ConfigOption::MUSIC_DIR) != nullptr;
}
diff --git a/src/storage/Configured.hxx b/src/storage/Configured.hxx
index 828a192c3..6769da5ff 100644
--- a/src/storage/Configured.hxx
+++ b/src/storage/Configured.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/FileInfo.hxx b/src/storage/FileInfo.hxx
index 8dd152c0a..4ba842811 100644
--- a/src/storage/FileInfo.hxx
+++ b/src/storage/FileInfo.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
#include <time.h>
#include <stdint.h>
-struct FileInfo {
+struct StorageFileInfo {
enum class Type : uint8_t {
OTHER,
REGULAR,
diff --git a/src/storage/MemoryDirectoryReader.cxx b/src/storage/MemoryDirectoryReader.cxx
index 160836b1a..e6875435c 100644
--- a/src/storage/MemoryDirectoryReader.cxx
+++ b/src/storage/MemoryDirectoryReader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,8 @@ MemoryStorageDirectoryReader::Read()
}
bool
-MemoryStorageDirectoryReader::GetInfo(gcc_unused bool follow, FileInfo &info,
+MemoryStorageDirectoryReader::GetInfo(gcc_unused bool follow,
+ StorageFileInfo &info,
gcc_unused Error &error)
{
assert(!first);
diff --git a/src/storage/MemoryDirectoryReader.hxx b/src/storage/MemoryDirectoryReader.hxx
index 1345082cb..69299d1d4 100644
--- a/src/storage/MemoryDirectoryReader.hxx
+++ b/src/storage/MemoryDirectoryReader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,7 @@ public:
struct Entry {
std::string name;
- FileInfo info;
+ StorageFileInfo info;
template<typename N>
explicit Entry(N &&_name):name(std::forward<N>(_name)) {}
@@ -61,7 +61,8 @@ public:
/* virtual methods from class StorageDirectoryReader */
const char *Read() override;
- bool GetInfo(bool follow, FileInfo &info, Error &error) override;
+ bool GetInfo(bool follow, StorageFileInfo &info,
+ Error &error) override;
};
#endif
diff --git a/src/storage/Registry.cxx b/src/storage/Registry.cxx
index d8e273fd5..a59ec01aa 100644
--- a/src/storage/Registry.cxx
+++ b/src/storage/Registry.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/Registry.hxx b/src/storage/Registry.hxx
index cb3a78f11..8d7828865 100644
--- a/src/storage/Registry.hxx
+++ b/src/storage/Registry.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/StorageInterface.cxx b/src/storage/StorageInterface.cxx
index 93c50a8ac..79f0815d7 100644
--- a/src/storage/StorageInterface.cxx
+++ b/src/storage/StorageInterface.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/StorageInterface.hxx b/src/storage/StorageInterface.hxx
index 4484815bc..4435bbf91 100644
--- a/src/storage/StorageInterface.hxx
+++ b/src/storage/StorageInterface.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,7 +25,7 @@
#include <string>
-struct FileInfo;
+struct StorageFileInfo;
class AllocatedPath;
class Error;
@@ -36,7 +36,8 @@ public:
virtual ~StorageDirectoryReader() {}
virtual const char *Read() = 0;
- virtual bool GetInfo(bool follow, FileInfo &info, Error &error) = 0;
+ virtual bool GetInfo(bool follow, StorageFileInfo &info,
+ Error &error) = 0;
};
class Storage {
@@ -45,7 +46,8 @@ public:
Storage(const Storage &) = delete;
virtual ~Storage() {}
- virtual bool GetInfo(const char *uri_utf8, bool follow, FileInfo &info,
+ virtual bool GetInfo(const char *uri_utf8, bool follow,
+ StorageFileInfo &info,
Error &error) = 0;
virtual StorageDirectoryReader *OpenDirectory(const char *uri_utf8,
diff --git a/src/storage/StoragePlugin.hxx b/src/storage/StoragePlugin.hxx
index 15f431105..962963d2f 100644
--- a/src/storage/StoragePlugin.hxx
+++ b/src/storage/StoragePlugin.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/plugins/LocalStorage.cxx b/src/storage/plugins/LocalStorage.cxx
index b965ceea8..83903ec81 100644
--- a/src/storage/plugins/LocalStorage.cxx
+++ b/src/storage/plugins/LocalStorage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,7 @@
#include "storage/StorageInterface.hxx"
#include "storage/FileInfo.hxx"
#include "util/Error.hxx"
-#include "fs/FileSystem.hxx"
+#include "fs/FileInfo.hxx"
#include "fs/AllocatedPath.hxx"
#include "fs/DirectoryReader.hxx"
@@ -46,7 +46,8 @@ public:
/* virtual methods from class StorageDirectoryReader */
const char *Read() override;
- bool GetInfo(bool follow, FileInfo &info, Error &error) override;
+ bool GetInfo(bool follow, StorageFileInfo &info,
+ Error &error) override;
};
class LocalStorage final : public Storage {
@@ -61,7 +62,7 @@ public:
}
/* virtual methods from class Storage */
- bool GetInfo(const char *uri_utf8, bool follow, FileInfo &info,
+ bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info,
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8,
@@ -78,28 +79,27 @@ private:
};
static bool
-Stat(Path path, bool follow, FileInfo &info, Error &error)
+Stat(Path path, bool follow, StorageFileInfo &info, Error &error)
{
- struct stat st;
- if (!StatFile(path, st, follow)) {
- error.SetErrno();
-
- const auto path_utf8 = path.ToUTF8();
- error.FormatPrefix("Failed to stat %s: ", path_utf8.c_str());
+ FileInfo src;
+ if (!GetFileInfo(path, src, follow, error))
return false;
- }
- if (S_ISREG(st.st_mode))
- info.type = FileInfo::Type::REGULAR;
- else if (S_ISDIR(st.st_mode))
- info.type = FileInfo::Type::DIRECTORY;
+ if (src.IsRegular())
+ info.type = StorageFileInfo::Type::REGULAR;
+ else if (src.IsDirectory())
+ info.type = StorageFileInfo::Type::DIRECTORY;
else
- info.type = FileInfo::Type::OTHER;
-
- info.size = st.st_size;
- info.mtime = st.st_mtime;
- info.device = st.st_dev;
- info.inode = st.st_ino;
+ info.type = StorageFileInfo::Type::OTHER;
+
+ info.size = src.GetSize();
+ info.mtime = src.GetModificationTime();
+#ifdef WIN32
+ info.device = info.inode = 0;
+#else
+ info.device = src.GetDevice();
+ info.inode = src.GetInode();
+#endif
return true;
}
@@ -142,7 +142,7 @@ LocalStorage::MapToRelativeUTF8(const char *uri_utf8) const
}
bool
-LocalStorage::GetInfo(const char *uri_utf8, bool follow, FileInfo &info,
+LocalStorage::GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info,
Error &error)
{
AllocatedPath path_fs = MapFS(uri_utf8, error);
@@ -172,7 +172,7 @@ LocalStorage::OpenDirectory(const char *uri_utf8, Error &error)
gcc_pure
static bool
-SkipNameFS(const char *name_fs)
+SkipNameFS(PathTraitsFS::const_pointer name_fs)
{
return name_fs[0] == '.' &&
(name_fs[1] == 0 ||
@@ -198,7 +198,7 @@ LocalDirectoryReader::Read()
}
bool
-LocalDirectoryReader::GetInfo(bool follow, FileInfo &info, Error &error)
+LocalDirectoryReader::GetInfo(bool follow, StorageFileInfo &info, Error &error)
{
const AllocatedPath path_fs =
AllocatedPath::Build(base_fs, reader.GetEntry());
diff --git a/src/storage/plugins/LocalStorage.hxx b/src/storage/plugins/LocalStorage.hxx
index 7295d38e7..ea6bc357c 100644
--- a/src/storage/plugins/LocalStorage.hxx
+++ b/src/storage/plugins/LocalStorage.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/plugins/NfsStorage.cxx b/src/storage/plugins/NfsStorage.cxx
index a1f079e2c..fc4fd5c07 100644
--- a/src/storage/plugins/NfsStorage.cxx
+++ b/src/storage/plugins/NfsStorage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -84,7 +84,7 @@ public:
}
/* virtual methods from class Storage */
- bool GetInfo(const char *uri_utf8, bool follow, FileInfo &info,
+ bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info,
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8,
@@ -245,14 +245,14 @@ NfsStorage::MapToRelativeUTF8(const char *uri_utf8) const
}
static void
-Copy(FileInfo &info, const struct stat &st)
+Copy(StorageFileInfo &info, const struct stat &st)
{
if (S_ISREG(st.st_mode))
- info.type = FileInfo::Type::REGULAR;
+ info.type = StorageFileInfo::Type::REGULAR;
else if (S_ISDIR(st.st_mode))
- info.type = FileInfo::Type::DIRECTORY;
+ info.type = StorageFileInfo::Type::DIRECTORY;
else
- info.type = FileInfo::Type::OTHER;
+ info.type = StorageFileInfo::Type::OTHER;
info.size = st.st_size;
info.mtime = st.st_mtime;
@@ -262,11 +262,11 @@ Copy(FileInfo &info, const struct stat &st)
class NfsGetInfoOperation final : public BlockingNfsOperation {
const char *const path;
- FileInfo &info;
+ StorageFileInfo &info;
public:
NfsGetInfoOperation(NfsConnection &_connection, const char *_path,
- FileInfo &_info)
+ StorageFileInfo &_info)
:BlockingNfsOperation(_connection), path(_path), info(_info) {}
protected:
@@ -281,7 +281,7 @@ protected:
bool
NfsStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow,
- FileInfo &info, Error &error)
+ StorageFileInfo &info, Error &error)
{
const std::string path = UriToNfsPath(uri_utf8, error);
if (path.empty())
@@ -304,19 +304,19 @@ SkipNameFS(const char *name)
}
static void
-Copy(FileInfo &info, const struct nfsdirent &ent)
+Copy(StorageFileInfo &info, const struct nfsdirent &ent)
{
switch (ent.type) {
case NF3REG:
- info.type = FileInfo::Type::REGULAR;
+ info.type = StorageFileInfo::Type::REGULAR;
break;
case NF3DIR:
- info.type = FileInfo::Type::DIRECTORY;
+ info.type = StorageFileInfo::Type::DIRECTORY;
break;
default:
- info.type = FileInfo::Type::OTHER;
+ info.type = StorageFileInfo::Type::OTHER;
break;
}
diff --git a/src/storage/plugins/NfsStorage.hxx b/src/storage/plugins/NfsStorage.hxx
index f7e18effc..bc757cf8c 100644
--- a/src/storage/plugins/NfsStorage.hxx
+++ b/src/storage/plugins/NfsStorage.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx
index 70a6e16bb..84b212cd1 100644
--- a/src/storage/plugins/SmbclientStorage.cxx
+++ b/src/storage/plugins/SmbclientStorage.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -44,7 +44,8 @@ public:
/* virtual methods from class StorageDirectoryReader */
const char *Read() override;
- bool GetInfo(bool follow, FileInfo &info, Error &error) override;
+ bool GetInfo(bool follow, StorageFileInfo &info,
+ Error &error) override;
};
class SmbclientStorage final : public Storage {
@@ -63,7 +64,7 @@ public:
}
/* virtual methods from class Storage */
- bool GetInfo(const char *uri_utf8, bool follow, FileInfo &info,
+ bool GetInfo(const char *uri_utf8, bool follow, StorageFileInfo &info,
Error &error) override;
StorageDirectoryReader *OpenDirectory(const char *uri_utf8,
@@ -92,7 +93,7 @@ SmbclientStorage::MapToRelativeUTF8(const char *uri_utf8) const
}
static bool
-GetInfo(const char *path, FileInfo &info, Error &error)
+GetInfo(const char *path, StorageFileInfo &info, Error &error)
{
struct stat st;
smbclient_mutex.lock();
@@ -104,11 +105,11 @@ GetInfo(const char *path, FileInfo &info, Error &error)
}
if (S_ISREG(st.st_mode))
- info.type = FileInfo::Type::REGULAR;
+ info.type = StorageFileInfo::Type::REGULAR;
else if (S_ISDIR(st.st_mode))
- info.type = FileInfo::Type::DIRECTORY;
+ info.type = StorageFileInfo::Type::DIRECTORY;
else
- info.type = FileInfo::Type::OTHER;
+ info.type = StorageFileInfo::Type::OTHER;
info.size = st.st_size;
info.mtime = st.st_mtime;
@@ -119,7 +120,7 @@ GetInfo(const char *path, FileInfo &info, Error &error)
bool
SmbclientStorage::GetInfo(const char *uri_utf8, gcc_unused bool follow,
- FileInfo &info, Error &error)
+ StorageFileInfo &info, Error &error)
{
const std::string mapped = MapUTF8(uri_utf8);
return ::GetInfo(mapped.c_str(), info, error);
@@ -172,7 +173,8 @@ SmbclientDirectoryReader::Read()
}
bool
-SmbclientDirectoryReader::GetInfo(gcc_unused bool follow, FileInfo &info,
+SmbclientDirectoryReader::GetInfo(gcc_unused bool follow,
+ StorageFileInfo &info,
Error &error)
{
const std::string path = PathTraitsUTF8::Build(base.c_str(), name);
diff --git a/src/storage/plugins/SmbclientStorage.hxx b/src/storage/plugins/SmbclientStorage.hxx
index 7c198d920..dd047f97e 100644
--- a/src/storage/plugins/SmbclientStorage.hxx
+++ b/src/storage/plugins/SmbclientStorage.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/ByteOrder.hxx b/src/system/ByteOrder.hxx
index 42181fe2c..babc503a9 100644
--- a/src/system/ByteOrder.hxx
+++ b/src/system/ByteOrder.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011-2013 Max Kellermann <max@duempel.org>,
+ * Copyright (C) 2011-2015 Max Kellermann <max@duempel.org>,
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,6 +30,8 @@
#ifndef BYTE_ORDER_HXX
#define BYTE_ORDER_HXX
+#include "Compiler.h"
+
#include <stdint.h>
#if defined(__i386__) || defined(__x86_64__) || defined(__ARMEL__)
@@ -75,23 +77,53 @@ IsBigEndian()
}
static inline constexpr uint16_t
+GenericByteSwap16(uint16_t value)
+{
+ return (value >> 8) | (value << 8);
+}
+
+static inline constexpr uint32_t
+GenericByteSwap32(uint32_t value)
+{
+ return (value >> 24) | ((value >> 8) & 0x0000ff00) |
+ ((value << 8) & 0x00ff0000) | (value << 24);
+}
+
+static inline constexpr uint64_t
+GenericByteSwap64(uint64_t value)
+{
+ return uint64_t(GenericByteSwap32(uint32_t(value >> 32)))
+ | (uint64_t(GenericByteSwap32(value)) << 32);
+}
+
+static inline constexpr uint16_t
ByteSwap16(uint16_t value)
{
- return (value >> 8) | (value << 8);
+#if CLANG_OR_GCC_VERSION(4,8)
+ return __builtin_bswap16(value);
+#else
+ return GenericByteSwap16(value);
+#endif
}
static inline constexpr uint32_t
ByteSwap32(uint32_t value)
{
- return (value >> 24) | ((value >> 8) & 0x0000ff00) |
- ((value << 8) & 0x00ff0000) | (value << 24);
+#if CLANG_OR_GCC_VERSION(4,3)
+ return __builtin_bswap32(value);
+#else
+ return GenericByteSwap32(value);
+#endif
}
static inline constexpr uint64_t
ByteSwap64(uint64_t value)
{
- return uint64_t(ByteSwap32(uint32_t(value >> 32)))
- | (uint64_t(ByteSwap32(value)) << 32);
+#if CLANG_OR_GCC_VERSION(4,3)
+ return __builtin_bswap64(value);
+#else
+ return GenericByteSwap64(value);
+#endif
}
/**
diff --git a/src/system/Clock.cxx b/src/system/Clock.cxx
index c2f5e5087..161525fe1 100644
--- a/src/system/Clock.cxx
+++ b/src/system/Clock.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/Clock.hxx b/src/system/Clock.hxx
index 333a41000..7a710477e 100644
--- a/src/system/Clock.hxx
+++ b/src/system/Clock.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/EPollFD.cxx b/src/system/EPollFD.cxx
index 43e74712f..08051cf06 100644
--- a/src/system/EPollFD.cxx
+++ b/src/system/EPollFD.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/EPollFD.hxx b/src/system/EPollFD.hxx
index 8b9d7d2ba..d12561b5d 100644
--- a/src/system/EPollFD.hxx
+++ b/src/system/EPollFD.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/EventFD.cxx b/src/system/EventFD.cxx
index 9ac4c1d94..016dd372c 100644
--- a/src/system/EventFD.cxx
+++ b/src/system/EventFD.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,46 +20,35 @@
#include "config.h"
#ifdef USE_EVENTFD
#include "EventFD.hxx"
-#include "system/fd_util.h"
#include "system/FatalError.hxx"
#include "Compiler.h"
#include <assert.h>
-#include <unistd.h>
-
#include <sys/eventfd.h>
EventFD::EventFD()
- :fd(eventfd_cloexec_nonblock(0, 0))
{
- if (fd < 0)
+ if (!fd.CreateEventFD(0))
FatalSystemError("eventfd() failed");
}
-EventFD::~EventFD()
-{
- assert(fd >= 0);
-
- close(fd);
-}
-
bool
EventFD::Read()
{
- assert(fd >= 0);
+ assert(fd.IsDefined());
eventfd_t value;
- return read(fd, &value, sizeof(value)) == (ssize_t)sizeof(value);
+ return fd.Read(&value, sizeof(value)) == (ssize_t)sizeof(value);
}
void
EventFD::Write()
{
- assert(fd >= 0);
+ assert(fd.IsDefined());
static constexpr eventfd_t value = 1;
gcc_unused ssize_t nbytes =
- write(fd, &value, sizeof(value));
+ fd.Write(&value, sizeof(value));
}
#endif /* USE_EVENTFD */
diff --git a/src/system/EventFD.hxx b/src/system/EventFD.hxx
index 2a70461d9..616877f4a 100644
--- a/src/system/EventFD.hxx
+++ b/src/system/EventFD.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#define MPD_EVENT_FD_HXX
#include "check.h"
+#include "FileDescriptor.hxx"
/**
* A class that wraps eventfd().
@@ -28,17 +29,19 @@
* Errors in the constructor are fatal.
*/
class EventFD {
- int fd;
+ FileDescriptor fd;
public:
EventFD();
- ~EventFD();
+ ~EventFD() {
+ fd.Close();
+ }
EventFD(const EventFD &other) = delete;
EventFD &operator=(const EventFD &other) = delete;
int Get() const {
- return fd;
+ return fd.Get();
}
/**
diff --git a/src/system/EventPipe.cxx b/src/system/EventPipe.cxx
index b8fc85aed..8b3141492 100644
--- a/src/system/EventPipe.cxx
+++ b/src/system/EventPipe.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/EventPipe.hxx b/src/system/EventPipe.hxx
index 42b3bb93d..229d5633e 100644
--- a/src/system/EventPipe.hxx
+++ b/src/system/EventPipe.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/FatalError.cxx b/src/system/FatalError.cxx
index 35e94f169..664b96a6c 100644
--- a/src/system/FatalError.cxx
+++ b/src/system/FatalError.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,10 +23,6 @@
#include "util/Domain.hxx"
#include "LogV.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>
@@ -78,18 +74,31 @@ FatalError(const char *msg, const Error &error)
FormatFatalError("%s: %s", msg, error.GetMessage());
}
+#ifdef WIN32
+
+void
+FatalSystemError(const char *msg, DWORD code)
+{
+ char buffer[256];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, code, 0,
+ buffer, sizeof(buffer), nullptr);
+ FormatFatalError("%s: %s", msg, buffer);
+}
+
+#endif
+
void
FatalSystemError(const char *msg)
{
- const char *system_error;
#ifdef WIN32
- system_error = g_win32_error_message(GetLastError());
+ FatalSystemError(msg, GetLastError());
#else
- system_error = strerror(errno);
-#endif
-
+ const char *system_error = strerror(errno);
FormatError(fatal_error_domain, "%s: %s", msg, system_error);
Abort();
+#endif
}
void
diff --git a/src/system/FatalError.hxx b/src/system/FatalError.hxx
index d4698b3d9..89363feeb 100644
--- a/src/system/FatalError.hxx
+++ b/src/system/FatalError.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,10 @@
#include "check.h"
#include "Compiler.h"
+#ifdef WIN32
+#include <windef.h>
+#endif
+
class Error;
/**
@@ -53,6 +57,14 @@ gcc_noreturn
void
FatalSystemError(const char *msg);
+#ifdef WIN32
+
+gcc_noreturn
+void
+FatalSystemError(const char *msg, DWORD code);
+
+#endif
+
gcc_noreturn
void
FormatFatalSystemError(const char *fmt, ...);
diff --git a/src/system/FileDescriptor.cxx b/src/system/FileDescriptor.cxx
new file mode 100644
index 000000000..db258e107
--- /dev/null
+++ b/src/system/FileDescriptor.cxx
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "config.h"
+#include "FileDescriptor.hxx"
+
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef WIN32
+#include <poll.h>
+#endif
+
+#ifdef USE_EVENTFD
+#include <sys/eventfd.h>
+#endif
+
+#ifdef USE_SIGNALFD
+#include <sys/signalfd.h>
+#endif
+
+#ifdef HAVE_INOTIFY_INIT
+#include <sys/inotify.h>
+#endif
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+bool
+FileDescriptor::Open(const char *pathname, int flags, mode_t mode)
+{
+ fd = ::open(pathname, flags | O_NOCTTY | O_CLOEXEC, mode);
+ return IsDefined();
+}
+
+bool
+FileDescriptor::OpenReadOnly(const char *pathname)
+{
+ return Open(pathname, O_RDONLY);
+}
+
+#ifndef WIN32
+
+bool
+FileDescriptor::OpenNonBlocking(const char *pathname)
+{
+ return Open(pathname, O_RDWR | O_NONBLOCK);
+}
+
+bool
+FileDescriptor::CreatePipe(FileDescriptor &r, FileDescriptor &w)
+{
+ int fds[2];
+
+#ifdef HAVE_PIPE2
+ const int flags = O_CLOEXEC;
+ const int result = pipe2(fds, flags);
+#else
+ const int result = pipe(fds);
+#endif
+
+ if (result < 0)
+ return false;
+
+ r = FileDescriptor(fds[0]);
+ w = FileDescriptor(fds[1]);
+ return true;
+}
+
+void
+FileDescriptor::SetNonBlocking()
+{
+ assert(IsDefined());
+
+ int flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+void
+FileDescriptor::SetBlocking()
+{
+ assert(IsDefined());
+
+ int flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
+}
+
+#endif
+
+#ifdef USE_EVENTFD
+
+bool
+FileDescriptor::CreateEventFD(unsigned initval)
+{
+ fd = ::eventfd(initval, EFD_NONBLOCK|EFD_CLOEXEC);
+ return fd >= 0;
+}
+
+#endif
+
+#ifdef USE_SIGNALFD
+
+bool
+FileDescriptor::CreateSignalFD(const sigset_t *mask)
+{
+ int new_fd = ::signalfd(fd, mask, SFD_NONBLOCK|SFD_CLOEXEC);
+ if (new_fd < 0)
+ return false;
+
+ fd = new_fd;
+ return true;
+}
+
+#endif
+
+#ifdef HAVE_INOTIFY_INIT
+
+bool
+FileDescriptor::CreateInotify()
+{
+#ifdef HAVE_INOTIFY_INIT1
+ int new_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
+#else
+ int new_fd = inotify_init();
+#endif
+ if (new_fd < 0)
+ return false;
+
+#ifndef HAVE_INOTIFY_INIT1
+ SetNonBlocking();
+#endif
+
+ fd = new_fd;
+ return true;
+}
+
+#endif
+
+bool
+FileDescriptor::Rewind()
+{
+ assert(IsDefined());
+
+ return lseek(fd, 0, SEEK_SET) == 0;
+}
+
+off_t
+FileDescriptor::GetSize() const
+{
+ struct stat st;
+ return ::fstat(fd, &st) >= 0
+ ? (long)st.st_size
+ : -1;
+}
+
+#ifndef WIN32
+
+int
+FileDescriptor::Poll(short events, int timeout) const
+{
+ assert(IsDefined());
+
+ struct pollfd pfd;
+ pfd.fd = fd;
+ pfd.events = events;
+ int result = poll(&pfd, 1, timeout);
+ return result > 0
+ ? pfd.revents
+ : result;
+}
+
+int
+FileDescriptor::WaitReadable(int timeout) const
+{
+ return Poll(POLLIN, timeout);
+}
+
+int
+FileDescriptor::WaitWritable(int timeout) const
+{
+ return Poll(POLLOUT, timeout);
+}
+
+#endif
diff --git a/src/system/FileDescriptor.hxx b/src/system/FileDescriptor.hxx
new file mode 100644
index 000000000..75a76844c
--- /dev/null
+++ b/src/system/FileDescriptor.hxx
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2012-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 FILE_DESCRIPTOR_HXX
+#define FILE_DESCRIPTOR_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#ifdef USE_SIGNALFD
+#include <signal.h>
+#endif
+
+/**
+ * An OO wrapper for a UNIX file descriptor.
+ *
+ * This class is unmanaged and trivial.
+ */
+class FileDescriptor {
+protected:
+ int fd;
+
+public:
+ FileDescriptor() = default;
+ explicit constexpr FileDescriptor(int _fd):fd(_fd) {}
+
+ constexpr bool operator==(FileDescriptor other) const {
+ return fd == other.fd;
+ }
+
+ constexpr bool IsDefined() const {
+ return fd >= 0;
+ }
+
+ /**
+ * Returns the file descriptor. This may only be called if
+ * IsDefined() returns true.
+ */
+ constexpr int Get() const {
+ return fd;
+ }
+
+ void Set(int _fd) {
+ fd = _fd;
+ }
+
+ int Steal() {
+ assert(IsDefined());
+
+ int _fd = fd;
+ fd = -1;
+ return _fd;
+ }
+
+ void SetUndefined() {
+ fd = -1;
+ }
+
+ static constexpr FileDescriptor Undefined() {
+ return FileDescriptor(-1);
+ }
+
+ bool Open(const char *pathname, int flags, mode_t mode=0666);
+ bool OpenReadOnly(const char *pathname);
+
+#ifndef WIN32
+ bool OpenNonBlocking(const char *pathname);
+
+ static bool CreatePipe(FileDescriptor &r, FileDescriptor &w);
+
+ /**
+ * Enable non-blocking mode on this file descriptor.
+ */
+ void SetNonBlocking();
+
+ /**
+ * Enable blocking mode on this file descriptor.
+ */
+ void SetBlocking();
+
+ /**
+ * Duplicate the file descriptor onto the given file descriptor.
+ */
+ bool Duplicate(int new_fd) const {
+ return ::dup2(Get(), new_fd) == 0;
+ }
+#endif
+
+#ifdef USE_EVENTFD
+ bool CreateEventFD(unsigned initval=0);
+#endif
+
+#ifdef USE_SIGNALFD
+ bool CreateSignalFD(const sigset_t *mask);
+#endif
+
+#ifdef HAVE_INOTIFY_INIT
+ bool CreateInotify();
+#endif
+
+ /**
+ * Close the file descriptor. It is legal to call it on an
+ * "undefined" object. After this call, IsDefined() is guaranteed
+ * to return false, and this object may be reused.
+ */
+ bool Close() {
+ return ::close(Steal()) == 0;
+ }
+
+ /**
+ * Rewind the pointer to the beginning of the file.
+ */
+ bool Rewind();
+
+ off_t Seek(off_t offset) {
+ return lseek(Get(), offset, SEEK_SET);
+ }
+
+ gcc_pure
+ off_t Tell() const {
+ return lseek(Get(), 0, SEEK_CUR);
+ }
+
+ /**
+ * Returns the size of the file in bytes, or -1 on error.
+ */
+ gcc_pure
+ off_t GetSize() const;
+
+ ssize_t Read(void *buffer, size_t length) {
+ return ::read(fd, buffer, length);
+ }
+
+ ssize_t Write(const void *buffer, size_t length) {
+ return ::write(fd, buffer, length);
+ }
+
+#ifndef WIN32
+ int Poll(short events, int timeout) const;
+
+ int WaitReadable(int timeout) const;
+ int WaitWritable(int timeout) const;
+#endif
+};
+
+#endif
diff --git a/src/system/PeriodClock.hxx b/src/system/PeriodClock.hxx
index 2c535fee9..a9db4cea0 100644
--- a/src/system/PeriodClock.hxx
+++ b/src/system/PeriodClock.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/system/SignalFD.cxx b/src/system/SignalFD.cxx
index 173a0cc8c..14193c893 100644
--- a/src/system/SignalFD.cxx
+++ b/src/system/SignalFD.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -23,33 +23,29 @@
#include "FatalError.hxx"
#include <assert.h>
-#include <unistd.h>
#include <sys/signalfd.h>
void
SignalFD::Create(const sigset_t &mask)
{
- fd = ::signalfd(fd, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (fd < 0)
+ if (!fd.CreateSignalFD(&mask))
FatalSystemError("signalfd() failed");
}
void
SignalFD::Close()
{
- if (fd >= 0) {
- ::close(fd);
- fd = -1;
- }
+ if (fd.IsDefined())
+ fd.Close();
}
int
SignalFD::Read()
{
- assert(fd >= 0);
+ assert(fd.IsDefined());
signalfd_siginfo info;
- return read(fd, &info, sizeof(info)) > 0
+ return fd.Read(&info, sizeof(info)) > 0
? info.ssi_signo
: -1;
}
diff --git a/src/system/SignalFD.hxx b/src/system/SignalFD.hxx
index 11bf30f74..dae150fea 100644
--- a/src/system/SignalFD.hxx
+++ b/src/system/SignalFD.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#define MPD_SIGNAL_FD_HXX
#include "check.h"
+#include "FileDescriptor.hxx"
#include <signal.h>
@@ -28,7 +29,7 @@
* A class that wraps signalfd().
*/
class SignalFD {
- int fd;
+ FileDescriptor fd;
public:
SignalFD():fd(-1) {}
@@ -48,7 +49,7 @@ public:
void Close();
int Get() const {
- return fd;
+ return fd.Get();
}
/**
diff --git a/src/system/fd_util.c b/src/system/fd_util.c
index b53ecda00..5763ede90 100644
--- a/src/system/fd_util.c
+++ b/src/system/fd_util.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
@@ -41,10 +41,6 @@
#include <sys/socket.h>
#endif
-#ifdef HAVE_INOTIFY_INIT
-#include <sys/inotify.h>
-#endif
-
#ifdef USE_EVENTFD
#include <sys/eventfd.h>
#endif
@@ -106,16 +102,6 @@ fd_set_nonblock(int fd)
}
int
-dup_cloexec(int oldfd)
-{
- int newfd = dup(oldfd);
- if (newfd >= 0)
- fd_set_nonblock(newfd);
-
- return newfd;
-}
-
-int
open_cloexec(const char *path_fs, int flags, int mode)
{
int fd;
@@ -136,30 +122,6 @@ open_cloexec(const char *path_fs, int flags, int mode)
}
int
-pipe_cloexec(int fd[2])
-{
-#ifdef WIN32
- return _pipe(fd, 512, _O_BINARY);
-#else
- int ret;
-
-#ifdef HAVE_PIPE2
- ret = pipe2(fd, O_CLOEXEC);
- if (ret >= 0 || errno != ENOSYS)
- return ret;
-#endif
-
- ret = pipe(fd);
- if (ret >= 0) {
- fd_set_cloexec(fd[0], true);
- fd_set_cloexec(fd[1], true);
- }
-
- return ret;
-#endif
-}
-
-int
pipe_cloexec_nonblock(int fd[2])
{
#ifdef WIN32
@@ -186,53 +148,6 @@ pipe_cloexec_nonblock(int fd[2])
#endif
}
-#ifndef WIN32
-
-int
-socketpair_cloexec(int domain, int type, int protocol, int sv[2])
-{
- int ret;
-
-#ifdef SOCK_CLOEXEC
- ret = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv);
- if (ret >= 0 || errno != EINVAL)
- return ret;
-#endif
-
- ret = socketpair(domain, type, protocol, sv);
- if (ret >= 0) {
- fd_set_cloexec(sv[0], true);
- fd_set_cloexec(sv[1], true);
- }
-
- return ret;
-}
-
-int
-socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2])
-{
- int ret;
-
-#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
- ret = socketpair(domain, type | SOCK_CLOEXEC | SOCK_NONBLOCK, protocol,
- sv);
- if (ret >= 0 || errno != EINVAL)
- return ret;
-#endif
-
- ret = socketpair(domain, type, protocol, sv);
- if (ret >= 0) {
- fd_set_cloexec(sv[0], true);
- fd_set_nonblock(sv[0]);
- fd_set_cloexec(sv[1], true);
- fd_set_nonblock(sv[1]);
- }
-
- return ret;
-}
-
-#endif
-
int
socket_cloexec_nonblock(int domain, int type, int protocol)
{
@@ -281,65 +196,6 @@ accept_cloexec_nonblock(int fd, struct sockaddr *address,
return ret;
}
-#ifndef WIN32
-
-ssize_t
-recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
-{
-#ifdef MSG_CMSG_CLOEXEC
- flags |= MSG_CMSG_CLOEXEC;
-#endif
-
- ssize_t result = recvmsg(sockfd, msg, flags);
- if (result >= 0) {
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
- while (cmsg != NULL) {
- if (cmsg->cmsg_type == SCM_RIGHTS) {
- const int *fd_p = (const int *)CMSG_DATA(cmsg);
- fd_set_cloexec(*fd_p, true);
- }
-
- cmsg = CMSG_NXTHDR(msg, cmsg);
- }
- }
-
- return result;
-}
-
-#endif
-
-#ifdef HAVE_INOTIFY_INIT
-
-int
-inotify_init_cloexec(void)
-{
- int fd;
-
-#ifdef HAVE_INOTIFY_INIT1
- fd = inotify_init1(IN_CLOEXEC);
- if (fd >= 0 || errno != ENOSYS)
- return fd;
-#endif
-
- fd = inotify_init();
- if (fd >= 0)
- fd_set_cloexec(fd, true);
-
- return fd;
-}
-
-#endif
-
-#ifdef USE_EVENTFD
-
-int
-eventfd_cloexec_nonblock(unsigned initval, int flags)
-{
- return eventfd(initval, flags | EFD_CLOEXEC | EFD_NONBLOCK);
-}
-
-#endif
-
int
close_socket(int fd)
{
diff --git a/src/system/fd_util.h b/src/system/fd_util.h
index f4a940e91..172b1ade3 100644
--- a/src/system/fd_util.h
+++ b/src/system/fd_util.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
@@ -55,13 +55,6 @@ int
fd_set_cloexec(int fd, bool enable);
/**
- * Wrapper for dup(), which sets the CLOEXEC flag on the new
- * descriptor.
- */
-int
-dup_cloexec(int oldfd);
-
-/**
* Wrapper for open(), which sets the CLOEXEC flag (atomically if
* supported by the OS).
*/
@@ -71,13 +64,6 @@ open_cloexec(const char *path_fs, int flags, int mode);
/**
* Wrapper for pipe(), which sets the CLOEXEC flag (atomically if
* supported by the OS).
- */
-int
-pipe_cloexec(int fd[2]);
-
-/**
- * Wrapper for pipe(), which sets the CLOEXEC flag (atomically if
- * supported by the OS).
*
* On systems that supports it (everybody except for Windows), it also
* sets the NONBLOCK flag.
@@ -85,25 +71,7 @@ pipe_cloexec(int fd[2]);
int
pipe_cloexec_nonblock(int fd[2]);
-#ifndef WIN32
-
-/**
- * Wrapper for socketpair(), which sets the CLOEXEC flag (atomically
- * if supported by the OS).
- */
-int
-socketpair_cloexec(int domain, int type, int protocol, int sv[2]);
-
-/**
- * Wrapper for socketpair(), which sets the flags CLOEXEC and NONBLOCK
- * (atomically if supported by the OS).
- */
-int
-socketpair_cloexec_nonblock(int domain, int type, int protocol, int sv[2]);
-
-#endif
-
-#ifdef HAVE_LIBMPDCLIENT
+#ifdef ENABLE_LIBMPDCLIENT
/* Avoid symbol conflict with statically linked libmpdclient */
#define socket_cloexec_nonblock socket_cloexec_nonblock_noconflict
#endif
@@ -123,42 +91,6 @@ int
accept_cloexec_nonblock(int fd, struct sockaddr *address,
size_t *address_length_r);
-
-#ifndef WIN32
-
-struct msghdr;
-
-/**
- * Wrapper for recvmsg(), which sets the CLOEXEC flag (atomically if
- * supported by the OS).
- */
-ssize_t
-recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
-
-#endif
-
-#ifdef HAVE_INOTIFY_INIT
-
-/**
- * Wrapper for inotify_init(), which sets the CLOEXEC flag (atomically
- * if supported by the OS).
- */
-int
-inotify_init_cloexec(void);
-
-#endif
-
-#ifdef USE_EVENTFD
-
-/**
- * Wrapper for eventfd() which sets the flags CLOEXEC and NONBLOCK
- * flag (atomically if supported by the OS).
- */
-int
-eventfd_cloexec_nonblock(unsigned initval, int flags);
-
-#endif
-
/**
* Portable wrapper for close(); use closesocket() on WIN32/WinSock.
*/
diff --git a/src/tag/Aiff.cxx b/src/tag/Aiff.cxx
index c2498c9e9..7235b76a8 100644
--- a/src/tag/Aiff.cxx
+++ b/src/tag/Aiff.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/Aiff.hxx b/src/tag/Aiff.hxx
index cd323ee2e..f9b11b5a6 100644
--- a/src/tag/Aiff.hxx
+++ b/src/tag/Aiff.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/ApeLoader.cxx b/src/tag/ApeLoader.cxx
index f51cb5c0b..b1759a730 100644
--- a/src/tag/ApeLoader.cxx
+++ b/src/tag/ApeLoader.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "ApeLoader.hxx"
#include "system/ByteOrder.hxx"
#include "fs/FileSystem.hxx"
+#include "util/StringView.hxx"
#include <stdint.h>
#include <assert.h>
@@ -89,7 +90,7 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
if (remaining < size)
break;
- if (!callback(flags, key, p, size))
+ if (!callback(flags, key, {p, size}))
break;
p += size;
@@ -103,7 +104,7 @@ ape_scan_internal(FILE *fp, ApeTagCallback callback)
bool
tag_ape_scan(Path path_fs, ApeTagCallback callback)
{
- FILE *fp = FOpen(path_fs, "rb");
+ FILE *fp = FOpen(path_fs, PATH_LITERAL("rb"));
if (fp == nullptr)
return false;
diff --git a/src/tag/ApeLoader.hxx b/src/tag/ApeLoader.hxx
index ce82cc35d..4587ff063 100644
--- a/src/tag/ApeLoader.hxx
+++ b/src/tag/ApeLoader.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,11 +26,11 @@
#include <stddef.h>
+struct StringView;
class Path;
typedef std::function<bool(unsigned long flags, const char *key,
- const char *value,
- size_t value_length)> ApeTagCallback;
+ StringView value)> ApeTagCallback;
/**
* Scans the APE tag values from a file.
diff --git a/src/tag/ApeReplayGain.cxx b/src/tag/ApeReplayGain.cxx
index 345f45710..883885369 100644
--- a/src/tag/ApeReplayGain.cxx
+++ b/src/tag/ApeReplayGain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,15 +21,16 @@
#include "ApeReplayGain.hxx"
#include "ApeLoader.hxx"
#include "ReplayGain.hxx"
-#include "util/ASCII.hxx"
#include "fs/Path.hxx"
+#include "util/ASCII.hxx"
+#include "util/StringView.hxx"
#include <string.h>
#include <stdlib.h>
static bool
replay_gain_ape_callback(unsigned long flags, const char *key,
- const char *_value, size_t value_length,
+ StringView _value,
ReplayGainInfo &info)
{
/* we only care about utf-8 text tags */
@@ -37,11 +38,11 @@ replay_gain_ape_callback(unsigned long flags, const char *key,
return false;
char value[16];
- if (value_length >= sizeof(value))
+ if (_value.size >= sizeof(value))
return false;
- memcpy(value, _value, value_length);
- value[value_length] = 0;
+ memcpy(value, _value.data, _value.size);
+ value[_value.size] = 0;
return ParseReplayGainTag(info, key, value);
}
@@ -53,10 +54,9 @@ replay_gain_ape_read(Path path_fs, ReplayGainInfo &info)
auto callback = [&info, &found]
(unsigned long flags, const char *key,
- const char *value,
- size_t value_length) {
+ StringView value) {
found |= replay_gain_ape_callback(flags, key,
- value, value_length,
+ value,
info);
return true;
};
diff --git a/src/tag/ApeReplayGain.hxx b/src/tag/ApeReplayGain.hxx
index 03c899c5c..faf68f0e3 100644
--- a/src/tag/ApeReplayGain.hxx
+++ b/src/tag/ApeReplayGain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/ApeTag.cxx b/src/tag/ApeTag.cxx
index f714a1624..81318a771 100644
--- a/src/tag/ApeTag.cxx
+++ b/src/tag/ApeTag.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,13 +24,13 @@
#include "TagTable.hxx"
#include "TagHandler.hxx"
#include "fs/Path.hxx"
+#include "util/StringView.hxx"
#include <string>
#include <string.h>
const struct tag_table ape_tags[] = {
- { "album artist", TAG_ALBUM_ARTIST },
{ "year", TAG_DATE },
{ nullptr, TAG_NUM_OF_ITEM_TYPES }
};
@@ -76,17 +76,18 @@ ForEachValue(const char *value, const char *end, C &&callback)
*/
static bool
tag_ape_import_item(unsigned long flags,
- const char *key, const char *value, size_t value_length,
+ const char *key, StringView value,
const struct tag_handler *handler, void *handler_ctx)
{
/* we only care about utf-8 text tags */
if ((flags & (0x3 << 1)) != 0)
return false;
- const char *const end = value + value_length;
+ const auto begin = value.begin();
+ const auto end = value.end();
if (handler->pair != nullptr)
- ForEachValue(value, end, [handler, handler_ctx,
+ ForEachValue(begin, end, [handler, handler_ctx,
key](const char *_value) {
handler->pair(key, _value, handler_ctx);
});
@@ -95,8 +96,8 @@ tag_ape_import_item(unsigned long flags,
if (type == TAG_NUM_OF_ITEM_TYPES)
return false;
- ForEachValue(value, end, [handler, handler_ctx,
- type](const char *_value) {
+ ForEachValue(begin, end, [handler, handler_ctx,
+ type](const char *_value) {
tag_handler_invoke_tag(handler, handler_ctx,
type, _value);
});
@@ -112,10 +113,8 @@ tag_ape_scan2(Path path_fs,
auto callback = [handler, handler_ctx, &recognized]
(unsigned long flags, const char *key,
- const char *value,
- size_t value_length) {
+ StringView value) {
recognized |= tag_ape_import_item(flags, key, value,
- value_length,
handler, handler_ctx);
return true;
};
diff --git a/src/tag/ApeTag.hxx b/src/tag/ApeTag.hxx
index edebf076c..20d1d7b81 100644
--- a/src/tag/ApeTag.hxx
+++ b/src/tag/ApeTag.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/Format.cxx b/src/tag/Format.cxx
new file mode 100644
index 000000000..de4db57ef
--- /dev/null
+++ b/src/tag/Format.cxx
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "Format.hxx"
+#include "Tag.hxx"
+#include "util/format.h"
+#include "util/StringUtil.hxx"
+
+#include <algorithm>
+
+#include <string.h>
+#include <time.h>
+
+struct FormatTagContext {
+ const Tag &tag;
+
+ char buffer[256];
+
+ explicit FormatTagContext(const Tag &_tag):tag(_tag) {}
+};
+
+/**
+ * Is this a character unsafe to use in a path name segment?
+ */
+static constexpr bool
+IsUnsafeChar(char ch)
+{
+ return
+ /* disallow characters illegal in file names on
+ Windows (Linux allows almost anything) */
+ ch == '\\' || ch == '/' || ch == ':' || ch == '*' ||
+ ch == '?' || ch == '<' || ch == '>' || ch == '|' ||
+ /* allow space, but disallow all other whitespace */
+ (unsigned char)ch < 0x20;
+}
+
+gcc_pure
+static bool
+HasUnsafeChar(const char *s)
+{
+ for (; *s; ++s)
+ if (IsUnsafeChar(*s))
+ return true;
+
+ return false;
+}
+
+static const char *
+SanitizeString(const char *s, char *buffer, size_t buffer_size)
+{
+ /* skip leading dots to avoid generating "../" sequences */
+ while (*s == '.')
+ ++s;
+
+ if (!HasUnsafeChar(s))
+ return s;
+
+ char *end = CopyString(buffer, s, buffer_size);
+ std::replace_if(buffer, end, IsUnsafeChar, ' ');
+ return buffer;
+}
+
+gcc_pure gcc_nonnull_all
+static const char *
+TagGetter(const void *object, const char *name)
+{
+ const auto &_ctx = *(const FormatTagContext *)object;
+ auto &ctx = const_cast<FormatTagContext &>(_ctx);
+
+ if (strcmp(name, "iso8601") == 0) {
+ time_t t = time(nullptr);
+#ifdef WIN32
+ const struct tm *tm2 = gmtime(&t);
+#else
+ struct tm tm;
+ const struct tm *tm2 = gmtime_r(&t, &tm);
+#endif
+ if (tm2 == nullptr)
+ return "";
+
+ strftime(ctx.buffer, sizeof(ctx.buffer),
+#ifdef WIN32
+ /* kludge: use underscore instead of colon on
+ Windows because colons are not allowed in
+ file names, and this library is mostly
+ used to generate file names */
+ "%Y-%m-%dT%H_%M_%SZ",
+#else
+ "%FT%TZ",
+#endif
+ tm2);
+ return ctx.buffer;
+ }
+
+ const Tag &tag = ctx.tag;
+
+ TagType tag_type = tag_name_parse_i(name);
+ if (tag_type == TAG_NUM_OF_ITEM_TYPES)
+ /* unknown tag name */
+ return nullptr;
+
+ const char *value = tag.GetValue(tag_type);
+ if (value == nullptr)
+ /* known tag name, but not present in this object */
+ value = "";
+
+ // TODO: handle multiple tag values
+ return SanitizeString(value, ctx.buffer, sizeof(ctx.buffer));
+}
+
+char *
+FormatTag(const Tag &tag, const char *format)
+{
+ FormatTagContext ctx(tag);
+ return format_object(format, &ctx, TagGetter);
+}
diff --git a/src/tag/Format.hxx b/src/tag/Format.hxx
new file mode 100644
index 000000000..a08e687d0
--- /dev/null
+++ b/src/tag/Format.hxx
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_TAG_FORMAT_HXX
+#define MPD_TAG_FORMAT_HXX
+
+#include "check.h"
+#include "Compiler.h"
+
+struct Tag;
+
+gcc_malloc gcc_nonnull_all
+char *
+FormatTag(const Tag &tag, const char *format);
+
+#endif
diff --git a/src/tag/Mask.hxx b/src/tag/Mask.hxx
new file mode 100644
index 000000000..9576d56e7
--- /dev/null
+++ b/src/tag/Mask.hxx
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_TAG_MASK_HXX
+#define MPD_TAG_MASK_HXX
+
+#include <stdint.h>
+
+typedef uint_least32_t tag_mask_t;
+
+#endif
diff --git a/src/tag/MixRamp.cxx b/src/tag/MixRamp.cxx
index e1b6e43c5..cbec047de 100644
--- a/src/tag/MixRamp.cxx
+++ b/src/tag/MixRamp.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/MixRamp.hxx b/src/tag/MixRamp.hxx
index 5b4e2dc30..7255bac4d 100644
--- a/src/tag/MixRamp.hxx
+++ b/src/tag/MixRamp.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/ReplayGain.cxx b/src/tag/ReplayGain.cxx
index 83a48f243..edf8c92f1 100644
--- a/src/tag/ReplayGain.cxx
+++ b/src/tag/ReplayGain.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/ReplayGain.hxx b/src/tag/ReplayGain.hxx
index 2bf5e0db1..a2e897235 100644
--- a/src/tag/ReplayGain.hxx
+++ b/src/tag/ReplayGain.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/Riff.cxx b/src/tag/Riff.cxx
index c630f082d..741225813 100644
--- a/src/tag/Riff.cxx
+++ b/src/tag/Riff.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/Riff.hxx b/src/tag/Riff.hxx
index a9af67b7a..b15716882 100644
--- a/src/tag/Riff.hxx
+++ b/src/tag/Riff.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/Set.cxx b/src/tag/Set.cxx
index 6a55a450f..6499321e6 100644
--- a/src/tag/Set.cxx
+++ b/src/tag/Set.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "Set.hxx"
#include "TagBuilder.hxx"
-#include "TagSettings.h"
+#include "Settings.hxx"
#include <assert.h>
@@ -58,16 +58,16 @@ CopyTagItem(TagBuilder &dest, const Tag &src, TagType type)
* Copy all tag items of the types in the mask.
*/
static void
-CopyTagMask(TagBuilder &dest, const Tag &src, uint32_t mask)
+CopyTagMask(TagBuilder &dest, const Tag &src, tag_mask_t mask)
{
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
- if ((mask & (1u << i)) != 0)
+ if ((mask & (tag_mask_t(1) << i)) != 0)
CopyTagItem(dest, src, TagType(i));
}
void
TagSet::InsertUnique(const Tag &src, TagType type, const char *value,
- uint32_t group_mask)
+ tag_mask_t group_mask)
{
TagBuilder builder;
if (value == nullptr)
@@ -75,7 +75,7 @@ TagSet::InsertUnique(const Tag &src, TagType type, const char *value,
else
builder.AddItem(type, value);
CopyTagMask(builder, src, group_mask);
-#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
+#if CLANG_OR_GCC_VERSION(4,8)
emplace(builder.Commit());
#else
insert(builder.Commit());
@@ -85,7 +85,7 @@ TagSet::InsertUnique(const Tag &src, TagType type, const char *value,
bool
TagSet::CheckUnique(TagType dest_type,
const Tag &tag, TagType src_type,
- uint32_t group_mask)
+ tag_mask_t group_mask)
{
bool found = false;
@@ -101,16 +101,16 @@ TagSet::CheckUnique(TagType dest_type,
void
TagSet::InsertUnique(const Tag &tag,
- TagType type, uint32_t group_mask)
+ TagType type, tag_mask_t group_mask)
{
static_assert(sizeof(group_mask) * 8 >= TAG_NUM_OF_ITEM_TYPES,
"Mask is too small");
- assert((group_mask & (1u << unsigned(type))) == 0);
+ assert((group_mask & (tag_mask_t(1) << unsigned(type))) == 0);
if (!CheckUnique(type, tag, type, group_mask) &&
(type != TAG_ALBUM_ARTIST ||
- ignore_tag_items[TAG_ALBUM_ARTIST] ||
+ !IsTagEnabled(TAG_ALBUM_ARTIST) ||
/* fall back to "Artist" if no "AlbumArtist" was found */
!CheckUnique(type, tag, TAG_ARTIST, group_mask)))
InsertUnique(tag, type, nullptr, group_mask);
diff --git a/src/tag/Set.hxx b/src/tag/Set.hxx
index b5acfcb36..587b25a3a 100644
--- a/src/tag/Set.hxx
+++ b/src/tag/Set.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,11 +22,11 @@
#include "Compiler.h"
#include "Tag.hxx"
+#include "Mask.hxx"
#include <set>
#include <string.h>
-#include <stdint.h>
/**
* Helper class for #TagSet which compares two #Tag objects.
@@ -59,15 +59,15 @@ struct TagLess {
class TagSet : public std::set<Tag, TagLess> {
public:
void InsertUnique(const Tag &tag,
- TagType type, uint32_t group_mask);
+ TagType type, tag_mask_t group_mask);
private:
void InsertUnique(const Tag &src, TagType type, const char *value,
- uint32_t group_mask);
+ tag_mask_t group_mask);
bool CheckUnique(TagType dest_type,
const Tag &tag, TagType src_type,
- uint32_t group_mask);
+ tag_mask_t group_mask);
};
#endif
diff --git a/src/tag/Settings.cxx b/src/tag/Settings.cxx
new file mode 100644
index 000000000..83c626db8
--- /dev/null
+++ b/src/tag/Settings.cxx
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "Settings.hxx"
+
+tag_mask_t global_tag_mask = (tag_mask_t)-1 & ~(1 << TAG_COMMENT);
diff --git a/src/tag/Settings.hxx b/src/tag/Settings.hxx
new file mode 100644
index 000000000..332454b8f
--- /dev/null
+++ b/src/tag/Settings.hxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_TAG_SETTINGS_HXX
+#define MPD_TAG_SETTINGS_HXX
+
+#include "Mask.hxx"
+#include "TagType.h"
+#include "Compiler.h"
+
+#include <stdint.h>
+
+extern tag_mask_t global_tag_mask;
+
+gcc_const
+static inline bool
+IsTagEnabled(unsigned tag)
+{
+ return global_tag_mask & (1u << tag);
+}
+
+gcc_const
+static inline bool
+IsTagEnabled(TagType tag)
+{
+ return IsTagEnabled(unsigned(tag));
+}
+
+#endif
diff --git a/src/tag/Tag.cxx b/src/tag/Tag.cxx
index 92ac4214c..fc124df0d 100644
--- a/src/tag/Tag.cxx
+++ b/src/tag/Tag.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,6 @@
#include "Tag.hxx"
#include "TagPool.hxx"
#include "TagString.hxx"
-#include "TagSettings.h"
#include "TagBuilder.hxx"
#include "util/ASCII.hxx"
diff --git a/src/tag/Tag.hxx b/src/tag/Tag.hxx
index f1d3d5767..aca2bf6a0 100644
--- a/src/tag/Tag.hxx
+++ b/src/tag/Tag.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagBuilder.cxx b/src/tag/TagBuilder.cxx
index 0882f9561..82d99006a 100644
--- a/src/tag/TagBuilder.cxx
+++ b/src/tag/TagBuilder.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,11 +19,12 @@
#include "config.h"
#include "TagBuilder.hxx"
-#include "TagSettings.h"
+#include "Settings.hxx"
#include "TagPool.hxx"
#include "TagString.hxx"
#include "Tag.hxx"
#include "util/WritableBuffer.hxx"
+#include "util/StringView.hxx"
#include <array>
@@ -189,22 +190,16 @@ TagBuilder::Complement(const Tag &other)
}
inline void
-TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
+TagBuilder::AddItemInternal(TagType type, StringView value)
{
-#if !CLANG_CHECK_VERSION(3,6)
- /* disabled on clang due to -Wtautological-pointer-compare */
- assert(value != nullptr);
-#endif
- assert(length > 0);
+ assert(!value.IsEmpty());
- auto f = FixTagString(value, length);
- if (!f.IsNull()) {
- value = f.data;
- length = f.size;
- }
+ auto f = FixTagString(value);
+ if (!f.IsNull())
+ value = { f.data, f.size };
tag_pool_lock.lock();
- auto i = tag_pool_get_item(type, value, length);
+ auto i = tag_pool_get_item(type, value);
tag_pool_lock.unlock();
free(f.data);
@@ -213,17 +208,12 @@ TagBuilder::AddItemInternal(TagType type, const char *value, size_t length)
}
void
-TagBuilder::AddItem(TagType type, const char *value, size_t length)
+TagBuilder::AddItem(TagType type, StringView value)
{
-#if !CLANG_CHECK_VERSION(3,6)
- /* disabled on clang due to -Wtautological-pointer-compare */
- assert(value != nullptr);
-#endif
-
- if (length == 0 || ignore_tag_items[type])
+ if (value.IsEmpty() || !IsTagEnabled(type))
return;
- AddItemInternal(type, value, length);
+ AddItemInternal(type, value);
}
void
@@ -234,14 +224,14 @@ TagBuilder::AddItem(TagType type, const char *value)
assert(value != nullptr);
#endif
- AddItem(type, value, strlen(value));
+ AddItem(type, StringView(value));
}
void
TagBuilder::AddEmptyItem(TagType type)
{
tag_pool_lock.lock();
- auto i = tag_pool_get_item(type, "", 0);
+ auto i = tag_pool_get_item(type, StringView::Empty());
tag_pool_lock.unlock();
items.push_back(i);
diff --git a/src/tag/TagBuilder.hxx b/src/tag/TagBuilder.hxx
index aff581313..08c66d0b3 100644
--- a/src/tag/TagBuilder.hxx
+++ b/src/tag/TagBuilder.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
#include <stddef.h>
+struct StringView;
struct TagItem;
struct Tag;
@@ -138,10 +139,10 @@ public:
*
* @param type the type of the new tag item
* @param value the value of the tag item (not null-terminated)
- * @param len the length of #value
+ * @param length the length of #value
*/
gcc_nonnull_all
- void AddItem(TagType type, const char *value, size_t length);
+ void AddItem(TagType type, StringView value);
/**
* Appends a new tag item.
@@ -171,7 +172,7 @@ public:
private:
gcc_nonnull_all
- void AddItemInternal(TagType type, const char *value, size_t length);
+ void AddItemInternal(TagType type, StringView value);
};
#endif
diff --git a/src/tag/TagConfig.cxx b/src/tag/TagConfig.cxx
index 00f20d1c0..b0e7b8ff0 100644
--- a/src/tag/TagConfig.cxx
+++ b/src/tag/TagConfig.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@
#include "config.h"
#include "TagConfig.hxx"
-#include "TagSettings.h"
+#include "Settings.hxx"
#include "Tag.hxx"
#include "config/ConfigGlobal.hxx"
#include "config/ConfigOption.hxx"
@@ -35,11 +35,11 @@
void
TagLoadConfig()
{
- const char *value = config_get_string(CONF_METADATA_TO_USE, nullptr);
+ const char *value = config_get_string(ConfigOption::METADATA_TO_USE);
if (value == nullptr)
return;
- std::fill_n(ignore_tag_items, size_t(TAG_NUM_OF_ITEM_TYPES), true);
+ global_tag_mask = 0;
if (StringEqualsCaseASCII(value, "none"))
return;
@@ -62,7 +62,7 @@ TagLoadConfig()
FormatFatalError("error parsing metadata item \"%s\"",
c);
- ignore_tag_items[type] = false;
+ global_tag_mask |= tag_mask_t(1) << unsigned(type);
s++;
c = s;
diff --git a/src/tag/TagConfig.hxx b/src/tag/TagConfig.hxx
index 0088e9757..05c6594c6 100644
--- a/src/tag/TagConfig.hxx
+++ b/src/tag/TagConfig.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagHandler.cxx b/src/tag/TagHandler.cxx
index 2cbb83242..bbd30877a 100644
--- a/src/tag/TagHandler.cxx
+++ b/src/tag/TagHandler.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,9 @@
#include "TagBuilder.hxx"
#include "util/ASCII.hxx"
+#include <stdio.h>
+#include <stdlib.h>
+
static void
add_tag_duration(SongTime duration, void *ctx)
{
@@ -35,7 +38,17 @@ add_tag_tag(TagType type, const char *value, void *ctx)
{
TagBuilder &tag = *(TagBuilder *)ctx;
- tag.AddItem(type, value);
+ if (type == TAG_TRACK || type == TAG_DISC) {
+ /* 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);
+ }
+ } else
+ tag.AddItem(type, value);
}
const struct tag_handler add_tag_handler = {
diff --git a/src/tag/TagHandler.hxx b/src/tag/TagHandler.hxx
index c12b605bc..e87c299fc 100644
--- a/src/tag/TagHandler.hxx
+++ b/src/tag/TagHandler.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagId3.cxx b/src/tag/TagId3.cxx
index 02dc58364..288f239d1 100644
--- a/src/tag/TagId3.cxx
+++ b/src/tag/TagId3.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,10 +33,6 @@
#include "fs/Path.hxx"
#include "fs/FileSystem.hxx"
-#ifdef HAVE_GLIB
-#include <glib.h>
-#endif
-
#include <id3tag.h>
#include <string>
@@ -66,12 +62,14 @@
static constexpr Domain id3_domain("id3");
+gcc_pure
static inline bool
tag_is_id3v1(struct id3_tag *tag)
{
return (id3_tag_options(tag, 0, 0) & ID3_TAG_OPTION_ID3V1) != 0;
}
+gcc_pure
static id3_utf8_t *
tag_id3_getstring(const struct id3_frame *frame, unsigned i)
{
@@ -89,42 +87,11 @@ tag_id3_getstring(const struct id3_frame *frame, unsigned i)
/* This will try to convert a string to utf-8,
*/
static id3_utf8_t *
-import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
+import_id3_string(const id3_ucs4_t *ucs4)
{
- id3_utf8_t *utf8;
-
-#ifdef HAVE_GLIB
- /* use encoding field here? */
- const char *encoding;
- if (is_id3v1 &&
- (encoding = config_get_string(CONF_ID3V1_ENCODING, nullptr)) != nullptr) {
- id3_latin1_t *isostr = id3_ucs4_latin1duplicate(ucs4);
- if (gcc_unlikely(isostr == nullptr))
- return nullptr;
-
- utf8 = (id3_utf8_t *)
- g_convert_with_fallback((const char*)isostr, -1,
- "utf-8", encoding,
- nullptr, nullptr,
- nullptr, nullptr);
- if (utf8 == nullptr) {
- FormatWarning(id3_domain,
- "Unable to convert %s string to UTF-8: '%s'",
- encoding, isostr);
- free(isostr);
- return nullptr;
- }
- free(isostr);
- } else {
-#else
- (void)is_id3v1;
-#endif
- utf8 = id3_ucs4_utf8duplicate(ucs4);
- if (gcc_unlikely(utf8 == nullptr))
- return nullptr;
-#ifdef HAVE_GLIB
- }
-#endif
+ id3_utf8_t *utf8 = id3_ucs4_utf8duplicate(ucs4);
+ if (gcc_unlikely(utf8 == nullptr))
+ return nullptr;
id3_utf8_t *utf8_stripped = (id3_utf8_t *)
xstrdup(Strip((char *)utf8));
@@ -141,7 +108,7 @@ import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
* - string list
*/
static void
-tag_id3_import_text_frame(struct id3_tag *tag, const struct id3_frame *frame,
+tag_id3_import_text_frame(const struct id3_frame *frame,
TagType type,
const struct tag_handler *handler, void *handler_ctx)
{
@@ -170,7 +137,7 @@ tag_id3_import_text_frame(struct id3_tag *tag, const struct id3_frame *frame,
if (type == TAG_GENRE)
ucs4 = id3_genre_name(ucs4);
- id3_utf8_t *utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
+ id3_utf8_t *utf8 = import_id3_string(ucs4);
if (utf8 == nullptr)
continue;
@@ -191,7 +158,7 @@ tag_id3_import_text(struct id3_tag *tag, const char *id, TagType type,
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != nullptr; ++i)
- tag_id3_import_text_frame(tag, frame, type,
+ tag_id3_import_text_frame(frame, type,
handler, handler_ctx);
}
@@ -205,8 +172,7 @@ tag_id3_import_text(struct id3_tag *tag, const char *id, TagType type,
* - full string (we use this one)
*/
static void
-tag_id3_import_comment_frame(struct id3_tag *tag,
- const struct id3_frame *frame, TagType type,
+tag_id3_import_comment_frame(const struct id3_frame *frame, TagType type,
const struct tag_handler *handler,
void *handler_ctx)
{
@@ -222,7 +188,7 @@ tag_id3_import_comment_frame(struct id3_tag *tag,
if (ucs4 == nullptr)
return;
- id3_utf8_t *utf8 = import_id3_string(tag_is_id3v1(tag), ucs4);
+ id3_utf8_t *utf8 = import_id3_string(ucs4);
if (utf8 == nullptr)
return;
@@ -241,7 +207,7 @@ tag_id3_import_comment(struct id3_tag *tag, const char *id, TagType type,
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != nullptr; ++i)
- tag_id3_import_comment_frame(tag, frame, type,
+ tag_id3_import_comment_frame(frame, type,
handler, handler_ctx);
}
@@ -249,10 +215,11 @@ tag_id3_import_comment(struct id3_tag *tag, const char *id, TagType type,
* Parse a TXXX name, and convert it to a TagType enum value.
* Returns TAG_NUM_OF_ITEM_TYPES if the TXXX name is not understood.
*/
+gcc_pure
static TagType
tag_id3_parse_txxx_name(const char *name)
{
- static const struct tag_table txxx_tags[] = {
+ static constexpr struct tag_table txxx_tags[] = {
{ "ALBUMARTISTSORT", TAG_ALBUM_ARTIST_SORT },
{ "MusicBrainz Artist Id", TAG_MUSICBRAINZ_ARTISTID },
{ "MusicBrainz Album Id", TAG_MUSICBRAINZ_ALBUMID },
@@ -517,7 +484,7 @@ tag_id3_riff_aiff_load(FILE *file)
struct id3_tag *
tag_id3_load(Path path_fs, Error &error)
{
- FILE *file = FOpen(path_fs, "rb");
+ FILE *file = FOpen(path_fs, PATH_LITERAL("rb"));
if (file == nullptr) {
error.FormatErrno("Failed to open file %s", path_fs.c_str());
return nullptr;
diff --git a/src/tag/TagId3.hxx b/src/tag/TagId3.hxx
index 1928d539d..94dfb1794 100644
--- a/src/tag/TagId3.hxx
+++ b/src/tag/TagId3.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,7 +29,7 @@ struct Tag;
struct id3_tag;
class Error;
-#ifdef HAVE_ID3TAG
+#ifdef ENABLE_ID3TAG
bool
tag_id3_scan(Path path_fs,
diff --git a/src/tag/TagItem.hxx b/src/tag/TagItem.hxx
index 489ecde3a..0aa52f700 100644
--- a/src/tag/TagItem.hxx
+++ b/src/tag/TagItem.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagNames.c b/src/tag/TagNames.c
index e051c5863..056d714e4 100644
--- a/src/tag/TagNames.c
+++ b/src/tag/TagNames.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagPool.cxx b/src/tag/TagPool.cxx
index 29f605337..88b2ba333 100644
--- a/src/tag/TagPool.cxx
+++ b/src/tag/TagPool.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +22,7 @@
#include "TagItem.hxx"
#include "util/Cast.hxx"
#include "util/VarSize.hxx"
+#include "util/StringView.hxx"
#include <assert.h>
#include <string.h>
@@ -37,39 +38,37 @@ struct TagPoolSlot {
TagItem item;
TagPoolSlot(TagPoolSlot *_next, TagType type,
- const char *value, size_t length)
+ StringView value)
:next(_next), ref(1) {
item.type = type;
- memcpy(item.value, value, length);
- item.value[length] = 0;
+ memcpy(item.value, value.data, value.size);
+ item.value[value.size] = 0;
}
static TagPoolSlot *Create(TagPoolSlot *_next, TagType type,
- const char *value, size_t length);
+ StringView value);
} gcc_packed;
TagPoolSlot *
TagPoolSlot::Create(TagPoolSlot *_next, TagType type,
- const char *value, size_t length)
+ StringView value)
{
TagPoolSlot *dummy;
return NewVarSize<TagPoolSlot>(sizeof(dummy->item.value),
- length + 1,
+ value.size + 1,
_next, type,
- value, length);
+ value);
}
static TagPoolSlot *slots[NUM_SLOTS];
static inline unsigned
-calc_hash_n(TagType type, const char *p, size_t length)
+calc_hash(TagType type, StringView p)
{
unsigned hash = 5381;
- assert(p != nullptr);
-
- while (length-- > 0)
- hash = (hash << 5) + hash + *p++;
+ for (auto ch : p)
+ hash = (hash << 5) + hash + ch;
return hash ^ type;
}
@@ -87,7 +86,7 @@ calc_hash(TagType type, const char *p)
return hash ^ type;
}
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline TagPoolSlot *
@@ -97,9 +96,9 @@ tag_item_to_slot(TagItem *item)
}
static inline TagPoolSlot **
-tag_value_slot_p(TagType type, const char *value, size_t length)
+tag_value_slot_p(TagType type, StringView value)
{
- return &slots[calc_hash_n(type, value, length) % NUM_SLOTS];
+ return &slots[calc_hash(type, value) % NUM_SLOTS];
}
static inline TagPoolSlot **
@@ -109,13 +108,12 @@ tag_value_slot_p(TagType type, const char *value)
}
TagItem *
-tag_pool_get_item(TagType type, const char *value, size_t length)
+tag_pool_get_item(TagType type, StringView value)
{
- auto slot_p = tag_value_slot_p(type, value, length);
+ auto slot_p = tag_value_slot_p(type, value);
for (auto slot = *slot_p; slot != nullptr; slot = slot->next) {
if (slot->item.type == type &&
- length == strlen(slot->item.value) &&
- memcmp(value, slot->item.value, length) == 0 &&
+ value.Equals(slot->item.value) &&
slot->ref < 0xff) {
assert(slot->ref > 0);
++slot->ref;
@@ -123,7 +121,7 @@ tag_pool_get_item(TagType type, const char *value, size_t length)
}
}
- auto slot = TagPoolSlot::Create(*slot_p, type, value, length);
+ auto slot = TagPoolSlot::Create(*slot_p, type, value);
*slot_p = slot;
return &slot->item;
}
@@ -141,11 +139,9 @@ tag_pool_dup_item(TagItem *item)
} else {
/* the reference counter overflows above 0xff;
duplicate the item, and start with 1 */
- size_t length = strlen(item->value);
- auto slot_p = tag_value_slot_p(item->type,
- item->value, length);
+ auto slot_p = tag_value_slot_p(item->type, item->value);
slot = TagPoolSlot::Create(*slot_p, item->type,
- item->value, strlen(item->value));
+ item->value);
*slot_p = slot;
return &slot->item;
}
diff --git a/src/tag/TagPool.hxx b/src/tag/TagPool.hxx
index 990ee87bd..7b4b5dadf 100644
--- a/src/tag/TagPool.hxx
+++ b/src/tag/TagPool.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,9 +26,10 @@
extern Mutex tag_pool_lock;
struct TagItem;
+struct StringView;
TagItem *
-tag_pool_get_item(TagType type, const char *value, size_t length);
+tag_pool_get_item(TagType type, StringView value);
TagItem *
tag_pool_dup_item(TagItem *item);
diff --git a/src/tag/TagRva2.cxx b/src/tag/TagRva2.cxx
index bbb6d11e6..8e22cd693 100644
--- a/src/tag/TagRva2.cxx
+++ b/src/tag/TagRva2.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,42 +26,42 @@
#include <stdint.h>
#include <string.h>
-enum rva2_channel {
- CHANNEL_OTHER = 0x00,
- CHANNEL_MASTER_VOLUME = 0x01,
- CHANNEL_FRONT_RIGHT = 0x02,
- CHANNEL_FRONT_LEFT = 0x03,
- CHANNEL_BACK_RIGHT = 0x04,
- CHANNEL_BACK_LEFT = 0x05,
- CHANNEL_FRONT_CENTRE = 0x06,
- CHANNEL_BACK_CENTRE = 0x07,
- CHANNEL_SUBWOOFER = 0x08
+enum class Rva2Channel : uint8_t {
+ OTHER = 0x00,
+ MASTER_VOLUME = 0x01,
+ FRONT_RIGHT = 0x02,
+ FRONT_LEFT = 0x03,
+ BACK_RIGHT = 0x04,
+ BACK_LEFT = 0x05,
+ FRONT_CENTRE = 0x06,
+ BACK_CENTRE = 0x07,
+ SUBWOOFER = 0x08
};
-struct rva2_data {
- uint8_t type;
+struct Rva2Data {
+ Rva2Channel type;
uint8_t volume_adjustment[2];
uint8_t peak_bits;
};
static inline id3_length_t
-rva2_peak_bytes(const struct rva2_data *data)
+rva2_peak_bytes(const Rva2Data &data)
{
- return (data->peak_bits + 7) / 8;
+ return (data.peak_bits + 7) / 8;
}
static inline int
-rva2_fixed_volume_adjustment(const struct rva2_data *data)
+rva2_fixed_volume_adjustment(const Rva2Data &data)
{
signed int voladj_fixed;
- voladj_fixed = (data->volume_adjustment[0] << 8) |
- data->volume_adjustment[1];
+ voladj_fixed = (data.volume_adjustment[0] << 8) |
+ data.volume_adjustment[1];
voladj_fixed |= -(voladj_fixed & 0x8000);
return voladj_fixed;
}
static inline float
-rva2_float_volume_adjustment(const struct rva2_data *data)
+rva2_float_volume_adjustment(const Rva2Data &data)
{
/*
* "The volume adjustment is encoded as a fixed point decibel
@@ -74,9 +74,9 @@ rva2_float_volume_adjustment(const struct rva2_data *data)
static inline bool
rva2_apply_data(ReplayGainInfo &rgi,
- const struct rva2_data *data, const id3_latin1_t *id)
+ const Rva2Data &data, const id3_latin1_t *id)
{
- if (data->type != CHANNEL_MASTER_VOLUME)
+ if (data.type != Rva2Channel::MASTER_VOLUME)
return false;
float volume_adjustment = rva2_float_volume_adjustment(data);
@@ -117,7 +117,7 @@ rva2_apply_frame(ReplayGainInfo &replay_gain_info,
*/
while (length >= 4) {
- const struct rva2_data *d = (const struct rva2_data *)data;
+ const Rva2Data &d = *(const Rva2Data *)data;
unsigned int peak_bytes = rva2_peak_bytes(d);
if (4 + peak_bytes > length)
break;
diff --git a/src/tag/TagRva2.hxx b/src/tag/TagRva2.hxx
index df559f472..615d5a282 100644
--- a/src/tag/TagRva2.hxx
+++ b/src/tag/TagRva2.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,7 @@ struct id3_tag;
struct ReplayGainInfo;
/**
- * Parse the RVA2 tag, and fill the #replay_gain_info struct. This is
+ * Parse the RVA2 tag, and fill the #ReplayGainInfo struct. This is
* used by decoder plugins with ID3 support.
*
* @return true on success
diff --git a/src/tag/TagString.cxx b/src/tag/TagString.cxx
index 4f07cd62a..d30a07a27 100644
--- a/src/tag/TagString.cxx
+++ b/src/tag/TagString.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,7 @@
#include "TagString.hxx"
#include "util/Alloc.hxx"
#include "util/WritableBuffer.hxx"
+#include "util/StringView.hxx"
#include "util/UTF8.hxx"
#include <assert.h>
@@ -54,14 +55,14 @@ FindInvalidUTF8(const char *p, const char *const end)
* Replace invalid sequences with the question mark.
*/
static WritableBuffer<char>
-patch_utf8(const char *src, size_t length, const char *_invalid)
+patch_utf8(StringView src, const char *_invalid)
{
/* duplicate the string, and replace invalid bytes in that
buffer */
- char *dest = (char *)xmemdup(src, length);
- char *const end = dest + length;
+ char *dest = (char *)xmemdup(src.data, src.size);
+ char *const end = dest + src.size;
- char *invalid = dest + (_invalid - src);
+ char *invalid = dest + (_invalid - src.data);
do {
*invalid = '?';
@@ -69,19 +70,19 @@ patch_utf8(const char *src, size_t length, const char *_invalid)
invalid = const_cast<char *>(__invalid);
} while (invalid != nullptr);
- return { dest, length };
+ return { dest, src.size };
}
static WritableBuffer<char>
-fix_utf8(const char *str, size_t length)
+fix_utf8(StringView p)
{
/* check if the string is already valid UTF-8 */
- const char *invalid = FindInvalidUTF8(str, str + length);
+ const char *invalid = FindInvalidUTF8(p.begin(), p.end());
if (invalid == nullptr)
return nullptr;
/* no, broken - patch invalid sequences */
- return patch_utf8(str, length, invalid);
+ return patch_utf8(p, invalid);
}
static bool
@@ -91,11 +92,11 @@ char_is_non_printable(unsigned char ch)
}
static const char *
-find_non_printable(const char *p, size_t length)
+find_non_printable(StringView p)
{
- for (size_t i = 0; i < length; ++i)
- if (char_is_non_printable(p[i]))
- return p + i;
+ for (const char &ch : p)
+ if (char_is_non_printable(ch))
+ return &ch;
return nullptr;
}
@@ -105,31 +106,29 @@ find_non_printable(const char *p, size_t length)
* Returns nullptr if nothing needs to be cleared.
*/
static WritableBuffer<char>
-clear_non_printable(const char *p, size_t length)
+clear_non_printable(StringView src)
{
- const char *first = find_non_printable(p, length);
+ const char *first = find_non_printable(src);
if (first == nullptr)
return nullptr;
- char *dest = (char *)xmemdup(p, length);
+ char *dest = (char *)xmemdup(src.data, src.size);
- for (size_t i = first - p; i < length; ++i)
+ for (size_t i = first - src.data; i < src.size; ++i)
if (char_is_non_printable(dest[i]))
dest[i] = ' ';
- return { dest, length };
+ return { dest, src.size };
}
WritableBuffer<char>
-FixTagString(const char *p, size_t length)
+FixTagString(StringView p)
{
- auto utf8 = fix_utf8(p, length);
- if (!utf8.IsNull()) {
- p = utf8.data;
- length = utf8.size;
- }
+ auto utf8 = fix_utf8(p);
+ if (!utf8.IsNull())
+ p = {utf8.data, utf8.size};
- WritableBuffer<char> cleared = clear_non_printable(p, length);
+ WritableBuffer<char> cleared = clear_non_printable(p);
if (cleared.IsNull())
cleared = utf8;
else
diff --git a/src/tag/TagString.hxx b/src/tag/TagString.hxx
index eccc2aa47..53fbc7abd 100644
--- a/src/tag/TagString.hxx
+++ b/src/tag/TagString.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,10 +25,11 @@
#include <stddef.h>
+struct StringView;
template<typename T> struct WritableBuffer;
gcc_nonnull_all
WritableBuffer<char>
-FixTagString(const char *p, size_t length);
+FixTagString(StringView p);
#endif
diff --git a/src/tag/TagTable.cxx b/src/tag/TagTable.cxx
index c6e1cff54..e2a22b642 100644
--- a/src/tag/TagTable.cxx
+++ b/src/tag/TagTable.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagTable.hxx b/src/tag/TagTable.hxx
index 095b4cbff..0d72cba99 100644
--- a/src/tag/TagTable.hxx
+++ b/src/tag/TagTable.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/TagType.h b/src/tag/TagType.h
index 0aa6b4a51..6f68d53d0 100644
--- a/src/tag/TagType.h
+++ b/src/tag/TagType.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/VorbisComment.cxx b/src/tag/VorbisComment.cxx
index 2dfc058d8..2c45470d4 100644
--- a/src/tag/VorbisComment.cxx
+++ b/src/tag/VorbisComment.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/tag/VorbisComment.hxx b/src/tag/VorbisComment.hxx
index 1dd3371c8..e48e9b7a9 100644
--- a/src/tag/VorbisComment.hxx
+++ b/src/tag/VorbisComment.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/thread/Cond.hxx b/src/thread/Cond.hxx
index a05d1c67d..ed016d212 100644
--- a/src/thread/Cond.hxx
+++ b/src/thread/Cond.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2014 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2009-2015 Max Kellermann <max@duempel.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,8 +32,6 @@
#ifdef WIN32
-/* mingw-w64 4.6.3 lacks a std::cond implementation */
-
#include "WindowsCond.hxx"
class Cond : public WindowsCond {};
diff --git a/src/thread/Id.hxx b/src/thread/Id.hxx
index 11be0a56b..60006e31a 100644
--- a/src/thread/Id.hxx
+++ b/src/thread/Id.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/thread/Mutex.hxx b/src/thread/Mutex.hxx
index c17538549..bc4deebdd 100644
--- a/src/thread/Mutex.hxx
+++ b/src/thread/Mutex.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2014 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2009-2015 Max Kellermann <max@duempel.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -32,8 +32,6 @@
#ifdef WIN32
-/* mingw-w64 4.6.3 lacks a std::mutex implementation */
-
#include "CriticalSection.hxx"
class Mutex : public CriticalSection {};
diff --git a/src/thread/Name.hxx b/src/thread/Name.hxx
index a99208dab..999cebf73 100644
--- a/src/thread/Name.hxx
+++ b/src/thread/Name.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/thread/PosixCond.hxx b/src/thread/PosixCond.hxx
index b3fe204e1..73dbe0218 100644
--- a/src/thread/PosixCond.hxx
+++ b/src/thread/PosixCond.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2009-2015 Max Kellermann <max@duempel.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,9 +41,13 @@ class PosixCond {
pthread_cond_t cond;
public:
-#if defined(__NetBSD__) || defined(__BIONIC__)
- /* NetBSD's PTHREAD_COND_INITIALIZER is not compatible with
- "constexpr" */
+#ifdef __GLIBC__
+ /* optimized constexpr constructor for pthread implementations
+ that support it */
+ constexpr PosixCond():cond(PTHREAD_COND_INITIALIZER) {}
+#else
+ /* slow fallback for pthread implementations that are not
+ compatible with "constexpr" */
PosixCond() {
pthread_cond_init(&cond, nullptr);
}
@@ -51,10 +55,6 @@ public:
~PosixCond() {
pthread_cond_destroy(&cond);
}
-#else
- /* optimized constexpr constructor for sane POSIX
- implementations */
- constexpr PosixCond():cond(PTHREAD_COND_INITIALIZER) {}
#endif
PosixCond(const PosixCond &other) = delete;
diff --git a/src/thread/PosixMutex.hxx b/src/thread/PosixMutex.hxx
index 5805158d5..e0fd614c8 100644
--- a/src/thread/PosixMutex.hxx
+++ b/src/thread/PosixMutex.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009-2013 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2009-2015 Max Kellermann <max@duempel.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -41,9 +41,13 @@ class PosixMutex {
pthread_mutex_t mutex;
public:
-#if defined(__NetBSD__) || defined(__BIONIC__)
- /* NetBSD's PTHREAD_MUTEX_INITIALIZER is not compatible with
- "constexpr" */
+#ifdef __GLIBC__
+ /* optimized constexpr constructor for pthread implementations
+ that support it */
+ constexpr PosixMutex():mutex(PTHREAD_MUTEX_INITIALIZER) {}
+#else
+ /* slow fallback for pthread implementations that are not
+ compatible with "constexpr" */
PosixMutex() {
pthread_mutex_init(&mutex, nullptr);
}
@@ -51,10 +55,6 @@ public:
~PosixMutex() {
pthread_mutex_destroy(&mutex);
}
-#else
- /* optimized constexpr constructor for sane POSIX
- implementations */
- constexpr PosixMutex():mutex(PTHREAD_MUTEX_INITIALIZER) {}
#endif
PosixMutex(const PosixMutex &other) = delete;
diff --git a/src/thread/Slack.hxx b/src/thread/Slack.hxx
index 66b2254a4..3f9c71d52 100644
--- a/src/thread/Slack.hxx
+++ b/src/thread/Slack.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/thread/Thread.cxx b/src/thread/Thread.cxx
index 2932d478f..78675d84e 100644
--- a/src/thread/Thread.cxx
+++ b/src/thread/Thread.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/thread/Thread.hxx b/src/thread/Thread.hxx
index 976ff5625..668f5e9f7 100644
--- a/src/thread/Thread.hxx
+++ b/src/thread/Thread.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/unix/Daemon.cxx b/src/unix/Daemon.cxx
index d283108ed..9aa16a078 100644
--- a/src/unix/Daemon.cxx
+++ b/src/unix/Daemon.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -36,6 +36,10 @@
#include <grp.h>
#endif
+#ifndef WCOREDUMP
+#define WCOREDUMP(v) 0
+#endif
+
#ifndef WIN32
/** the Unix user name which MPD runs as */
@@ -62,28 +66,17 @@ static int detach_fd = -1;
void
daemonize_kill(void)
{
- FILE *fp;
- int pid, ret;
-
if (pidfile.IsNull())
FatalError("no pid_file specified in the config file");
- fp = FOpen(pidfile, "r");
- if (fp == nullptr) {
- const std::string utf8 = pidfile.ToUTF8();
- FormatFatalSystemError("Unable to open pid file \"%s\"",
- utf8.c_str());
- }
-
- if (fscanf(fp, "%i", &pid) != 1) {
+ const pid_t pid = ReadPidFile(pidfile);
+ if (pid < 0) {
const std::string utf8 = pidfile.ToUTF8();
FormatFatalError("unable to read the pid from file \"%s\"",
utf8.c_str());
}
- fclose(fp);
- ret = kill(pid, SIGTERM);
- if (ret < 0)
+ if (kill(pid, SIGTERM) < 0)
FormatFatalSystemError("unable to kill process %i",
int(pid));
diff --git a/src/unix/Daemon.hxx b/src/unix/Daemon.hxx
index fe5681511..5937705ce 100644
--- a/src/unix/Daemon.hxx
+++ b/src/unix/Daemon.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -33,10 +33,10 @@ daemonize_init(const char *user, const char *group, AllocatedPath &&pidfile)
#ifndef WIN32
void
-daemonize_finish(void);
+daemonize_finish();
#else
static inline void
-daemonize_finish(void)
+daemonize_finish()
{ /* nop */ }
#endif
@@ -46,11 +46,11 @@ daemonize_finish(void)
*/
#ifndef WIN32
void
-daemonize_kill(void);
+daemonize_kill();
#else
#include "system/FatalError.hxx"
static inline void
-daemonize_kill(void)
+daemonize_kill()
{
FatalError("--kill is not available on WIN32");
}
@@ -61,10 +61,10 @@ daemonize_kill(void)
*/
#ifndef WIN32
void
-daemonize_close_stdin(void);
+daemonize_close_stdin();
#else
static inline void
-daemonize_close_stdin(void) {}
+daemonize_close_stdin() {}
#endif
/**
@@ -72,10 +72,10 @@ daemonize_close_stdin(void) {}
*/
#ifndef WIN32
void
-daemonize_set_user(void);
+daemonize_set_user();
#else
static inline void
-daemonize_set_user(void)
+daemonize_set_user()
{ /* nop */ }
#endif
diff --git a/src/unix/PidFile.hxx b/src/unix/PidFile.hxx
index a242c7810..cbb681554 100644
--- a/src/unix/PidFile.hxx
+++ b/src/unix/PidFile.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,61 +25,90 @@
#include "Log.hxx"
#include <assert.h>
-#include <stdio.h>
-#include <sys/types.h>
+#include <string.h>
#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
class PidFile {
- FILE *file;
+ int fd;
public:
- PidFile(const AllocatedPath &path):file(nullptr) {
+ PidFile(const AllocatedPath &path):fd(-1) {
if (path.IsNull())
return;
- file = FOpen(path, "w");
- if (file == nullptr) {
+ fd = OpenFile(path, O_WRONLY|O_CREAT|O_TRUNC, 0666);
+ if (fd < 0) {
const std::string utf8 = path.ToUTF8();
FormatFatalSystemError("Failed to create pid file \"%s\"",
- path.c_str());
+ utf8.c_str());
}
}
PidFile(const PidFile &) = delete;
void Close() {
- if (file == nullptr)
+ if (fd < 0)
return;
- fclose(file);
+ close(fd);
}
void Delete(const AllocatedPath &path) {
- if (file == nullptr) {
+ if (fd < 0) {
assert(path.IsNull());
return;
}
assert(!path.IsNull());
- fclose(file);
+ close(fd);
RemoveFile(path);
}
void Write(pid_t pid) {
- if (file == nullptr)
+ if (fd < 0)
return;
- fprintf(file, "%lu\n", (unsigned long)pid);
- fclose(file);
+ char buffer[64];
+ sprintf(buffer, "%lu\n", (unsigned long)pid);
+
+ write(fd, buffer, strlen(buffer));
+ close(fd);
}
void Write() {
- if (file == nullptr)
+ if (fd < 0)
return;
Write(getpid());
}
};
+gcc_pure
+static inline pid_t
+ReadPidFile(Path path)
+{
+ int fd = OpenFile(path, O_RDONLY, 0);
+ if (fd < 0)
+ return -1;
+
+ pid_t pid = -1;
+
+ char buffer[32];
+ auto nbytes = read(fd, buffer, sizeof(buffer) - 1);
+ if (nbytes > 0) {
+ buffer[nbytes] = 0;
+
+ char *endptr;
+ auto value = strtoul(buffer, &endptr, 10);
+ if (endptr > buffer)
+ pid = value;
+ }
+
+ close(fd);
+ return pid;
+}
+
#endif
diff --git a/src/unix/SignalHandlers.cxx b/src/unix/SignalHandlers.cxx
index 4aef4fa71..47085b4fd 100644
--- a/src/unix/SignalHandlers.cxx
+++ b/src/unix/SignalHandlers.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/unix/SignalHandlers.hxx b/src/unix/SignalHandlers.hxx
index 551b373c1..573db7511 100644
--- a/src/unix/SignalHandlers.hxx
+++ b/src/unix/SignalHandlers.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/ASCII.hxx b/src/util/ASCII.hxx
index 9f7147338..d9a2198e1 100644
--- a/src/util/ASCII.hxx
+++ b/src/util/ASCII.hxx
@@ -27,8 +27,8 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef MPD_ASCII_HXX
-#define MPD_ASCII_HXX
+#ifndef ASCII_HXX
+#define ASCII_HXX
#include "Compiler.h"
diff --git a/src/util/Alloc.cxx b/src/util/Alloc.cxx
index 006e09701..c2676ca3d 100644
--- a/src/util/Alloc.cxx
+++ b/src/util/Alloc.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -75,3 +75,87 @@ xstrndup(const char *s, size_t n)
return p;
}
+
+#if CLANG_OR_GCC_VERSION(4,7)
+
+template<typename... Args>
+static inline size_t
+FillLengths(size_t *lengths, const char *a, Args&&... args)
+{
+ return FillLengths(lengths, a) + FillLengths(lengths + 1, args...);
+}
+
+template<>
+inline size_t
+FillLengths(size_t *lengths, const char *a)
+{
+ return *lengths = strlen(a);
+}
+
+template<typename... Args>
+static inline void
+StringCat(char *p, const size_t *lengths, const char *a, Args&&... args)
+{
+ StringCat(p, lengths, a);
+ StringCat(p + *lengths, lengths + 1, args...);
+}
+
+template<>
+inline void
+StringCat(char *p, const size_t *lengths, const char *a)
+{
+ memcpy(p, a, *lengths);
+}
+
+#endif
+
+template<typename... Args>
+gcc_malloc gcc_nonnull_all
+static inline char *
+t_xstrcatdup(Args&&... args)
+{
+#if CLANG_OR_GCC_VERSION(4,7)
+ constexpr size_t n = sizeof...(args);
+
+ size_t lengths[n];
+ const size_t total = FillLengths(lengths, args...);
+
+ char *p = (char *)xalloc(total + 1);
+ StringCat(p, lengths, args...);
+ p[total] = 0;
+ return p;
+#else
+ /* fallback implementation for gcc 4.6, because that old
+ compiler is too buggy to compile the above template
+ functions */
+ const char *const argv[] = { args... };
+
+ size_t total = 0;
+ for (auto i : argv)
+ total += strlen(i);
+
+ char *p = (char *)xalloc(total + 1), *q = p;
+ for (auto i : argv)
+ q = stpcpy(q, i);
+
+ return p;
+#endif
+}
+
+char *
+xstrcatdup(const char *a, const char *b)
+{
+ return t_xstrcatdup(a, b);
+}
+
+char *
+xstrcatdup(const char *a, const char *b, const char *c)
+{
+ return t_xstrcatdup(a, b, c);
+}
+
+char *
+xstrcatdup(const char *a, const char *b, const char *c, const char *d)
+{
+ return t_xstrcatdup(a, b, c, d);
+}
diff --git a/src/util/Alloc.hxx b/src/util/Alloc.hxx
index 15c123b7a..9e1007e69 100644
--- a/src/util/Alloc.hxx
+++ b/src/util/Alloc.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -64,4 +64,23 @@ gcc_malloc gcc_nonnull_all
char *
xstrndup(const char *s, size_t n);
+/**
+ * Concatenate two strings, returning a new allocation. Use free() to
+ * free it.
+ *
+ * This function never fails; in out-of-memory situations, it aborts
+ * the process.
+ */
+gcc_malloc gcc_nonnull_all
+char *
+xstrcatdup(const char *a, const char *b);
+
+gcc_malloc gcc_nonnull_all
+char *
+xstrcatdup(const char *a, const char *b, const char *c);
+
+gcc_malloc gcc_nonnull_all
+char *
+xstrcatdup(const char *a, const char *b, const char *c, const char *d);
+
#endif
diff --git a/src/util/AllocatedString.cxx b/src/util/AllocatedString.cxx
new file mode 100644
index 000000000..486462fa4
--- /dev/null
+++ b/src/util/AllocatedString.cxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "AllocatedString.hxx"
+#include "StringAPI.hxx"
+
+template<>
+AllocatedString<char>
+AllocatedString<char>::Duplicate(const_pointer src)
+{
+ return Duplicate(src, StringLength(src));
+}
diff --git a/src/util/AllocatedString.hxx b/src/util/AllocatedString.hxx
new file mode 100644
index 000000000..01eefac8a
--- /dev/null
+++ b/src/util/AllocatedString.hxx
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 ALLOCATED_STRING_HXX
+#define ALLOCATED_STRING_HXX
+
+#include "StringPointer.hxx"
+
+#include <utility>
+#include <algorithm>
+
+/**
+ * A string pointer whose memory is managed by this class.
+ *
+ * Unlike std::string, this object can hold a "nullptr" special value.
+ */
+template<typename T=char>
+class AllocatedString {
+public:
+ typedef typename StringPointer<T>::value_type value_type;
+ typedef typename StringPointer<T>::pointer pointer;
+ typedef typename StringPointer<T>::const_pointer const_pointer;
+
+ static constexpr value_type SENTINEL = '\0';
+
+private:
+ pointer value;
+
+ explicit AllocatedString(pointer _value)
+ :value(_value) {}
+
+public:
+ AllocatedString(std::nullptr_t n):value(n) {}
+
+ AllocatedString(AllocatedString &&src)
+ :value(src.Steal()) {}
+
+ ~AllocatedString() {
+ delete[] value;
+ }
+
+ static AllocatedString Donate(pointer value) {
+ return AllocatedString(value);
+ }
+
+ static AllocatedString Null() {
+ return nullptr;
+ }
+
+ static AllocatedString Empty() {
+ auto p = new value_type[1];
+ p[0] = SENTINEL;
+ return Donate(p);
+ }
+
+ static AllocatedString Duplicate(const_pointer src);
+
+ static AllocatedString Duplicate(const_pointer begin,
+ const_pointer end) {
+ auto p = new value_type[end - begin + 1];
+ *std::copy(begin, end, p) = SENTINEL;
+ return Donate(p);
+ }
+
+ static AllocatedString Duplicate(const_pointer begin,
+ size_t length) {
+ auto p = new value_type[length + 1];
+ *std::copy_n(begin, length, p) = SENTINEL;
+ return Donate(p);
+ }
+
+ AllocatedString &operator=(AllocatedString &&src) {
+ std::swap(value, src.value);
+ return *this;
+ }
+
+ constexpr bool IsNull() const {
+ return value == nullptr;
+ }
+
+ constexpr const_pointer c_str() const {
+ return value;
+ }
+
+ bool empty() const {
+ return *value == SENTINEL;
+ }
+
+ pointer Steal() {
+ pointer result = value;
+ value = nullptr;
+ return result;
+ }
+
+ AllocatedString Clone() const {
+ return Duplicate(c_str());
+ }
+};
+
+#endif
diff --git a/src/util/ByteReverse.cxx b/src/util/ByteReverse.cxx
index 5cc8692a7..c0c2946ca 100644
--- a/src/util/ByteReverse.cxx
+++ b/src/util/ByteReverse.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/ByteReverse.hxx b/src/util/ByteReverse.hxx
index 0c060c0cb..55d6a64db 100644
--- a/src/util/ByteReverse.hxx
+++ b/src/util/ByteReverse.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/Cast.hxx b/src/util/Cast.hxx
index 887137da4..647171970 100644
--- a/src/util/Cast.hxx
+++ b/src/util/Cast.hxx
@@ -84,7 +84,7 @@ ContainerAttributeOffset(const A C::*p)
* Cast the given pointer to a struct member to its parent structure.
*/
template<class C, class A>
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline C &
@@ -97,7 +97,7 @@ ContainerCast(A &a, A C::*member)
* Cast the given pointer to a struct member to its parent structure.
*/
template<class C, class A>
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
constexpr
#endif
static inline const C &
diff --git a/src/util/CharUtil.hxx b/src/util/CharUtil.hxx
index 84a88a94e..efd40896a 100644
--- a/src/util/CharUtil.hxx
+++ b/src/util/CharUtil.hxx
@@ -128,7 +128,7 @@ ToUpperASCII(char ch)
/**
* Convert the specified ASCII character (0x00..0x7f) to lower case.
- * Unlike toupper(), it ignores the system locale.
+ * Unlike tolower(), it ignores the system locale.
*/
constexpr
static inline char
diff --git a/src/util/ConstBuffer.hxx b/src/util/ConstBuffer.hxx
index 4d0a49e98..b98a8b543 100644
--- a/src/util/ConstBuffer.hxx
+++ b/src/util/ConstBuffer.hxx
@@ -246,6 +246,20 @@ struct ConstBuffer {
data += n;
size -= n;
}
+
+ /**
+ * Move the front pointer to the given address, and adjust the
+ * size attribute to retain the old end address.
+ */
+ void MoveFront(pointer_type new_data) {
+#ifndef NDEBUG
+ assert(IsNull() == (new_data == nullptr));
+ assert(new_data <= end());
+#endif
+
+ size = end() - new_data;
+ data = new_data;
+ }
};
#endif
diff --git a/src/util/DeleteDisposer.hxx b/src/util/DeleteDisposer.hxx
new file mode 100644
index 000000000..dd91e1299
--- /dev/null
+++ b/src/util/DeleteDisposer.hxx
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 DELETE_DISPOSER_HXX
+#define DELETE_DISPOSER_HXX
+
+/**
+ * A disposer for boost::intrusive that invokes the "delete" operator
+ * on the given pointer.
+ */
+struct DeleteDisposer {
+ template<typename T>
+ void operator()(T *t) {
+ delete t;
+ }
+};
+
+#endif
diff --git a/src/util/DivideString.cxx b/src/util/DivideString.cxx
new file mode 100644
index 000000000..8e3d5a1b8
--- /dev/null
+++ b/src/util/DivideString.cxx
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "DivideString.hxx"
+#include "StringUtil.hxx"
+
+#include <string.h>
+
+DivideString::DivideString(const char *s, char separator, bool strip)
+ :first(nullptr)
+{
+ const char *x = strchr(s, separator);
+ if (x == nullptr)
+ return;
+
+ size_t length = x - s;
+ second = x + 1;
+
+ if (strip)
+ second = StripLeft(second);
+
+ if (strip) {
+ const char *end = s + length;
+ s = StripLeft(s);
+ end = StripRight(s, end);
+ length = end - s;
+ }
+
+ first = new char[length + 1];
+ memcpy(first, s, length);
+ first[length] = 0;
+}
diff --git a/src/util/DivideString.hxx b/src/util/DivideString.hxx
new file mode 100644
index 000000000..d98b512a6
--- /dev/null
+++ b/src/util/DivideString.hxx
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_DIVIDE_STRING_HXX
+#define MPD_DIVIDE_STRING_HXX
+
+#include "Compiler.h"
+
+#include <assert.h>
+
+/**
+ * Split a given constant string at a separator character. Duplicates
+ * the first part to be able to null-terminate it.
+ */
+class DivideString {
+ char *first;
+ const char *second;
+
+public:
+ /**
+ * @param strip strip the first part and left-strip the second
+ * part?
+ */
+ DivideString(const char *s, char separator, bool strip=false);
+
+ ~DivideString() {
+ delete[] first;
+ }
+
+ /**
+ * Was the separator found?
+ */
+ bool IsDefined() const {
+ return first != nullptr;
+ }
+
+ /**
+ * Is the first part empty?
+ */
+ bool IsEmpty() const {
+ assert(IsDefined());
+
+ return *first == 0;
+ }
+
+ const char *GetFirst() const {
+ assert(IsDefined());
+
+ return first;
+ }
+
+ const char *GetSecond() const {
+ assert(IsDefined());
+
+ return second;
+ }
+};
+
+#endif
diff --git a/src/util/DynamicFifoBuffer.hxx b/src/util/DynamicFifoBuffer.hxx
index c1e5d1b94..5a9056edb 100644
--- a/src/util/DynamicFifoBuffer.hxx
+++ b/src/util/DynamicFifoBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2013 Max Kellermann <max@duempel.org>
+ * Copyright (C) 2003-2015 Max Kellermann <max@duempel.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,8 +27,8 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef FIFO_BUFFER_HPP
-#define FIFO_BUFFER_HPP
+#ifndef DYNAMIC_FIFO_BUFFER_HXX
+#define DYNAMIC_FIFO_BUFFER_HXX
#include "ForeignFifoBuffer.hxx"
diff --git a/src/util/Error.cxx b/src/util/Error.cxx
index 92b2cc5d0..67a1b03fd 100644
--- a/src/util/Error.cxx
+++ b/src/util/Error.cxx
@@ -32,7 +32,7 @@
#include "Domain.hxx"
#ifdef WIN32
-#include <glib.h>
+#include <windows.h>
#endif
#include <errno.h>
@@ -135,7 +135,11 @@ Error::FormatErrno(const char *fmt, ...)
void
Error::SetLastError(DWORD _code, const char *prefix)
{
- const char *msg = g_win32_error_message(_code);
+ char msg[256];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, _code, 0, msg, sizeof(msg), nullptr);
+
Format(win32_domain, int(_code), "%s: %s", prefix, msg);
}
diff --git a/src/util/FormatString.cxx b/src/util/FormatString.cxx
index d222a505c..5ada067cb 100644
--- a/src/util/FormatString.cxx
+++ b/src/util/FormatString.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/FormatString.hxx b/src/util/FormatString.hxx
index dc1ac3c67..b0f8dd7f9 100644
--- a/src/util/FormatString.hxx
+++ b/src/util/FormatString.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/LazyRandomEngine.cxx b/src/util/LazyRandomEngine.cxx
index b0aac913c..abd83da8c 100644
--- a/src/util/LazyRandomEngine.cxx
+++ b/src/util/LazyRandomEngine.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/LazyRandomEngine.hxx b/src/util/LazyRandomEngine.hxx
index 4156b3bb1..7b9b1c655 100644
--- a/src/util/LazyRandomEngine.hxx
+++ b/src/util/LazyRandomEngine.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/Manual.hxx b/src/util/Manual.hxx
index 75cffac06..6ba932bdd 100644
--- a/src/util/Manual.hxx
+++ b/src/util/Manual.hxx
@@ -41,7 +41,7 @@
#include <assert.h>
-#if defined(__clang__) || GCC_CHECK_VERSION(4,7)
+#if CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
@@ -54,12 +54,7 @@
*/
template<class T>
class Manual {
-#if GCC_OLDER_THAN(4,8)
- /* no alignas() on gcc < 4.8: apply worst-case fallback */
- __attribute__((aligned(8)))
-#else
- alignas(T)
-#endif
+ gcc_alignas(T, 8)
char data[sizeof(T)];
#ifndef NDEBUG
@@ -89,32 +84,46 @@ public:
void Destruct() {
assert(initialized);
- T *t = (T *)data;
- t->T::~T();
+ T &t = Get();
+ t.T::~T();
#ifndef NDEBUG
initialized = false;
#endif
}
+ T &Get() {
+ assert(initialized);
+
+ void *p = static_cast<void *>(data);
+ return *static_cast<T *>(p);
+ }
+
+ const T &Get() const {
+ assert(initialized);
+
+ const void *p = static_cast<const void *>(data);
+ return *static_cast<const T *>(p);
+ }
+
operator T &() {
- return *(T *)data;
+ return Get();
}
operator const T &() const {
- return *(const T *)data;
+ return Get();
}
T *operator->() {
- return (T *)data;
+ return &Get();
}
const T *operator->() const {
- return (T *)data;
+ return &Get();
}
};
-#if defined(__clang__) || GCC_VERSION >= 40700
+#if CLANG_OR_GCC_VERSION(4,7)
#pragma GCC diagnostic pop
#endif
diff --git a/src/util/OptionDef.hxx b/src/util/OptionDef.hxx
index dd82154c4..29b7e268b 100644
--- a/src/util/OptionDef.hxx
+++ b/src/util/OptionDef.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/OptionParser.cxx b/src/util/OptionParser.cxx
index b10008527..45be084c9 100644
--- a/src/util/OptionParser.cxx
+++ b/src/util/OptionParser.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/OptionParser.hxx b/src/util/OptionParser.hxx
index b9d34adbb..c6c794a7d 100644
--- a/src/util/OptionParser.hxx
+++ b/src/util/OptionParser.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/PeakBuffer.cxx b/src/util/PeakBuffer.cxx
index e4624bbec..da3b275d8 100644
--- a/src/util/PeakBuffer.cxx
+++ b/src/util/PeakBuffer.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/PeakBuffer.hxx b/src/util/PeakBuffer.hxx
index 702a3dee0..784b3cdbd 100644
--- a/src/util/PeakBuffer.hxx
+++ b/src/util/PeakBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/RefCount.hxx b/src/util/RefCount.hxx
index 02ef8818c..c6cf2e41f 100644
--- a/src/util/RefCount.hxx
+++ b/src/util/RefCount.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* Redistribution and use in source and binary forms, with or without
diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx
index 63ca087ae..16c1cf744 100644
--- a/src/util/SliceBuffer.hxx
+++ b/src/util/SliceBuffer.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/SplitString.cxx b/src/util/SplitString.cxx
index 75e799279..9588312f8 100644
--- a/src/util/SplitString.cxx
+++ b/src/util/SplitString.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,20 +18,42 @@
*/
#include "SplitString.hxx"
+#include "StringUtil.hxx"
#include <string.h>
-SplitString::SplitString(const char *s, char separator)
- :first(nullptr)
+std::forward_list<std::string>
+SplitString(const char *s, char separator, bool strip)
{
- const char *x = strchr(s, separator);
- if (x == nullptr)
- return;
+ if (strip)
+ s = StripLeft(s);
- size_t length = x - s;
- second = x + 1;
+ std::forward_list<std::string> list;
+ if (*s == 0)
+ return list;
- first = new char[length + 1];
- memcpy(first, s, length);
- first[length] = 0;
+ auto i = list.before_begin();
+
+ while (true) {
+ const char *next = strchr(s, separator);
+ if (next == nullptr)
+ break;
+
+ const char *end = next++;
+ if (strip)
+ end = StripRight(s, end);
+
+ i = list.emplace_after(i, s, end);
+
+ s = next;
+ if (strip)
+ s = StripLeft(s);
+ }
+
+ const char *end = s + strlen(s);
+ if (strip)
+ end = StripRight(s, end);
+
+ list.emplace_after(i, s, end);
+ return list;
}
diff --git a/src/util/SplitString.hxx b/src/util/SplitString.hxx
index 96ffb21ec..545470c7a 100644
--- a/src/util/SplitString.hxx
+++ b/src/util/SplitString.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,52 +20,20 @@
#ifndef MPD_SPLIT_STRING_HXX
#define MPD_SPLIT_STRING_HXX
-#include "Compiler.h"
-
-#include <assert.h>
+#include <forward_list>
+#include <string>
/**
- * Split a given constant string at a separator character. Duplicates
- * the first part to be able to null-terminate it.
+ * Split a string at a certain separator character into sub strings
+ * and returns a list of these.
+ *
+ * Two consecutive separator characters result in an empty string in
+ * the list.
+ *
+ * An empty input string, as a special case, results in an empty list
+ * (and not a list with an empty string).
*/
-class SplitString {
- char *first;
- const char *second;
-
-public:
- SplitString(const char *s, char separator);
-
- ~SplitString() {
- delete[] first;
- }
-
- /**
- * Was the separator found?
- */
- bool IsDefined() const {
- return first != nullptr;
- }
-
- /**
- * Is the first part empty?
- */
- bool IsEmpty() const {
- assert(IsDefined());
-
- return *first == 0;
- }
-
- const char *GetFirst() const {
- assert(IsDefined());
-
- return first;
- }
-
- const char *GetSecond() const {
- assert(IsDefined());
-
- return second;
- }
-};
+std::forward_list<std::string>
+SplitString(const char *s, char separator, bool strip=true);
#endif
diff --git a/src/util/StringAPI.hxx b/src/util/StringAPI.hxx
new file mode 100644
index 000000000..08087f5f8
--- /dev/null
+++ b/src/util/StringAPI.hxx
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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_API_HXX
+#define STRING_API_HXX
+
+#include "Compiler.h"
+
+#include <string.h>
+
+#ifdef _UNICODE
+#include "WStringAPI.hxx"
+#endif
+
+gcc_pure gcc_nonnull_all
+static inline size_t
+StringLength(const char *p)
+{
+ return strlen(p);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const char *
+StringFind(const char *haystack, const char *needle)
+{
+ return strstr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline char *
+StringFind(char *haystack, char needle, size_t size)
+{
+ return (char *)memchr(haystack, needle, size);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const char *
+StringFind(const char *haystack, char needle, size_t size)
+{
+ return (const char *)memchr(haystack, needle, size);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const char *
+StringFind(const char *haystack, char needle)
+{
+ return strchr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline char *
+StringFind(char *haystack, char needle)
+{
+ return strchr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const char *
+StringFindLast(const char *haystack, char needle)
+{
+ return strrchr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline char *
+StringFindLast(char *haystack, char needle)
+{
+ return strrchr(haystack, needle);
+}
+
+gcc_nonnull_all
+static inline void
+UnsafeCopyString(char *dest, const char *src)
+{
+ strcpy(dest, src);
+}
+
+gcc_nonnull_all
+static inline char *
+UnsafeCopyStringP(char *dest, const char *src)
+{
+#if defined(WIN32) || defined(__BIONIC__)
+ /* emulate stpcpy() */
+ UnsafeCopyString(dest, src);
+ return dest + StringLength(dest);
+#else
+ return stpcpy(dest, src);
+#endif
+}
+
+/**
+ * Checks whether #a and #b are equal.
+ */
+gcc_pure gcc_nonnull_all
+static inline bool
+StringIsEqual(const char *a, const char *b)
+{
+ return strcmp(a, b) == 0;
+}
+
+/**
+ * Checks whether #a and #b are equal.
+ */
+gcc_pure gcc_nonnull_all
+static inline bool
+StringIsEqual(const char *a, const char *b, size_t length)
+{
+ return strncmp(a, b, length) == 0;
+}
+
+/**
+ * Copy the string to a new allocation. The return value must be
+ * freed with free().
+ */
+gcc_malloc gcc_nonnull_all
+static inline char *
+DuplicateString(const char *p)
+{
+ return strdup(p);
+}
+
+#endif
diff --git a/src/util/StringPointer.hxx b/src/util/StringPointer.hxx
new file mode 100644
index 000000000..4859d8265
--- /dev/null
+++ b/src/util/StringPointer.hxx
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 Max Kellermann <max@duempel.org>
+ *
+ * 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_POINTER_HXX
+#define STRING_POINTER_HXX
+
+/**
+ * Simple OO wrapper for a const string pointer.
+ */
+template<typename T=char>
+class StringPointer {
+public:
+ typedef T value_type;
+ typedef T *pointer;
+ typedef const T *const_pointer;
+
+private:
+ const_pointer value;
+
+public:
+ StringPointer() = default;
+ constexpr StringPointer(const_pointer _value)
+ :value(_value) {}
+
+ /**
+ * Check if this is a "nulled" instance. A "nulled" instance
+ * must not be used.
+ */
+ constexpr bool IsNull() const {
+ return value == nullptr;
+ }
+
+ constexpr const_pointer c_str() const {
+ return value;
+ }
+};
+
+#endif
diff --git a/src/util/StringUtil.cxx b/src/util/StringUtil.cxx
index bcade2b3b..b9c99eb4a 100644
--- a/src/util/StringUtil.cxx
+++ b/src/util/StringUtil.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
*/
#include "StringUtil.hxx"
+#include "StringAPI.hxx"
#include "CharUtil.hxx"
#include "ASCII.hxx"
@@ -26,6 +27,66 @@
#include <assert.h>
#include <string.h>
+bool
+StringStartsWith(const char *haystack, const char *needle)
+{
+ const size_t length = strlen(needle);
+ return memcmp(haystack, needle, length) == 0;
+}
+
+bool
+StringEndsWith(const char *haystack, const char *needle)
+{
+ const size_t haystack_length = strlen(haystack);
+ const size_t needle_length = strlen(needle);
+
+ return haystack_length >= needle_length &&
+ memcmp(haystack + haystack_length - needle_length,
+ needle, needle_length) == 0;
+}
+
+const char *
+StringAfterPrefix(const char *string, const char *prefix)
+{
+#if !CLANG_CHECK_VERSION(3,6)
+ /* disabled on clang due to -Wtautological-pointer-compare */
+ assert(string != nullptr);
+ assert(prefix != nullptr);
+#endif
+
+ size_t prefix_length = strlen(prefix);
+ return StringIsEqual(string, prefix, prefix_length)
+ ? string + prefix_length
+ : nullptr;
+}
+
+const char *
+FindStringSuffix(const char *p, const char *suffix)
+{
+ const size_t p_length = strlen(p);
+ const size_t suffix_length = strlen(suffix);
+
+ if (p_length < suffix_length)
+ return nullptr;
+
+ const char *q = p + p_length - suffix_length;
+ return memcmp(q, suffix, suffix_length) == 0
+ ? q
+ : nullptr;
+}
+
+char *
+CopyString(char *gcc_restrict dest, const char *gcc_restrict src, size_t size)
+{
+ size_t length = strlen(src);
+ if (length >= size)
+ length = size - 1;
+
+ char *p = std::copy_n(src, length, dest);
+ *p = '\0';
+ return p;
+}
+
const char *
StripLeft(const char *p)
{
@@ -79,36 +140,6 @@ Strip(char *p)
}
bool
-StringStartsWith(const char *haystack, const char *needle)
-{
- const size_t length = strlen(needle);
- return memcmp(haystack, needle, length) == 0;
-}
-
-bool
-StringEndsWith(const char *haystack, const char *needle)
-{
- const size_t haystack_length = strlen(haystack);
- const size_t needle_length = strlen(needle);
-
- return haystack_length >= needle_length &&
- memcmp(haystack + haystack_length - needle_length,
- needle, needle_length) == 0;
-}
-
-char *
-CopyString(char *gcc_restrict dest, const char *gcc_restrict src, size_t size)
-{
- size_t length = strlen(src);
- if (length >= size)
- length = size - 1;
-
- char *p = std::copy(src, src + length, dest);
- *p = '\0';
- return p;
-}
-
-bool
string_array_contains(const char *const* haystack, const char *needle)
{
assert(haystack != nullptr);
@@ -120,3 +151,23 @@ string_array_contains(const char *const* haystack, const char *needle)
return false;
}
+
+void
+ToUpperASCII(char *dest, const char *src, size_t size)
+{
+ assert(dest != nullptr);
+ assert(src != nullptr);
+ assert(size > 1);
+
+ char *const end = dest + size - 1;
+
+ do {
+ char ch = *src++;
+ if (ch == 0)
+ break;
+
+ *dest++ = ToUpperASCII(ch);
+ } while (dest < end);
+
+ *dest = 0;
+}
diff --git a/src/util/StringUtil.hxx b/src/util/StringUtil.hxx
index 9beda5441..7e6dc4d61 100644
--- a/src/util/StringUtil.hxx
+++ b/src/util/StringUtil.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,47 @@
#include <stddef.h>
+#ifdef _UNICODE
+#include "WStringUtil.hxx"
+#endif
+
+gcc_pure
+bool
+StringStartsWith(const char *haystack, const char *needle);
+
+gcc_pure
+bool
+StringEndsWith(const char *haystack, const char *needle);
+
+/**
+ * Returns the portion of the string after a prefix. If the string
+ * does not begin with the specified prefix, this function returns
+ * nullptr.
+ */
+gcc_pure gcc_nonnull_all
+const char *
+StringAfterPrefix(const char *string, const char *prefix);
+
+/**
+ * Check if the given string ends with the specified suffix. If yes,
+ * returns the position of the suffix, and nullptr otherwise.
+ */
+gcc_pure
+const char *
+FindStringSuffix(const char *p, const char *suffix);
+
+/**
+ * Copy a string. If the buffer is too small, then the string is
+ * truncated. This is a safer version of strncpy().
+ *
+ * @param size the size of the destination buffer (including the null
+ * terminator)
+ * @return a pointer to the null terminator
+ */
+gcc_nonnull_all
+char *
+CopyString(char *dest, const char *src, size_t size);
+
/**
* Returns a pointer to the first non-whitespace character in the
* string, or to the end of the string.
@@ -82,26 +123,6 @@ StripRight(char *p);
char *
Strip(char *p);
-gcc_pure
-bool
-StringStartsWith(const char *haystack, const char *needle);
-
-gcc_pure
-bool
-StringEndsWith(const char *haystack, const char *needle);
-
-/**
- * Copy a string. If the buffer is too small, then the string is
- * truncated. This is a safer version of strncpy().
- *
- * @param size the size of the destination buffer (including the null
- * terminator)
- * @return a pointer to the null terminator
- */
-gcc_nonnull_all
-char *
-CopyString(char *dest, const char *src, size_t size);
-
/**
* Checks whether a string array contains the specified string.
*
@@ -114,4 +135,12 @@ gcc_pure
bool
string_array_contains(const char *const* haystack, const char *needle);
+/**
+ * Convert the specified ASCII string (0x00..0x7f) to upper case.
+ *
+ * @param size the destination buffer size
+ */
+void
+ToUpperASCII(char *dest, const char *src, size_t size);
+
#endif
diff --git a/src/util/StringView.cxx b/src/util/StringView.cxx
new file mode 100644
index 000000000..904f92f65
--- /dev/null
+++ b/src/util/StringView.cxx
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2013-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 "StringView.hxx"
+#include "CharUtil.hxx"
+
+void
+StringView::StripLeft()
+{
+ while (!IsEmpty() && IsWhitespaceOrNull(front()))
+ pop_front();
+}
+
+void
+StringView::StripRight()
+{
+ while (!IsEmpty() && IsWhitespaceOrNull(back()))
+ pop_back();
+}
diff --git a/src/util/StringView.hxx b/src/util/StringView.hxx
new file mode 100644
index 000000000..dd6c4dc77
--- /dev/null
+++ b/src/util/StringView.hxx
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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_VIEW_HXX
+#define STRING_VIEW_HXX
+
+#include "ConstBuffer.hxx"
+
+#include <string.h>
+
+struct StringView : ConstBuffer<char> {
+ StringView() = default;
+
+ constexpr StringView(pointer_type _data, size_type _size)
+ :ConstBuffer<char>(_data, _size) {}
+
+ constexpr StringView(pointer_type _begin, pointer_type _end)
+ :ConstBuffer<char>(_begin, _end - _begin) {}
+
+ StringView(pointer_type _data)
+ :ConstBuffer<char>(_data,
+ _data != nullptr ? strlen(_data) : 0) {}
+
+ StringView(std::nullptr_t n)
+ :ConstBuffer<char>(n) {}
+
+ static constexpr StringView Empty() {
+ return StringView("", size_t(0));
+ }
+
+ void SetEmpty() {
+ data = "";
+ size = 0;
+ }
+
+ gcc_pure
+ pointer_type Find(char ch) const {
+ return (pointer_type)memchr(data, ch, size);
+ }
+
+ StringView &operator=(std::nullptr_t) {
+ data = nullptr;
+ size = 0;
+ return *this;
+ }
+
+ StringView &operator=(pointer_type _data) {
+ data = _data;
+ size = _data != nullptr ? strlen(_data) : 0;
+ return *this;
+ }
+
+ gcc_pure
+ bool StartsWith(StringView needle) const {
+ return size >= needle.size &&
+ memcmp(data, needle.data, needle.size) == 0;
+ }
+
+ gcc_pure
+ bool Equals(StringView other) const {
+ return size == other.size &&
+ memcmp(data, other.data, size) == 0;
+ }
+
+ template<size_t n>
+ bool EqualsLiteral(const char (&other)[n]) const {
+ return Equals({other, n - 1});
+ }
+
+ gcc_pure
+ bool EqualsIgnoreCase(StringView other) const {
+ return size == other.size &&
+ strncasecmp(data, other.data, size) == 0;
+ }
+
+ template<size_t n>
+ bool EqualsLiteralIgnoreCase(const char (&other)[n]) const {
+ return EqualsIgnoreCase({other, n - 1});
+ }
+
+ /**
+ * Skip all whitespace at the beginning.
+ */
+ void StripLeft();
+
+ /**
+ * Skip all whitespace at the end.
+ */
+ void StripRight();
+};
+
+#endif
diff --git a/src/util/Tokenizer.hxx b/src/util/Tokenizer.hxx
index dc2646589..3f3448d52 100644
--- a/src/util/Tokenizer.hxx
+++ b/src/util/Tokenizer.hxx
@@ -71,7 +71,7 @@ public:
/**
* Reads the next unquoted word from the input string.
*
- * @param error_r if this function returns nullptr and **input_p!=0, it
+ * @param error if this function returns nullptr and **input_p!=0, it
* provides an #Error object in this argument
* @return a pointer to the null-terminated word, or nullptr
* on error or end of line
@@ -83,9 +83,7 @@ public:
* escapes the following character. This function modifies the input
* string.
*
- * @param input_p the input string; this function returns a pointer to
- * the first non-whitespace character of the following token
- * @param error_r if this function returns nullptr and **input_p!=0, it
+ * @param error if this function returns nullptr and **input_p!=0, it
* provides an #Error object in this argument
* @return a pointer to the null-terminated string, or nullptr on error
* or end of line
@@ -97,7 +95,7 @@ public:
* input. This is a wrapper for NextUnquoted() and
* NextString().
*
- * @param error_r if this function returns nullptr and
+ * @param error if this function returns nullptr and
* **input_p!=0, it provides an #Error object in
* this argument
* @return a pointer to the null-terminated string, or nullptr
diff --git a/src/util/UriUtil.cxx b/src/util/UriUtil.cxx
index 54d0ded77..0782304e3 100644
--- a/src/util/UriUtil.cxx
+++ b/src/util/UriUtil.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/UriUtil.hxx b/src/util/UriUtil.hxx
index d478d5b92..e8edfb5a0 100644
--- a/src/util/UriUtil.hxx
+++ b/src/util/UriUtil.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/VarSize.hxx b/src/util/VarSize.hxx
index 04f1bf580..4da115fba 100644
--- a/src/util/VarSize.hxx
+++ b/src/util/VarSize.hxx
@@ -42,7 +42,7 @@
* example when you want to store a variable-length string as the last
* attribute without the overhead of a second allocation.
*
- * @param T a struct/class with a variable-size last attribute
+ * @tparam T a struct/class with a variable-size last attribute
* @param declared_tail_size the declared size of the last element in
* #T
* @param real_tail_size the real required size of the last element in
diff --git a/src/util/WStringAPI.hxx b/src/util/WStringAPI.hxx
new file mode 100644
index 000000000..e020ecd7f
--- /dev/null
+++ b/src/util/WStringAPI.hxx
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010-2015 Max Kellermann <max@duempel.org>
+ *
+ * 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 WSTRING_API_HXX
+#define WSTRING_API_HXX
+
+#include "Compiler.h"
+
+#include <wchar.h>
+
+gcc_pure gcc_nonnull_all
+static inline size_t
+StringLength(const wchar_t *p)
+{
+ return wcslen(p);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const wchar_t *
+StringFind(const wchar_t *haystack, const wchar_t *needle)
+{
+ return wcsstr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const wchar_t *
+StringFind(const wchar_t *haystack, wchar_t needle, size_t size)
+{
+ return wmemchr(haystack, needle, size);
+}
+
+gcc_pure gcc_nonnull_all
+static inline wchar_t *
+StringFind(wchar_t *haystack, wchar_t needle, size_t size)
+{
+ return wmemchr(haystack, needle, size);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const wchar_t *
+StringFind(const wchar_t *haystack, wchar_t needle)
+{
+ return wcschr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline wchar_t *
+StringFind(wchar_t *haystack, wchar_t needle)
+{
+ return wcschr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline const wchar_t *
+StringFindLast(const wchar_t *haystack, wchar_t needle)
+{
+ return wcsrchr(haystack, needle);
+}
+
+gcc_pure gcc_nonnull_all
+static inline wchar_t *
+StringFindLast(wchar_t *haystack, wchar_t needle)
+{
+ return wcsrchr(haystack, needle);
+}
+
+gcc_nonnull_all
+static inline void
+UnsafeCopyString(wchar_t *dest, const wchar_t *src)
+{
+ wcscpy(dest, src);
+}
+
+gcc_nonnull_all
+static inline wchar_t *
+UnsafeCopyStringP(wchar_t *dest, const wchar_t *src)
+{
+#if defined(WIN32) || defined(__BIONIC__)
+ /* emulate wcpcpy() */
+ UnsafeCopyString(dest, src);
+ return dest + StringLength(dest);
+#else
+ return wcpcpy(dest, src);
+#endif
+}
+
+/**
+ * Checks whether str1 and str2 are equal.
+ * @param str1 String 1
+ * @param str2 String 2
+ * @return True if equal, False otherwise
+ */
+gcc_pure gcc_nonnull_all
+static inline bool
+StringIsEqual(const wchar_t *str1, const wchar_t *str2)
+{
+ return wcscmp(str1, str2) == 0;
+}
+
+/**
+ * Checks whether #a and #b are equal.
+ */
+gcc_pure gcc_nonnull_all
+static inline bool
+StringIsEqual(const wchar_t *a, const wchar_t *b, size_t length)
+{
+ return wcsncmp(a, b, length) == 0;
+}
+
+#ifndef __BIONIC__
+
+gcc_malloc gcc_nonnull_all
+static inline wchar_t *
+DuplicateString(const wchar_t *p)
+{
+ return wcsdup(p);
+}
+
+#endif
+
+#endif
diff --git a/src/util/WStringUtil.cxx b/src/util/WStringUtil.cxx
new file mode 100644
index 000000000..19e4fc68d
--- /dev/null
+++ b/src/util/WStringUtil.cxx
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "WStringUtil.hxx"
+#include "WStringAPI.hxx"
+#include "ASCII.hxx"
+
+#include <algorithm>
+
+#include <assert.h>
+#include <string.h>
+
+bool
+StringStartsWith(const wchar_t *haystack, const wchar_t *needle)
+{
+ return memcmp(haystack, needle, StringLength(needle) * sizeof(needle[0])) == 0;
+}
+
+bool
+StringEndsWith(const wchar_t *haystack, const wchar_t *needle)
+{
+ const size_t haystack_length = StringLength(haystack);
+ const size_t needle_length = StringLength(needle);
+
+ return haystack_length >= needle_length &&
+ StringIsEqual(haystack + haystack_length - needle_length, needle);
+}
+
+const wchar_t *
+StringAfterPrefix(const wchar_t *string, const wchar_t *prefix)
+{
+#if !CLANG_CHECK_VERSION(3,6)
+ /* disabled on clang due to -Wtautological-pointer-compare */
+ assert(string != nullptr);
+ assert(prefix != nullptr);
+#endif
+
+ size_t prefix_length = StringLength(prefix);
+ return StringIsEqual(string, prefix, prefix_length)
+ ? string + prefix_length
+ : nullptr;
+}
+
+const wchar_t *
+FindStringSuffix(const wchar_t *p, const wchar_t *suffix)
+{
+ const size_t p_length = StringLength(p);
+ const size_t suffix_length = StringLength(suffix);
+
+ if (p_length < suffix_length)
+ return nullptr;
+
+ const auto *q = p + p_length - suffix_length;
+ return memcmp(q, suffix, suffix_length * sizeof(*suffix)) == 0
+ ? q
+ : nullptr;
+}
diff --git a/src/util/WStringUtil.hxx b/src/util/WStringUtil.hxx
new file mode 100644
index 000000000..3dde0162e
--- /dev/null
+++ b/src/util/WStringUtil.hxx
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef WSTRING_UTIL_HXX
+#define WSTRING_UTIL_HXX
+
+#include "Compiler.h"
+
+#include <wchar.h>
+
+gcc_pure
+bool
+StringStartsWith(const wchar_t *haystack, const wchar_t *needle);
+
+gcc_pure
+bool
+StringEndsWith(const wchar_t *haystack, const wchar_t *needle);
+
+/**
+ * Returns the portion of the string after a prefix. If the string
+ * does not begin with the specified prefix, this function returns
+ * nullptr.
+ */
+gcc_nonnull_all
+const wchar_t *
+StringAfterPrefix(const wchar_t *string, const wchar_t *prefix);
+
+/**
+ * Check if the given string ends with the specified suffix. If yes,
+ * returns the position of the suffix, and nullptr otherwise.
+ */
+gcc_pure
+const wchar_t *
+FindStringSuffix(const wchar_t *p, const wchar_t *suffix);
+
+#endif
diff --git a/src/util/bit_reverse.c b/src/util/bit_reverse.c
index 9226c4261..271eee166 100644
--- a/src/util/bit_reverse.c
+++ b/src/util/bit_reverse.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/bit_reverse.h b/src/util/bit_reverse.h
index b39b02e92..f4d378e61 100644
--- a/src/util/bit_reverse.h
+++ b/src/util/bit_reverse.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/util/format.c b/src/util/format.c
new file mode 100644
index 000000000..66243c8ec
--- /dev/null
+++ b/src/util/format.c
@@ -0,0 +1,259 @@
+/*
+ * music player command (mpc)
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "format.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+/**
+ * Reallocate the given string and append the source string.
+ */
+gcc_malloc
+static char *
+string_append(char *dest, const char *src, size_t len)
+{
+ size_t destlen = dest != NULL
+ ? strlen(dest)
+ : 0;
+
+ dest = realloc(dest, destlen + len + 1);
+ memcpy(dest + destlen, src, len);
+ dest[destlen + len] = '\0';
+
+ return dest;
+}
+
+/**
+ * Skip the format string until the current group is closed by either
+ * '&', '|' or ']' (supports nesting).
+ */
+gcc_pure
+static const char *
+skip_format(const char *p)
+{
+ unsigned stack = 0;
+
+ while (*p != '\0') {
+ if (*p == '[')
+ stack++;
+ else if (*p == '#' && p[1] != '\0')
+ /* skip escaped stuff */
+ ++p;
+ else if (stack > 0) {
+ if (*p == ']')
+ --stack;
+ } else if (*p == '&' || *p == '|' || *p == ']')
+ break;
+
+ ++p;
+ }
+
+ return p;
+}
+
+static bool
+is_name_char(char ch)
+{
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
+ (ch >= '0' && ch <= '9') || ch == '_';
+}
+
+static char *
+format_object2(const char *format, const char **last, const void *object,
+ const char *(*getter)(const void *object, const char *name))
+{
+ char *ret = NULL;
+ const char *p;
+ bool found = false;
+
+ for (p = format; *p != '\0';) {
+ switch (p[0]) {
+ case '|':
+ ++p;
+ if (!found) {
+ /* nothing found yet: try the next
+ section */
+ free(ret);
+ ret = NULL;
+ } else
+ /* already found a value: skip the
+ next section */
+ p = skip_format(p);
+ break;
+
+ case '&':
+ ++p;
+ if (!found)
+ /* nothing found yet, so skip this
+ section */
+ p = skip_format(p);
+ else
+ /* we found something yet, but it will
+ only be used if the next section
+ also found something, so reset the
+ flag */
+ found = false;
+ break;
+
+ case '[': {
+ char *t = format_object2(p + 1, &p, object, getter);
+ if (t != NULL) {
+ ret = string_append(ret, t, strlen(t));
+ free(t);
+ found = true;
+ }
+ }
+ break;
+
+ case ']':
+ if (last != NULL)
+ *last = p + 1;
+ if (!found) {
+ free(ret);
+ ret = NULL;
+ }
+ return ret;
+
+ case '\\': {
+ /* take care of escape sequences */
+ char ltemp;
+ switch (p[1]) {
+ case 'a':
+ ltemp = '\a';
+ break;
+
+ case 'b':
+ ltemp = '\b';
+ break;
+
+ case 't':
+ ltemp = '\t';
+ break;
+
+ case 'n':
+ ltemp = '\n';
+ break;
+
+ case 'v':
+ ltemp = '\v';
+ break;
+
+ case 'f':
+ ltemp = '\f';
+ break;
+
+ case 'r':
+ ltemp = '\r';
+ break;
+
+ case '[':
+ case ']':
+ ltemp = p[1];
+ break;
+
+ default:
+ /* unknown escape: copy the
+ backslash */
+ ltemp = p[0];
+ --p;
+ break;
+ }
+
+ ret = string_append(ret, &ltemp, 1);
+ p += 2;
+ }
+ break;
+
+ case '%': {
+ /* find the extent of this format specifier
+ (stop at \0, ' ', or esc) */
+ const char *end = p + 1;
+ while (is_name_char(*end))
+ ++end;
+
+ const size_t length = end - p + 1;
+
+ if (*end != '%') {
+ ret = string_append(ret, p, length - 1);
+ p = end;
+ continue;
+ }
+
+ char name[32];
+ if (length > (int)sizeof(name)) {
+ ret = string_append(ret, p, length);
+ p = end + 1;
+ continue;
+ }
+
+ memcpy(name, p + 1, length - 2);
+ name[length - 2] = 0;
+
+ const char *value = getter(object, name);
+ size_t value_length;
+ if (value != NULL) {
+ if (*value != 0)
+ found = true;
+ value_length = strlen(value);
+ } else {
+ /* unknown variable: copy verbatim
+ from format string */
+ value = p;
+ value_length = length;
+ }
+
+ ret = string_append(ret, value, value_length);
+
+ /* advance past the specifier */
+ p = end + 1;
+ }
+ break;
+
+ case '#':
+ /* let the escape character escape itself */
+ if (p[1] != '\0') {
+ ret = string_append(ret, p + 1, 1);
+ p += 2;
+ break;
+ }
+
+ /* fall through */
+
+ default:
+ /* pass-through non-escaped portions of the format string */
+ ret = string_append(ret, p, 1);
+ ++p;
+ }
+ }
+
+ if (last != NULL)
+ *last = p;
+ return ret;
+}
+
+char *
+format_object(const char *format, const void *object,
+ const char *(*getter)(const void *object, const char *name))
+{
+ return format_object2(format, NULL, object, getter);
+}
diff --git a/src/util/format.h b/src/util/format.h
new file mode 100644
index 000000000..fa3624b51
--- /dev/null
+++ b/src/util/format.h
@@ -0,0 +1,51 @@
+/*
+ * music player command (mpc)
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPC_FORMAT_H
+#define MPC_FORMAT_H
+
+#include "Compiler.h"
+
+struct mpd_song;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Pretty-print an object into a string using the given format
+ * specification.
+ *
+ * @param format the format string
+ * @param object the object
+ * @param getter a getter function that extracts a value from the object
+ * @return the resulting string to be freed by free(); NULL if
+ * no format string group produced any output
+ */
+gcc_malloc
+char *
+format_object(const char *format, const void *object,
+ const char *(*getter)(const void *object, const char *name));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/win32/Win32Main.cxx b/src/win32/Win32Main.cxx
index 75a1e9a23..a833e7362 100644
--- a/src/win32/Win32Main.cxx
+++ b/src/win32/Win32Main.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -29,20 +29,19 @@
#include <cstdlib>
#include <atomic>
-#include <glib.h>
-
#include <windows.h>
+#include <tchar.h>
static int service_argc;
static char **service_argv;
-static char service_name[] = "";
+static TCHAR service_name[] = _T("");
static std::atomic_bool running;
static SERVICE_STATUS_HANDLE service_handle;
static void WINAPI
-service_main(DWORD argc, CHAR *argv[]);
+service_main(DWORD argc, LPTSTR argv[]);
-static SERVICE_TABLE_ENTRY service_registry[] = {
+static constexpr SERVICE_TABLE_ENTRY service_registry[] = {
{service_name, service_main},
{nullptr, nullptr}
};
@@ -80,21 +79,14 @@ service_dispatcher(gcc_unused DWORD control, gcc_unused DWORD event_type,
}
static void WINAPI
-service_main(gcc_unused DWORD argc, gcc_unused CHAR *argv[])
+service_main(gcc_unused DWORD argc, gcc_unused LPTSTR argv[])
{
- DWORD error_code;
- gchar* error_message;
-
service_handle =
RegisterServiceCtrlHandlerEx(service_name,
service_dispatcher, nullptr);
- if (service_handle == 0) {
- error_code = GetLastError();
- error_message = g_win32_error_message(error_code);
- FormatFatalError("RegisterServiceCtrlHandlerEx() failed: %s",
- error_message);
- }
+ if (service_handle == 0)
+ FatalSystemError("RegisterServiceCtrlHandlerEx() failed");
service_notify_status(SERVICE_START_PENDING);
mpd_main(service_argc, service_argv);
@@ -131,27 +123,22 @@ console_handler(DWORD event)
int win32_main(int argc, char *argv[])
{
- DWORD error_code;
- gchar* error_message;
-
service_argc = argc;
service_argv = argv;
if (StartServiceCtrlDispatcher(service_registry))
return 0; /* run as service successefully */
- error_code = GetLastError();
+ const DWORD error_code = GetLastError();
if (error_code == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
/* running as console app */
running.store(false);
- SetConsoleTitle("Music Player Daemon");
+ SetConsoleTitle(_T("Music Player Daemon"));
SetConsoleCtrlHandler(console_handler, TRUE);
return mpd_main(argc, argv);
}
- error_message = g_win32_error_message(error_code);
- FormatFatalError("StartServiceCtrlDispatcher() failed: %s",
- error_message);
+ FatalSystemError("StartServiceCtrlDispatcher() failed", error_code);
}
void win32_app_started()
diff --git a/src/win32/mpd.ico b/src/win32/mpd.ico
deleted file mode 100644
index 86fd9fe43..000000000
--- a/src/win32/mpd.ico
+++ /dev/null
Binary files differ
diff --git a/src/win32/mpd_win32_rc.rc.in b/src/win32/mpd_win32_rc.rc.in
deleted file mode 100644
index e5312dc78..000000000
--- a/src/win32/mpd_win32_rc.rc.in
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <windows.h>
-
-#define VERSION_NUMBER @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@
-#define VERSION_NUMBER_STR "@VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_REVISION@,@VERSION_EXTRA@"
-
-MPD_ICON ICON "@top_srcdir@/src/win32/mpd.ico"
-
-1 VERSIONINFO
-FILETYPE VFT_APP
-FILEOS VOS__WINDOWS32
-PRODUCTVERSION VERSION_NUMBER
-
-FILEVERSION VERSION_NUMBER
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904B0"
- BEGIN
- VALUE "CompanyName", "Music Player Daemon Project"
- VALUE "ProductName", "Music Player Daemon"
- VALUE "ProductVersion", VERSION_NUMBER_STR
- VALUE "InternalName", "mpd"
- VALUE "OriginalFilename", "mpd.exe"
- VALUE "FileVersion", "@VERSION@"
- VALUE "FileDescription", "Music Player Daemon @VERSION@"
- VALUE "LegalCopyright", "Copyright \251 The Music Player Daemon Project"
- END
- END
-
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1200
- END
-END
diff --git a/src/zeroconf/AvahiPoll.cxx b/src/zeroconf/AvahiPoll.cxx
index 20d5d74e6..1c75cda5a 100644
--- a/src/zeroconf/AvahiPoll.cxx
+++ b/src/zeroconf/AvahiPoll.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/AvahiPoll.hxx b/src/zeroconf/AvahiPoll.hxx
index e194d3370..ab340565d 100644
--- a/src/zeroconf/AvahiPoll.hxx
+++ b/src/zeroconf/AvahiPoll.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfAvahi.cxx b/src/zeroconf/ZeroconfAvahi.cxx
index 5adda38f9..46393e9f6 100644
--- a/src/zeroconf/ZeroconfAvahi.cxx
+++ b/src/zeroconf/ZeroconfAvahi.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfAvahi.hxx b/src/zeroconf/ZeroconfAvahi.hxx
index 09a199f55..2719de528 100644
--- a/src/zeroconf/ZeroconfAvahi.hxx
+++ b/src/zeroconf/ZeroconfAvahi.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfBonjour.cxx b/src/zeroconf/ZeroconfBonjour.cxx
index 8d7565e0e..3f395f54e 100644
--- a/src/zeroconf/ZeroconfBonjour.cxx
+++ b/src/zeroconf/ZeroconfBonjour.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfBonjour.hxx b/src/zeroconf/ZeroconfBonjour.hxx
index cff52815e..70d9039c8 100644
--- a/src/zeroconf/ZeroconfBonjour.hxx
+++ b/src/zeroconf/ZeroconfBonjour.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfGlue.cxx b/src/zeroconf/ZeroconfGlue.cxx
index 95797491b..f00395e7c 100644
--- a/src/zeroconf/ZeroconfGlue.cxx
+++ b/src/zeroconf/ZeroconfGlue.cxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -44,7 +44,7 @@ ZeroconfInit(gcc_unused EventLoop &loop)
{
const char *serviceName;
- zeroconfEnabled = config_get_bool(CONF_ZEROCONF_ENABLED,
+ zeroconfEnabled = config_get_bool(ConfigOption::ZEROCONF_ENABLED,
DEFAULT_ZEROCONF_ENABLED);
if (!zeroconfEnabled)
return;
@@ -56,7 +56,8 @@ ZeroconfInit(gcc_unused EventLoop &loop)
return;
}
- serviceName = config_get_string(CONF_ZEROCONF_NAME, SERVICE_NAME);
+ serviceName = config_get_string(ConfigOption::ZEROCONF_NAME,
+ SERVICE_NAME);
#ifdef HAVE_AVAHI
AvahiInit(loop, serviceName);
diff --git a/src/zeroconf/ZeroconfGlue.hxx b/src/zeroconf/ZeroconfGlue.hxx
index 5d2f29642..7abd07e65 100644
--- a/src/zeroconf/ZeroconfGlue.hxx
+++ b/src/zeroconf/ZeroconfGlue.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/zeroconf/ZeroconfInternal.hxx b/src/zeroconf/ZeroconfInternal.hxx
index 4d47d260a..3376062ff 100644
--- a/src/zeroconf/ZeroconfInternal.hxx
+++ b/src/zeroconf/ZeroconfInternal.hxx
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2003-2015 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify