1 /***************************************************************************
2 * Copyright (C) 2008-2014 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>
29 #include "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
) {
184 // specialization for strings (input/output)
185 template <typename SomeCharT
, typename OtherCharT
>
186 struct output_
<std::basic_string
<SomeCharT
>, std::basic_string
<OtherCharT
>> {
187 typedef std::basic_string
<SomeCharT
> SomeString
;
188 typedef std::basic_string
<OtherCharT
> OtherString
;
190 // compile only if string types are the same
191 static typename
std::enable_if
<
192 std::is_same
<SomeString
, OtherString
>::value
,
194 >::type
exec(SomeString
&result
, const OtherString
&s
) {
198 // when writing to a string, we should ignore all other
199 // properties. if this code is reached, throw an exception.
200 template <typename ValueT
, typename SomeCharT
>
201 struct output_
<ValueT
, std::basic_string
<SomeCharT
>> {
202 static void exec(std::basic_string
<CharT
> &, const ValueT
&) {
203 throw std::logic_error("non-string property can't be appended to the string");
207 template <typename ValueT
>
208 void output(const ValueT
&value
) const
212 if (m_output_switched
&& m_second_os
!= nullptr)
213 output_
<ValueT
, SecondOutputT
>::exec(*m_second_os
, value
);
215 output_
<ValueT
, OutputT
>::exec(m_output
, value
);
220 const MPD::Song
*m_song
;
222 bool m_output_switched
;
223 SecondOutputT
*m_second_os
;
225 unsigned m_no_output
;
226 const unsigned m_flags
;
229 template <typename CharT
, typename VisitorT
>
230 void visit(VisitorT
&visitor
, const AST
<CharT
> &ast
)
232 for (const auto &ex
: ast
.base())
233 boost::apply_visitor(visitor
, ex
);
236 template <typename CharT
, typename ItemT
>
237 void print(const AST
<CharT
> &ast
, NC::Menu
<ItemT
> &menu
, const MPD::Song
*song
,
238 NC::BasicBuffer
<CharT
> *buffer
, const unsigned flags
)
240 Printer
<CharT
, NC::Menu
<ItemT
>, NC::Buffer
> printer(menu
, song
, buffer
, flags
);
244 template <typename CharT
>
245 void print(const AST
<CharT
> &ast
, NC::BasicBuffer
<CharT
> &buffer
,
246 const MPD::Song
*song
, const unsigned flags
)
248 Printer
<CharT
, NC::BasicBuffer
<CharT
>> printer(buffer
, song
, &buffer
, flags
);
252 template <typename CharT
>
253 std::basic_string
<CharT
> stringify(const AST
<CharT
> &ast
, const MPD::Song
*song
)
255 std::basic_string
<CharT
> result
;
256 Printer
<CharT
, std::basic_string
<CharT
>> printer(result
, song
, &result
, Flags::Tag
);
263 #endif // NCMPCPP_HAVE_FORMAT__IMPL_H