fix toggle command
[ncmpcpp.git] / src / helpers.cpp
blob48c76a022fd665bbbe309de4e00232aeebf46031
1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
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. *
9 * *
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. *
14 * *
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 #include <cstring>
22 #include <algorithm>
23 #include <iostream>
24 #include <stdexcept>
26 #include "charset.h"
27 #include "global.h"
28 #include "helpers.h"
29 #include "playlist.h"
30 #include "status.h"
31 #include "tag_editor.h"
33 using namespace MPD;
35 bool ConnectToMPD()
37 if (!Mpd.Connect())
39 std::cout << "Cannot connect to mpd: " << Mpd.GetErrorMessage() << std::endl;
40 return false;
42 return true;
45 void ParseArgv(int argc, char **argv)
47 bool quit = 0;
48 std::string now_playing_format = "{{(%l) }{{%a - }%t}}|{%f}}";
50 for (int i = 1; i < argc; ++i)
52 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host"))
54 if (++i >= argc)
55 exit(0);
56 Mpd.SetHostname(argv[i]);
57 continue;
59 if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port"))
61 if (++i >= argc)
62 exit(0);
63 Mpd.SetPort(atoi(argv[i]));
64 continue;
66 else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version"))
68 std::cout << "ncmpcpp version: " << VERSION << "\n\n"
69 << "optional screens compiled-in:\n"
70 # ifdef HAVE_TAGLIB_H
71 << " - tag editor\n"
72 << " - tiny tag editor\n"
73 # endif
74 # ifdef HAVE_CURL_CURL_H
75 << " - artist info\n"
76 # endif
77 # ifdef ENABLE_OUTPUTS
78 << " - outputs\n"
79 # endif
80 # ifdef ENABLE_VISUALIZER
81 << " - visualizer\n"
82 # endif
83 # ifdef ENABLE_CLOCK
84 << " - clock\n"
85 # endif
86 << "\nencoding detection: "
87 # ifdef HAVE_LANGINFO_H
88 << "enabled"
89 # else
90 << "disabled"
91 # endif // HAVE_LANGINFO_H
92 << "\nbuilt with support for:"
93 # ifdef HAVE_CURL_CURL_H
94 << " curl"
95 # endif
96 # ifdef HAVE_ICONV_H
97 << " iconv"
98 # endif
99 # ifdef HAVE_FFTW3_H
100 << " fftw"
101 # endif
102 # ifdef USE_PDCURSES
103 << " pdcurses"
104 # else
105 << " ncurses"
106 # endif
107 # ifdef HAVE_TAGLIB_H
108 << " taglib"
109 # endif
110 # ifdef HAVE_PTHREAD_H
111 << " threads"
112 # endif
113 # ifdef _UTF8
114 << " unicode"
115 # endif
116 << std::endl;
117 exit(0);
119 else if (!strcmp(argv[i], "-?") || !strcmp(argv[i], "--help"))
121 std::cout
122 << "Usage: ncmpcpp [OPTION]...\n"
123 << " -h, --host connect to server at host [localhost]\n"
124 << " -p, --port connect to server at port [6600]\n"
125 << " -?, --help show this help message\n"
126 << " -v, --version display version information\n"
127 << " --now-playing display now playing song [" << now_playing_format << "]\n"
128 << "\n"
129 << " play start playing\n"
130 << " pause pause the currently playing song\n"
131 << " toggle toggle play/pause mode\n"
132 << " stop stop playing\n"
133 << " next play the next song\n"
134 << " prev play the previous song\n"
135 << " volume [+-]<num> adjusts volume by [+-]<num>\n"
137 exit(0);
140 if (!ConnectToMPD())
141 exit(0);
143 if (!strcmp(argv[i], "--now-playing"))
145 Mpd.UpdateStatus();
146 if (!Mpd.GetErrorMessage().empty())
148 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
149 exit(1);
151 if (Mpd.isPlaying())
153 if (argc > ++i)
155 // apply additional pair of braces
156 now_playing_format = "{";
157 now_playing_format += argv[i];
158 now_playing_format += "}";
159 Replace(now_playing_format, "\\n", "\n");
160 Replace(now_playing_format, "\\t", "\t");
161 MPD::Song::ValidateFormat("now-playing format", now_playing_format);
163 std::cout << utf_to_locale_cpy(Mpd.GetCurrentSong().toString(now_playing_format)) << "\n";
165 exit(0);
167 else if (!strcmp(argv[i], "play"))
169 Mpd.Play();
170 quit = 1;
172 else if (!strcmp(argv[i], "pause"))
174 Mpd.Pause(1);
175 quit = 1;
177 else if (!strcmp(argv[i], "toggle"))
179 Mpd.UpdateStatus();
180 if (!Mpd.GetErrorMessage().empty())
182 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
183 exit(1);
185 Mpd.Toggle();
186 quit = 1;
188 else if (!strcmp(argv[i], "stop"))
190 Mpd.Stop();
191 quit = 1;
193 else if (!strcmp(argv[i], "next"))
195 Mpd.Next();
196 quit = 1;
198 else if (!strcmp(argv[i], "prev"))
200 Mpd.Prev();
201 quit = 1;
203 else if (!strcmp(argv[i], "volume"))
205 i++;
206 Mpd.UpdateStatus();
207 if (!Mpd.GetErrorMessage().empty())
209 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
210 exit(1);
212 if (i != argc)
213 Mpd.SetVolume(Mpd.GetVolume()+atoi(argv[i]));
214 quit = 1;
216 else
218 std::cout << "ncmpcpp: invalid option: " << argv[i] << std::endl;
219 exit(0);
221 if (!Mpd.GetErrorMessage().empty())
223 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
224 exit(0);
227 if (quit)
228 exit(0);
231 bool CaseInsensitiveSorting::operator()(const Item &a, const Item &b)
233 if (a.type == b.type)
235 switch (a.type)
237 case itDirectory:
238 return cmp(ExtractTopDirectory(a.name), ExtractTopDirectory(b.name)) < 0;
239 case itPlaylist:
240 return cmp(a.name, b.name) < 0;
241 case itSong:
242 return Config.browser_sort_by_mtime
243 ? a.song->GetMTime() > b.song->GetMTime()
244 : operator()(a.song, b.song);
245 default: // there's no other type, just silence compiler.
246 return 0;
249 else
250 return a.type < b.type;
253 std::string Timestamp(time_t t)
255 char result[32];
256 tm info;
257 result[strftime(result, 31, "%x %X", localtime_r(&t, &info))] = 0;
258 return result;
261 void UpdateSongList(Menu<Song> *menu)
263 bool bold = 0;
264 for (size_t i = 0; i < menu->Size(); ++i)
266 for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
268 if (myPlaylist->Items->at(j).GetHash() == menu->at(i).GetHash())
270 bold = 1;
271 break;
274 menu->Bold(i, bold);
275 bold = 0;
277 menu->Refresh();
280 #ifdef HAVE_TAGLIB_H
281 std::string FindSharedDir(Menu<Song> *menu)
283 SongList list;
284 for (size_t i = 0; i < menu->Size(); ++i)
285 list.push_back(&(*menu)[i]);
286 return FindSharedDir(list);
289 std::string FindSharedDir(const SongList &v)
291 if (v.empty()) // this should never happen, but in case...
292 FatalError("empty SongList passed to FindSharedDir(const SongList &)!");
293 size_t i = -1;
294 std::string first = v.front()->GetDirectory();
295 for (SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
297 size_t j = 0;
298 std::string dir = (*it)->GetDirectory();
299 size_t length = std::min(first.length(), dir.length());
300 while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
301 ++j;
302 i = j;
304 return i ? first.substr(0, i) : "/";
306 #endif // HAVE_TAGLIB_H
308 std::string FindSharedDir(const std::string &one, const std::string &two)
310 if (one == two)
311 return one;
312 size_t i = 0;
313 while (!one.compare(i, 1, two, i, 1))
314 ++i;
315 i = one.rfind("/", i);
316 return i != std::string::npos ? one.substr(0, i) : "/";
319 std::string GetLineValue(std::string &line, char a, char b, bool once)
321 int pos[2] = { -1, -1 };
322 size_t i;
323 for (i = line.find(a); i != std::string::npos && pos[1] < 0; i = line.find(b, i))
325 if (i && line[i-1] == '\\')
327 i++;
328 continue;
330 if (once)
331 line[i] = 0;
332 pos[pos[0] >= 0] = i++;
334 pos[0]++;
335 std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
336 Replace(result, "\\\"", "\"");
337 return result;
340 std::string ExtractTopDirectory(const std::string &s)
342 size_t slash = s.rfind("/");
343 return slash != std::string::npos ? s.substr(++slash) : s;
346 std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
348 std::basic_string<my_char_t> s(str);
349 if (!Config.header_text_scrolling)
350 return s;
351 std::basic_string<my_char_t> result;
352 size_t len = Window::Length(s);
354 if (len > width)
356 s += U(" ** ");
357 len = 0;
358 std::basic_string<my_char_t>::const_iterator b = s.begin(), e = s.end();
359 for (std::basic_string<my_char_t>::const_iterator it = b+pos; it < e && len < width; ++it)
361 if ((len += wcwidth(*it)) > width)
362 break;
363 result += *it;
365 if (++pos >= s.length())
366 pos = 0;
367 for (; len < width; ++b)
369 if ((len += wcwidth(*b)) > width)
370 break;
371 result += *b;
374 else
375 result = s;
376 return result;
379 #ifdef HAVE_CURL_CURL_H
380 size_t write_data(char *buffer, size_t size, size_t nmemb, void *data)
382 size_t result = size*nmemb;
383 static_cast<std::string *>(data)->append(buffer, result);
384 return result;
386 #endif // HAVE_CURL_CURL_H