1 /***************************************************************************
2 * Copyright (C) 2008-2016 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #ifndef NCMPCPP_HAVE_FORMAT_IMPL_H
22 #define NCMPCPP_HAVE_FORMAT_IMPL_H
24 #include <boost/variant.hpp>
26 #include "curses/menu.h"
27 #include "curses/strbuffer.h"
30 #include "utility/functional.h"
31 #include "utility/wide_string.h"
35 // Commutative binary operation such that:
36 // - Empty + Empty = Empty
37 // - Empty + Missing = Missing
39 // - Missing + Missing = Missing
40 // - Missing + Ok = Missing
42 inline Result
&operator+=(Result
&base
, Result result
)
44 if (base
== Result::Missing
|| result
== Result::Missing
)
45 base
= Result::Missing
;
46 else if (base
== Result::Ok
|| result
== Result::Ok
)
51 /*inline std::ostream &operator<<(std::ostream &os, Result r)
68 template <typename CharT
, typename OutputT
, typename SecondOutputT
= OutputT
>
69 struct Printer
: boost::static_visitor
<Result
>
71 typedef std::basic_string
<CharT
> StringT
;
73 Printer(OutputT
&os
, const MPD::Song
*song
, SecondOutputT
*second_os
, const unsigned flags
)
76 , m_output_switched(false)
77 , m_second_os(second_os
)
82 Result
operator()(const StringT
&s
)
93 Result
operator()(const NC::Color
&c
)
95 if (m_flags
& Flags::Color
)
100 Result
operator()(NC::Format fmt
)
102 if (m_flags
& Flags::Format
)
104 return Result::Empty
;
107 Result
operator()(OutputSwitch
)
110 m_output_switched
= true;
114 Result
operator()(const SongTag
&st
)
117 if (m_flags
& Flags::Tag
&& m_song
!= nullptr)
119 tags
= convertString
<CharT
, char>::apply(
120 m_song
->getTags(st
.function())
125 if (st
.delimiter() > 0)
127 // shorten date/length by simple truncation
128 if (st
.function() == &MPD::Song::getDate
|| st
.function() == &MPD::Song::getLength
)
129 tags
.resize(st
.delimiter());
131 tags
= wideShorten(tags
, st
.delimiter());
137 return Result::Missing
;
140 // If all Empty -> Empty, if any Ok -> continue with Ok, if any Missing -> stop with Empty.
141 Result
operator()(const Group
<CharT
> &group
)
143 auto visit
= [this, &group
] {
144 Result result
= Result::Empty
;
145 for (const auto &ex
: group
.base())
147 result
+= boost::apply_visitor(*this, ex
);
148 if (result
== Result::Missing
)
150 result
= Result::Empty
;
158 Result result
= visit();
160 if (!m_no_output
&& result
== Result::Ok
)
165 // If all Empty or Missing -> Empty, if any Ok -> stop with Ok.
166 Result
operator()(const FirstOf
<CharT
> &first_of
)
168 for (const auto &ex
: first_of
.base())
170 if (boost::apply_visitor(*this, ex
) == Result::Ok
)
173 return Result::Empty
;
177 // generic version for streams (buffers, menus)
178 template <typename ValueT
, typename OutputStreamT
>
180 static void exec(OutputStreamT
&os
, const ValueT
&value
, const SongTag
*) {
185 // specialization for strings (input/output)
186 template <typename SomeCharT
, typename OtherCharT
>
187 struct output_
<std::basic_string
<SomeCharT
>, std::basic_string
<OtherCharT
>> {
188 typedef std::basic_string
<SomeCharT
> SomeString
;
189 typedef std::basic_string
<OtherCharT
> OtherString
;
191 // compile only if string types are the same
192 static typename
std::enable_if
<
193 std::is_same
<SomeString
, OtherString
>::value
,
195 >::type
exec(SomeString
&result
, const OtherString
&s
, const SongTag
*) {
199 // when writing to a string, we should ignore all other
200 // properties. if this code is reached, throw an exception.
201 template <typename ValueT
, typename SomeCharT
>
202 struct output_
<ValueT
, std::basic_string
<SomeCharT
>> {
203 static void exec(std::basic_string
<CharT
> &, const ValueT
&, const SongTag
*) {
204 throw std::logic_error("non-string property can't be appended to the string");
208 // Specialization for SongTagMap.
209 template <typename SomeCharT
, typename OtherCharT
>
210 struct output_
<std::basic_string
<SomeCharT
>, SongTagMap
<OtherCharT
> > {
211 // Compile only if string types are the same.
212 static typename
std::enable_if
<
213 std::is_same
<SomeCharT
, OtherCharT
>::value
,
215 >::type
exec(SongTagMap
<OtherCharT
> &acc
,
216 const std::basic_string
<SomeCharT
> &s
, const SongTag
*st
) {
218 acc
.emplace_back(*st
, s
);
222 // When extracting tags from a song all the other properties should
223 // be ignored. If that's not the case, throw an exception.
224 template <typename ValueT
, typename SomeCharT
>
225 struct output_
<ValueT
, SongTagMap
<SomeCharT
> > {
226 static void exec(SongTagMap
<SomeCharT
> &, const ValueT
&, const SongTag
*) {
227 throw std::logic_error("Non-string property can't be inserted into the SongTagMap");
231 template <typename ValueT
>
232 void output(const ValueT
&value
, const SongTag
*st
= nullptr) const
236 if (m_output_switched
&& m_second_os
!= nullptr)
237 output_
<ValueT
, SecondOutputT
>::exec(*m_second_os
, value
, st
);
239 output_
<ValueT
, OutputT
>::exec(m_output
, value
, st
);
244 const MPD::Song
*m_song
;
246 bool m_output_switched
;
247 SecondOutputT
*m_second_os
;
249 unsigned m_no_output
;
250 const unsigned m_flags
;
253 template <typename CharT
, typename VisitorT
>
254 void visit(VisitorT
&visitor
, const AST
<CharT
> &ast
)
256 for (const auto &ex
: ast
.base())
257 boost::apply_visitor(visitor
, ex
);
260 template <typename CharT
, typename ItemT
>
261 void print(const AST
<CharT
> &ast
, NC::Menu
<ItemT
> &menu
, const MPD::Song
*song
,
262 NC::BasicBuffer
<CharT
> *buffer
, const unsigned flags
)
264 Printer
<CharT
, NC::Menu
<ItemT
>, NC::Buffer
> printer(menu
, song
, buffer
, flags
);
268 template <typename CharT
>
269 void print(const AST
<CharT
> &ast
, NC::BasicBuffer
<CharT
> &buffer
,
270 const MPD::Song
*song
, const unsigned flags
)
272 Printer
<CharT
, NC::BasicBuffer
<CharT
>> printer(buffer
, song
, &buffer
, flags
);
276 template <typename CharT
>
277 std::basic_string
<CharT
> stringify(const AST
<CharT
> &ast
, const MPD::Song
*song
)
279 std::basic_string
<CharT
> result
;
280 Printer
<CharT
, std::basic_string
<CharT
>> printer(result
, song
, &result
, Flags::Tag
);
285 template <typename CharT
>
286 SongTagMap
<CharT
> extractTags(const AST
<CharT
> &ast
, const MPD::Song
&song
)
288 SongTagMap
<CharT
> result
;
289 Printer
<CharT
, SongTagMap
<CharT
> > printer(result
, &song
, &result
, Flags::Tag
);
296 #endif // NCMPCPP_HAVE_FORMAT__IMPL_H