move code responsible for screen resize to SIGWINCH handler
[ncmpcpp.git] / src / helpers.cpp
blobc1479efc8deb1eb01d3664abe4f4b3c90a01bc95
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.Toggle();
180 quit = 1;
182 else if (!strcmp(argv[i], "stop"))
184 Mpd.Stop();
185 quit = 1;
187 else if (!strcmp(argv[i], "next"))
189 Mpd.Next();
190 quit = 1;
192 else if (!strcmp(argv[i], "prev"))
194 Mpd.Prev();
195 quit = 1;
197 else if (!strcmp(argv[i], "volume"))
199 i++;
200 Mpd.UpdateStatus();
201 if (!Mpd.GetErrorMessage().empty())
203 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
204 exit(1);
206 if (i != argc)
207 Mpd.SetVolume(Mpd.GetVolume()+atoi(argv[i]));
208 quit = 1;
210 else
212 std::cout << "ncmpcpp: invalid option: " << argv[i] << std::endl;
213 exit(0);
215 if (!Mpd.GetErrorMessage().empty())
217 std::cout << "Error: " << Mpd.GetErrorMessage() << std::endl;
218 exit(0);
221 if (quit)
222 exit(0);
225 bool CaseInsensitiveSorting::operator()(const Item &a, const Item &b)
227 if (a.type == b.type)
229 switch (a.type)
231 case itDirectory:
232 return cmp(ExtractTopDirectory(a.name), ExtractTopDirectory(b.name)) < 0;
233 case itPlaylist:
234 return cmp(a.name, b.name) < 0;
235 case itSong:
236 return Config.browser_sort_by_mtime
237 ? a.song->GetMTime() > b.song->GetMTime()
238 : operator()(a.song, b.song);
239 default: // there's no other type, just silence compiler.
240 return 0;
243 else
244 return a.type < b.type;
247 std::string Timestamp(time_t t)
249 char result[32];
250 tm info;
251 result[strftime(result, 31, "%x %X", localtime_r(&t, &info))] = 0;
252 return result;
255 void UpdateSongList(Menu<Song> *menu)
257 bool bold = 0;
258 for (size_t i = 0; i < menu->Size(); ++i)
260 for (size_t j = 0; j < myPlaylist->Items->Size(); ++j)
262 if (myPlaylist->Items->at(j).GetHash() == menu->at(i).GetHash())
264 bold = 1;
265 break;
268 menu->Bold(i, bold);
269 bold = 0;
271 menu->Refresh();
274 #ifdef HAVE_TAGLIB_H
275 std::string FindSharedDir(Menu<Song> *menu)
277 SongList list;
278 for (size_t i = 0; i < menu->Size(); ++i)
279 list.push_back(&(*menu)[i]);
280 return FindSharedDir(list);
283 std::string FindSharedDir(const SongList &v)
285 if (v.empty()) // this should never happen, but in case...
286 FatalError("empty SongList passed to FindSharedDir(const SongList &)!");
287 size_t i = -1;
288 std::string first = v.front()->GetDirectory();
289 for (SongList::const_iterator it = ++v.begin(); it != v.end(); ++it)
291 size_t j = 0;
292 std::string dir = (*it)->GetDirectory();
293 size_t length = std::min(first.length(), dir.length());
294 while (!first.compare(j, 1, dir, j, 1) && j < length && j < i)
295 ++j;
296 i = j;
298 return i ? first.substr(0, i) : "/";
300 #endif // HAVE_TAGLIB_H
302 std::string FindSharedDir(const std::string &one, const std::string &two)
304 if (one == two)
305 return one;
306 size_t i = 0;
307 while (!one.compare(i, 1, two, i, 1))
308 ++i;
309 i = one.rfind("/", i);
310 return i != std::string::npos ? one.substr(0, i) : "/";
313 std::string GetLineValue(std::string &line, char a, char b, bool once)
315 int pos[2] = { -1, -1 };
316 size_t i;
317 for (i = line.find(a); i != std::string::npos && pos[1] < 0; i = line.find(b, i))
319 if (i && line[i-1] == '\\')
321 i++;
322 continue;
324 if (once)
325 line[i] = 0;
326 pos[pos[0] >= 0] = i++;
328 pos[0]++;
329 std::string result = pos[0] >= 0 && pos[1] >= 0 ? line.substr(pos[0], pos[1]-pos[0]) : "";
330 Replace(result, "\\\"", "\"");
331 return result;
334 std::string ExtractTopDirectory(const std::string &s)
336 size_t slash = s.rfind("/");
337 return slash != std::string::npos ? s.substr(++slash) : s;
340 std::basic_string<my_char_t> Scroller(const std::basic_string<my_char_t> &str, size_t &pos, size_t width)
342 std::basic_string<my_char_t> s(str);
343 if (!Config.header_text_scrolling)
344 return s;
345 std::basic_string<my_char_t> result;
346 size_t len = Window::Length(s);
348 if (len > width)
350 s += U(" ** ");
351 len = 0;
352 std::basic_string<my_char_t>::const_iterator b = s.begin(), e = s.end();
353 for (std::basic_string<my_char_t>::const_iterator it = b+pos; it < e && len < width; ++it)
355 if ((len += wcwidth(*it)) > width)
356 break;
357 result += *it;
359 if (++pos >= s.length())
360 pos = 0;
361 for (; len < width; ++b)
363 if ((len += wcwidth(*b)) > width)
364 break;
365 result += *b;
368 else
369 result = s;
370 return result;
373 #ifdef HAVE_CURL_CURL_H
374 size_t write_data(char *buffer, size_t size, size_t nmemb, void *data)
376 size_t result = size*nmemb;
377 static_cast<std::string *>(data)->append(buffer, result);
378 return result;
380 #endif // HAVE_CURL_CURL_H