format: shorten date by simple truncation
[ncmpcpp.git] / src / configuration.cpp
blobc8fa609e3a172d472d3598f185ddb072527d9bbf
1 /***************************************************************************
2 * Copyright (C) 2008-2014 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 <algorithm>
22 #include <boost/filesystem/operations.hpp>
23 #include <boost/program_options.hpp>
24 #include <iostream>
26 #include "bindings.h"
27 #include "configuration.h"
28 #include "config.h"
29 #include "mpdpp.h"
30 #include "settings.h"
31 #include "utility/string.h"
33 namespace po = boost::program_options;
35 using std::cerr;
36 using std::cout;
38 namespace {
40 const char *env_home;
42 std::string xdg_config_home()
44 std::string result;
45 const char *env_xdg_config_home = getenv("XDG_CONFIG_HOME");
46 if (env_xdg_config_home == nullptr)
47 result = "~/.config/";
48 else
50 result = env_xdg_config_home;
51 if (!result.empty() && result.back() != '/')
52 result += "/";
54 return result;
59 void expand_home(std::string &path)
61 assert(env_home != nullptr);
62 if (!path.empty() && path[0] == '~')
63 path.replace(0, 1, env_home);
66 bool configure(int argc, char **argv)
68 const std::vector<std::string> default_config_paths = {
69 "~/.ncmpcpp/config",
70 xdg_config_home() + "ncmpcpp/config"
73 std::string bindings_path;
74 std::vector<std::string> config_paths;
76 po::options_description options("Options");
77 options.add_options()
78 ("host,h", po::value<std::string>()->default_value("localhost"), "connect to server at host")
79 ("port,p", po::value<int>()->default_value(6600), "connect to server at port")
80 ("current-song", po::value<std::string>()->implicit_value("{{{(%l) }{{%a - }%t}}|{%f}}"), "print current song using given format and exit")
81 ("config,c", po::value<std::vector<std::string>>(&config_paths)->default_value(default_config_paths, join<std::string>(default_config_paths, " AND ")), "specify configuration file(s)")
82 ("ignore-config-errors", "ignore unknown and invalid options in configuration files")
83 ("bindings,b", po::value<std::string>(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file")
84 ("screen,s", po::value<std::string>(), "specify the startup screen")
85 ("slave-screen,S", po::value<std::string>(), "specify the startup slave screen")
86 ("help,?", "show help message")
87 ("version,v", "display version information")
90 po::variables_map vm;
91 try
93 po::store(po::parse_command_line(argc, argv, options), vm);
95 if (vm.count("help"))
97 cout << "Usage: " << argv[0] << " [options]...\n" << options << "\n";
98 return false;
100 if (vm.count("version"))
102 std::cout << "ncmpcpp " << VERSION << "\n\n"
103 << "optional screens compiled-in:\n"
104 # ifdef HAVE_TAGLIB_H
105 << " - tag editor\n"
106 << " - tiny tag editor\n"
107 # endif
108 # ifdef HAVE_CURL_CURL_H
109 << " - artist info\n"
110 # endif
111 # ifdef ENABLE_OUTPUTS
112 << " - outputs\n"
113 # endif
114 # ifdef ENABLE_VISUALIZER
115 << " - visualizer\n"
116 # endif
117 # ifdef ENABLE_CLOCK
118 << " - clock\n"
119 # endif
120 << "\nencoding detection: "
121 # ifdef HAVE_LANGINFO_H
122 << "enabled"
123 # else
124 << "disabled"
125 # endif // HAVE_LANGINFO_H
126 << "\nbuilt with support for:"
127 # ifdef HAVE_CURL_CURL_H
128 << " curl"
129 # endif
130 # ifdef HAVE_FFTW3_H
131 << " fftw"
132 # endif
133 << " ncurses"
134 # ifdef HAVE_TAGLIB_H
135 << " taglib"
136 # endif
137 # ifdef NCMPCPP_UNICODE
138 << " unicode"
139 # endif
140 << "\n";
141 return false;
144 po::notify(vm);
145 // get home directory
146 env_home = getenv("HOME");
147 if (env_home == nullptr)
149 cerr << "Fatal error: HOME environment variable is not defined\n";
150 return false;
153 // read configuration
154 std::for_each(config_paths.begin(), config_paths.end(), expand_home);
155 if (Config.read(config_paths, vm.count("ignore-config-errors")) == false)
156 exit(1);
158 // if bindings file was not specified, use the one from main directory.
159 if (vm["bindings"].defaulted())
160 bindings_path = Config.ncmpcpp_directory + "bindings";
161 else
162 expand_home(bindings_path);
164 // read bindings
165 if (Bindings.read(bindings_path) == false)
166 exit(1);
167 Bindings.generateDefaults();
169 // create directories
170 boost::filesystem::create_directory(Config.ncmpcpp_directory);
171 boost::filesystem::create_directory(Config.lyrics_directory);
173 // try to get MPD connection details from environment variables
174 // as they take precedence over these from the configuration.
175 auto env_host = getenv("MPD_HOST");
176 auto env_port = getenv("MPD_PORT");
177 if (env_host != nullptr)
178 Mpd.SetHostname(env_host);
179 if (env_port != nullptr)
180 Mpd.SetPort(boost::lexical_cast<int>(env_port));
182 // if MPD connection details are provided as command line
183 // parameters, use them as their priority is the highest.
184 if (!vm["host"].defaulted())
185 Mpd.SetHostname(vm["host"].as<std::string>());
186 if (!vm["port"].defaulted())
187 Mpd.SetPort(vm["port"].as<int>());
188 Mpd.SetTimeout(Config.mpd_connection_timeout);
190 // print current song
191 if (vm.count("current-song"))
193 Mpd.Connect();
194 auto s = Mpd.GetCurrentSong();
195 if (!s.empty())
197 auto format = Format::parse(vm["current-song"].as<std::string>(), Format::Flags::Tag);
198 std::cout << Format::stringify<char>(format, &s);
199 return false;
203 // custom startup screen
204 if (vm.count("screen"))
206 auto screen = vm["screen"].as<std::string>();
207 Config.startup_screen_type = stringtoStartupScreenType(screen);
208 if (Config.startup_screen_type == ScreenType::Unknown)
210 std::cerr << "Unknown screen: " << screen << "\n";
211 exit(1);
215 // custom startup slave screen
216 if (vm.count("slave-screen"))
218 auto screen = vm["slave-screen"].as<std::string>();
219 Config.startup_slave_screen_type = stringtoStartupScreenType(screen);
220 if (Config.startup_slave_screen_type == ScreenType::Unknown)
222 std::cerr << "Unknown slave screen: " << screen << "\n";
223 exit(1);
227 catch (std::exception &e)
229 cerr << "Error while processing configuration: " << e.what() << "\n";
230 exit(1);
232 return true;