Code

don't declare local variable "options"
[ncmpc.git] / src / main.c
1 /* 
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
21 #include "config.h"
22 #include "ncmpc.h"
23 #include "mpdclient.h"
24 #include "support.h"
25 #include "options.h"
26 #include "conf.h"
27 #include "command.h"
28 #include "src_lyrics.h"
29 #include "screen.h"
30 #include "screen_utils.h"
31 #include "strfsong.h"
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <string.h>
38 #define BUFSIZE 1024
40 static mpdclient_t   *mpd = NULL;
41 static gboolean connected = FALSE;
42 static GTimer      *timer = NULL;
44 static const gchar *
45 error_msg(const gchar *msg)
46 {
47   gchar *p;
49   if( (p=strchr(msg, '}' )) == NULL )
50     return msg;
51   while( p && *p && (*p=='}' || *p==' ') )
52     p++;
54   return p;
55 }
57 static void
58 error_callback(mpdclient_t *c, gint error, const gchar *msg)
59 {
60         gint code = GET_ACK_ERROR_CODE(error);
62         error = error & 0xFF;
63         D("Error [%d:%d]> \"%s\"\n", error, code, msg);
64         switch (error) {
65         case MPD_ERROR_CONNPORT:
66         case MPD_ERROR_NORESPONSE:
67                 break;
68         case MPD_ERROR_ACK:
69                 screen_status_printf("%s", error_msg(msg));
70                 screen_bell();
71                 break;
72         default:
73                 screen_status_printf("%s", msg);
74                 screen_bell();
75                 doupdate();
76                 connected = FALSE;
77         }
78 }
80 static void
81 update_xterm_title(void)
82 {
83   static char title[BUFSIZE];
84   char tmp[BUFSIZE];
85   mpd_Status *status = NULL;
86   mpd_Song *song = NULL;
88   if( mpd )
89     {
90       status = mpd->status;
91       song = mpd->song;
92     }
94   if(options.xterm_title_format && status && song && IS_PLAYING(status->state))
95     {
96       strfsong(tmp, BUFSIZE, options.xterm_title_format, song);
97     }
98   else
99     g_strlcpy(tmp, PACKAGE " version " VERSION, BUFSIZE);
101   if( strncmp(title,tmp,BUFSIZE) )
102     {
103       g_strlcpy(title, tmp, BUFSIZE);
104       set_xterm_title("%s", title);
105     }
108 static void
109 exit_and_cleanup(void)
111   screen_exit();
112   set_xterm_title("");
113   printf("\n");
114   if( mpd )
115     {
116       mpdclient_disconnect(mpd);
117       mpd = mpdclient_free(mpd);
118     }
119   g_free(options.host);
120   g_free(options.password);
121   g_free(options.list_format);
122   g_free(options.status_format);
123   g_free(options.scroll_sep);
124   if( timer )
125     g_timer_destroy(timer);
128 static void
129 catch_sigint( int sig )
131         printf("\n%s\n", _("Exiting..."));
132         exit(EXIT_SUCCESS);
136 static void
137 catch_sigcont( int sig )
139         D("catch_sigcont()\n");
140 #ifdef ENABLE_RAW_MODE
141         reset_prog_mode(); /* restore tty modes */
142         refresh();
143 #endif
144         screen_resize();
147 void
148 sigstop(void)
150   def_prog_mode();  /* save the tty modes */
151   endwin();         /* end curses mode temporarily */
152   kill(0, SIGSTOP); /* issue SIGSTOP */
155 #ifndef NDEBUG
156 void 
157 D(const char *format, ...)
159   if( options.debug )
160     {
161       gchar *msg;
162       va_list ap;
163   
164       va_start(ap,format);
165       msg = g_strdup_vprintf(format,ap);
166       va_end(ap);
167       fprintf(stderr, "%s", msg);
168       g_free(msg);
169     }
171 #endif
173 int
174 main(int argc, const char *argv[])
176         struct sigaction act;
177         const char *charset = NULL;
178         gboolean key_error;
180 #ifdef HAVE_LOCALE_H
181         /* time and date formatting */
182         setlocale(LC_TIME,"");
183         /* care about sorting order etc */
184         setlocale(LC_COLLATE,"");
185         /* charset */
186         setlocale(LC_CTYPE,"");
187         /* initialize charset conversions */
188         charset_init(g_get_charset(&charset));
189         D("charset: %s\n", charset);
190 #endif
192         /* initialize i18n support */
193 #ifdef ENABLE_NLS
194         setlocale(LC_MESSAGES, "");
195         bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR);
196         bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
197         textdomain(GETTEXT_PACKAGE);
198 #endif
200         /* initialize options */
201         options_init();
203         /* parse command line options - 1 pass get configuration files */
204         options_parse(argc, argv);
206         /* read configuration */
207         read_configuration(&options);
209         /* check key bindings */
210         key_error = check_key_bindings(NULL, NULL, 0);
212         /* parse command line options - 2 pass */
213         options_parse(argc, argv);
215         /* setup signal behavior - SIGINT */
216         sigemptyset( &act.sa_mask );
217         act.sa_flags    = 0;
218         act.sa_handler = catch_sigint;
219         if( sigaction(SIGINT, &act, NULL)<0 ) {
220                 perror("signal");
221                 exit(EXIT_FAILURE);
222         }
224         /* setup signal behavior - SIGTERM */
225         sigemptyset( &act.sa_mask );
226         act.sa_flags    = 0;
227         act.sa_handler = catch_sigint;
228         if( sigaction(SIGTERM, &act, NULL)<0 ) {
229                 perror("sigaction()");
230                 exit(EXIT_FAILURE);
231         }
233         /* setup signal behavior - SIGCONT */
234         sigemptyset( &act.sa_mask );
235         act.sa_flags    = 0;
236         act.sa_handler = catch_sigcont;
237         if( sigaction(SIGCONT, &act, NULL)<0 ) {
238                 perror("sigaction(SIGCONT)");
239                 exit(EXIT_FAILURE);
240         }
242         /* setup signal behaviour - SIGHUP*/
243         sigemptyset( &act.sa_mask );
244         act.sa_flags    = 0;
245         act.sa_handler = catch_sigint;
246         if( sigaction(SIGHUP, &act, NULL)<0 ) {
247                 perror("sigaction(SIGHUP)");
248                 exit(EXIT_FAILURE);
249         }
251         /* install exit function */
252         atexit(exit_and_cleanup);
254         ncurses_init();
256         src_lyr_init ();
258         /* connect to our music player daemon */
259         mpd = mpdclient_new();
261         if (mpdclient_connect(mpd,
262                               options.host,
263                               options.port,
264                               10.0,
265                               options.password))
266                 exit(EXIT_FAILURE);
268         /* if no password is used, but the mpd wants one, the connection
269            might be established but no status information is avaiable */
270         mpdclient_update(mpd);
271         if (!mpd->status)
272                 screen_auth(mpd);
274         if (!mpd->status)
275                 exit(EXIT_FAILURE);
277         connected = TRUE;
278         D("Connected to MPD version %d.%d.%d\n",
279           mpd->connection->version[0],
280           mpd->connection->version[1],
281           mpd->connection->version[2]);
283         /* quit if mpd is pre 0.11.0 - song id not supported by mpd */
284         if( MPD_VERSION_LT(mpd, 0,11,0) ) {
285                 fprintf(stderr,
286                         _("Error: MPD version %d.%d.%d is to old (0.11.0 needed).\n"),
287                         mpd->connection->version[0],
288                         mpd->connection->version[1],
289                         mpd->connection->version[2]);
290                 exit(EXIT_FAILURE);
291         }
293         /* initialize curses */
294         screen_init(mpd);
295         /* install error callback function */
296         mpdclient_install_error_callback(mpd, error_callback);
298         /* initialize timer */
299         timer = g_timer_new();
301         connected = TRUE;
302         while (connected || options.reconnect) {
303                 static gdouble t = G_MAXDOUBLE;
305                 if( key_error ) {
306                         char buf[BUFSIZE];
308                         key_error=check_key_bindings(NULL, buf, BUFSIZE);
309                         screen_status_printf("%s", buf);
310                 }
312                 if( connected && (t>=MPD_UPDATE_TIME || mpd->need_update) ) {
313                         mpdclient_update(mpd);
314                         g_timer_start(timer);
315                 }
317                 if( connected ) {
318                         command_t cmd;
320                         screen_update(mpd);
321                         if( (cmd=get_keyboard_command()) != CMD_NONE )
322                                 {
323                                         screen_cmd(mpd, cmd);
324                                         if( cmd==CMD_VOLUME_UP || cmd==CMD_VOLUME_DOWN)
325                                                 /* make shure we dont update the volume yet */
326                                                 g_timer_start(timer);
327                                 }
328                         else
329                                 screen_idle(mpd);
330                 } else if( options.reconnect ) {
331                         screen_status_printf(_("Connecting to %s...  [Press %s to abort]"),
332                                              options.host, get_key_names(CMD_QUIT,0) );
334                         if( get_keyboard_command_with_timeout(MPD_RECONNECT_TIME)==CMD_QUIT)
335                                 exit(EXIT_SUCCESS);
337                         if (mpdclient_connect(mpd,
338                                               options.host, options.port,
339                                               1.5,
340                                               options.password) == 0) {
341                                 screen_status_printf(_("Connected to %s!"), options.host);
342                                 connected = TRUE;
343                         }
345                         doupdate();
346                 }
348                 if (options.enable_xterm_title)
349                         update_xterm_title();
351                 t = g_timer_elapsed(timer, NULL);
352         }
353         exit(EXIT_FAILURE);