fix copy'n'paste bug
[ncmpcpp.git] / src / helpers.cpp
blobc8685a5ff7e348b04f68e266555c0a71c1c4bdbc
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 MPD::Song::ValidateFormat("now-playing format", now_playing_format);
161 std::cout << utf_to_locale_cpy(Mpd.GetCurrentSong().toString(now_playing_format)) << "\n";
163 exit(0);
165 else if (!strcmp(argv[i], "play"))
167 Mpd.Play();
168 quit = 1;
170 else if (!strcmp(argv[i], "pause"))
172 Mpd.Pause(1);
173 quit = 1;
175 else if (!strcmp(argv[i], "toggle"))
177 Mpd.Toggle();
178 quit = 1;
180 else if (!strcmp(argv[i], "stop"))
182 Mpd.Stop();
183 quit = 1;
185 else if (!strcmp(argv[i], "next"))
187 Mpd.Next();
188 quit = 1;
190 else if (!strcmp(argv[i], "prev"))
192 Mpd.Prev();
193 quit = 1;
195 else if (!strcmp(argv[i], "volume"))
197 i++;
198 Mpd.UpdateStatus();
199 if (!Mpd.GetErrorMessage().empty())
201 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
202 exit(1);
204 if (i != argc)
205 Mpd.SetVolume(Mpd.GetVolume()+atoi(argv[i]));
206 quit = 1;
208 else
210 std::cout << "ncmpcpp: invalid option: " << argv[i] << std::endl;
211 exit(0);
213 if (!Mpd.GetErrorMessage().empty())
215 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
216 exit(0);
219 if (quit)
220 exit(0);
223 bool CaseInsensitiveSorting::operator()(const Item &a, const Item &b)
225 if (a.type == b.type)
227 switch (a.type)
229 case itDirectory:
230 return cmp(ExtractTopDirectory(a.name), ExtractTopDirectory(b.name)) < 0;
231 case itPlaylist:
232 return cmp(a.name, b.name) < 0;
233 case itSong:
234 return operator()(a.song, b.song);
235 default: // there's no other type, just silence compiler.
236 return 0;
239 else
240 return a.type < b.type;
243 void UpdateSongList(Menu<Song> *menu)
245 bool bold = 0;
246 for (size_t i = 0; i < menu->Size(); ++i)
248 for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
250 if (myPlaylist->Items->at(j).GetHash() == menu->at(i).GetHash())
252 bold = 1;
253 break;
256 menu->Bold(i, bold);
257 bold = 0;
259 menu->Refresh();
262 #ifdef HAVE_TAGLIB_H
263 std::string FindSharedDir(Menu<Song> *menu)
265 SongList list;
266 for (size_t i = 0; i < menu->Size(); ++i)
267 list.push_back(&(*menu)[i]);
268 return FindSharedDir(list);
271 std::string FindSharedDir(const SongList &v)
273 if (v.empty()) // this should never happen, but in case...
274 FatalError("empty SongList passed to FindSharedDir(const SongList &)!");
275 size_t i = -1;
276 std::string first = v.front()->GetDirectory();
277 for (SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
279 size_t j = 0;
280 std::string dir = (*it)->GetDirectory();
281 size_t length = std::min(first.length(), dir.length());
282 while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
283 ++j;
284 i = j;
286 return i ? first.substr(0, i) : "/";
288 #endif // HAVE_TAGLIB_H
290 std::string FindSharedDir(const std::string &one, const std::string &two)
292 if (one == two)
293 return one;
294 size_t i = 0;
295 while (!one.compare(i, 1, two, i, 1))
296 ++i;
297 i = one.rfind("/", i);
298 return i != std::string::npos ? one.substr(0, i) : "/";
301 std::string GetLineValue(std::string &line, char a, char b, bool once)
303 int pos[2] = { -1, -1 };
304 size_t i;
305 for (i = line.find(a); i != std::string::npos && pos[1] < 0; i = line.find(b, i))
307 if (i && line[i-1] == '\\')
309 i++;
310 continue;
312 if (once)
313 line[i] = 0;
314 pos[pos[0] >= 0] = i++;
316 pos[0]++;
317 std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
318 for (i = result.find("\\\""); i != std::string::npos; i = result.find("\\\""))
319 result.replace(i, 2, "\"");
320 return result;
323 std::string ExtractTopDirectory(const std::string &s)
325 size_t slash = s.rfind("/");
326 return slash != std::string::npos ? s.substr(++slash) : s;
329 std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
331 std::basic_string<my_char_t> s(str);
332 if (!Config.header_text_scrolling)
333 return s;
334 std::basic_string<my_char_t> result;
335 size_t len = Window::Length(s);
337 if (len > width)
339 s += U(" ** ");
340 len = 0;
341 std::basic_string<my_char_t>::const_iterator b = s.begin(), e = s.end();
342 for (std::basic_string<my_char_t>::const_iterator it = b+pos; it < e && len < width; ++it)
344 if ((len += wcwidth(*it)) > width)
345 break;
346 result += *it;
348 if (++pos >= s.length())
349 pos = 0;
350 for (; len < width; ++b)
352 if ((len += wcwidth(*b)) > width)
353 break;
354 result += *b;
357 else
358 result = s;
359 return result;
362 #ifdef HAVE_CURL_CURL_H
363 size_t write_data(char *buffer, size_t size, size_t nmemb, void *data)
365 size_t result = size*nmemb;
366 static_cast<std::string *>(data)->append(buffer, result);
367 return result;
369 #endif // HAVE_CURL_CURL_H