fixes for db97a1a3186b2bbd9d36770e83aa5325db5ce77a
[ncmpcpp.git] / src / helpers.cpp
blobf2d8c6af01299095052649280e2e6d276919be72
1 /***************************************************************************
2 * Copyright (C) 2008-2010 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 bool ConnectToMPD()
35 if (!Mpd.Connect())
37 std::cout << "Cannot connect to mpd: " << Mpd.GetErrorMessage() << std::endl;
38 return false;
40 return true;
43 void ParseArgv(int argc, char **argv)
45 bool quit = 0;
46 std::string now_playing_format = "{{(%l) }{{%a - }%t}}|{%f}}";
48 for (int i = 1; i < argc; ++i)
50 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host"))
52 if (++i >= argc)
53 exit(0);
54 Mpd.SetHostname(argv[i]);
55 continue;
57 if (!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port"))
59 if (++i >= argc)
60 exit(0);
61 Mpd.SetPort(atoi(argv[i]));
62 continue;
64 else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version"))
66 std::cout << "ncmpcpp version: " << VERSION << "\n\n"
67 << "optional screens compiled-in:\n"
68 # ifdef HAVE_TAGLIB_H
69 << " - tag editor\n"
70 << " - tiny tag editor\n"
71 # endif
72 # ifdef HAVE_CURL_CURL_H
73 << " - artist info\n"
74 # endif
75 # ifdef ENABLE_OUTPUTS
76 << " - outputs\n"
77 # endif
78 # ifdef ENABLE_VISUALIZER
79 << " - visualizer\n"
80 # endif
81 # ifdef ENABLE_CLOCK
82 << " - clock\n"
83 # endif
84 << "\nencoding detection: "
85 # ifdef HAVE_LANGINFO_H
86 << "enabled"
87 # else
88 << "disabled"
89 # endif // HAVE_LANGINFO_H
90 << "\nbuilt with support for:"
91 # ifdef HAVE_CURL_CURL_H
92 << " curl"
93 # endif
94 # ifdef HAVE_ICONV_H
95 << " iconv"
96 # endif
97 # ifdef HAVE_FFTW3_H
98 << " fftw"
99 # endif
100 # ifdef USE_PDCURSES
101 << " pdcurses"
102 # else
103 << " ncurses"
104 # endif
105 # ifdef HAVE_TAGLIB_H
106 << " taglib"
107 # endif
108 # ifdef HAVE_PTHREAD_H
109 << " threads"
110 # endif
111 # ifdef _UTF8
112 << " unicode"
113 # endif
114 << std::endl;
115 exit(0);
117 else if (!strcmp(argv[i], "-?") || !strcmp(argv[i], "--help"))
119 std::cout
120 << "Usage: ncmpcpp [OPTION]...\n"
121 << " -h, --host connect to server at host [localhost]\n"
122 << " -p, --port connect to server at port [6600]\n"
123 << " -?, --help show this help message\n"
124 << " -v, --version display version information\n"
125 << " --now-playing display now playing song [" << now_playing_format << "]\n"
126 << "\n"
127 << " play start playing\n"
128 << " pause pause the currently playing song\n"
129 << " toggle toggle play/pause mode\n"
130 << " stop stop playing\n"
131 << " next play the next song\n"
132 << " prev play the previous song\n"
133 << " volume [+-]<num> adjusts volume by [+-]<num>\n"
135 exit(0);
138 if (!ConnectToMPD())
139 exit(0);
141 if (!strcmp(argv[i], "--now-playing"))
143 Mpd.UpdateStatus();
144 if (!Mpd.GetErrorMessage().empty())
146 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
147 exit(1);
149 if (Mpd.isPlaying())
151 if (argc > ++i)
153 // apply additional pair of braces
154 now_playing_format = "{";
155 now_playing_format += argv[i];
156 now_playing_format += "}";
157 Replace(now_playing_format, "\\n", "\n");
158 Replace(now_playing_format, "\\t", "\t");
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.UpdateStatus();
178 if (!Mpd.GetErrorMessage().empty())
180 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
181 exit(1);
183 Mpd.Toggle();
184 quit = 1;
186 else if (!strcmp(argv[i], "stop"))
188 Mpd.Stop();
189 quit = 1;
191 else if (!strcmp(argv[i], "next"))
193 Mpd.Next();
194 quit = 1;
196 else if (!strcmp(argv[i], "prev"))
198 Mpd.Prev();
199 quit = 1;
201 else if (!strcmp(argv[i], "volume"))
203 i++;
204 Mpd.UpdateStatus();
205 if (!Mpd.GetErrorMessage().empty())
207 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
208 exit(1);
210 if (i != argc)
211 Mpd.SetVolume(Mpd.GetVolume()+atoi(argv[i]));
212 quit = 1;
214 else
216 std::cout << "ncmpcpp: invalid option: " << argv[i] << std::endl;
217 exit(0);
219 if (!Mpd.GetErrorMessage().empty())
221 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
222 exit(0);
225 if (quit)
226 exit(0);
229 bool CaseInsensitiveSorting::operator()(const MPD::Item &a, const MPD::Item &b)
231 if (a.type == b.type)
233 switch (a.type)
235 case MPD::itDirectory:
236 return cmp(ExtractTopDirectory(a.name), ExtractTopDirectory(b.name)) < 0;
237 case MPD::itPlaylist:
238 return cmp(a.name, b.name) < 0;
239 case MPD::itSong:
240 return Config.browser_sort_by_mtime
241 ? a.song->GetMTime() > b.song->GetMTime()
242 : operator()(a.song, b.song);
243 default: // there's no other type, just silence compiler.
244 return 0;
247 else
248 return a.type < b.type;
251 std::string Timestamp(time_t t)
253 char result[32];
254 tm info;
255 result[strftime(result, 31, "%x %X", localtime_r(&t, &info))] = 0;
256 return result;
259 void UpdateSongList(Menu<MPD::Song> *menu)
261 bool bold = 0;
262 for (size_t i = 0; i < menu->Size(); ++i)
264 for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
266 if (myPlaylist->Items->at(j).GetHash() == menu->at(i).GetHash())
268 bold = 1;
269 break;
272 menu->Bold(i, bold);
273 bold = 0;
275 menu->Refresh();
278 #ifdef HAVE_TAGLIB_H
279 std::string FindSharedDir(Menu<MPD::Song> *menu)
281 MPD::SongList list;
282 for (size_t i = 0; i < menu->Size(); ++i)
283 list.push_back(&(*menu)[i]);
284 return FindSharedDir(list);
287 std::string FindSharedDir(const MPD::SongList &v)
289 if (v.empty()) // this should never happen, but in case...
290 FatalError("empty SongList passed to FindSharedDir(const SongList &)!");
291 size_t i = -1;
292 std::string first = v.front()->GetDirectory();
293 for (MPD::SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
295 size_t j = 0;
296 std::string dir = (*it)->GetDirectory();
297 size_t length = std::min(first.length(), dir.length());
298 while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
299 ++j;
300 i = j;
302 return i ? first.substr(0, i) : "/";
304 #endif // HAVE_TAGLIB_H
306 std::string FindSharedDir(const std::string &one, const std::string &two)
308 if (one == two)
309 return one;
310 size_t i = 0;
311 while (!one.compare(i, 1, two, i, 1))
312 ++i;
313 i = one.rfind("/", i);
314 return i != std::string::npos ? one.substr(0, i) : "/";
317 std::string GetLineValue(std::string &line, char a, char b, bool once)
319 int pos[2] = { -1, -1 };
320 size_t i;
321 for (i = line.find(a); i != std::string::npos && pos[1] < 0; i = line.find(b, i))
323 if (i && line[i-1] == '\\')
325 i++;
326 continue;
328 if (once)
329 line[i] = 0;
330 pos[pos[0] >= 0] = i++;
332 pos[0]++;
333 std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
334 Replace(result, "\\\"", "\"");
335 return result;
338 std::string ExtractTopDirectory(const std::string &s)
340 size_t slash = s.rfind("/");
341 return slash != std::string::npos ? s.substr(++slash) : s;
344 std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
346 std::basic_string<my_char_t> s(str);
347 if (!Config.header_text_scrolling)
348 return s;
349 std::basic_string<my_char_t> result;
350 size_t len = Window::Length(s);
352 if (len > width)
354 s += U(" ** ");
355 len = 0;
356 std::basic_string<my_char_t>::const_iterator b = s.begin(), e = s.end();
357 for (std::basic_string<my_char_t>::const_iterator it = b+pos; it < e && len < width; ++it)
359 if ((len += wcwidth(*it)) > width)
360 break;
361 result += *it;
363 if (++pos >= s.length())
364 pos = 0;
365 for (; len < width; ++b)
367 if ((len += wcwidth(*b)) > width)
368 break;
369 result += *b;
372 else
373 result = s;
374 return result;
377 #ifdef HAVE_CURL_CURL_H
378 size_t write_data(char *buffer, size_t size, size_t nmemb, void *data)
380 size_t result = size*nmemb;
381 static_cast<std::string *>(data)->append(buffer, result);
382 return result;
384 #endif // HAVE_CURL_CURL_H