Patch to display lyrics

I've made a small patch to display the lyrics of the file who is currently read. They are fetch from a file on the disk in the same directory and with the name but without extension. It looks like the help screen because it is (almost) the same code. You called it by pressing L.

Please post remarks and excuse me english (it's not my mother tongue).

Here is the patch :


Index: moc/interface.c
===================================================================
--- moc/interface.c (revision 2093)
+++ moc/interface.c (working copy)
@@ -56,6 +56,7 @@
#include "decoder.h"
#include "themes.h"
#include "softmixer.h"
+#include "lyrics.h"

#define INTERFACE_LOG "mocp_client_log"

@@ -2953,6 +2954,8 @@
{
if (iface_in_help())
iface_handle_help_key (k);
+ if (iface_in_lyrics())
+ iface_handle_lyrics_key (k);
else if (iface_in_entry())
entry_key (k);
else if (iface_in_theme_menu())
@@ -3044,6 +3047,9 @@
case KEY_CMD_HELP:
iface_switch_to_help ();
break;
+ case KEY_CMD_LYRICS:
+ iface_switch_to_lyrics ();
+ break;
case KEY_CMD_HIDE_MESSAGE:
iface_disable_message ();
break;
@@ -3347,6 +3353,7 @@

windows_end ();
keys_cleanup ();
+ lyrics_cleanup ();

plist_free (dir_plist);
plist_free (playlist);
Index: moc/keys.c
===================================================================
--- moc/keys.c (revision 2093)
+++ moc/keys.c (working copy)
@@ -736,6 +736,14 @@
{ KEY_F(10), -1 },
1
},
+ {
+ KEY_CMD_LYRICS,
+ "show_lyrics",
+ "Display lyrics of the current song (if available)",
+ CON_MENU,
+ { 'L', -1 },
+ 1
+ },
{
KEY_CMD_TOGGLE_PLAYLIST_FULL_PATHS,
"playlist_full_paths",
Index: moc/keys.h
===================================================================
--- moc/keys.h (revision 2093)
+++ moc/keys.h (working copy)
@@ -89,6 +89,7 @@
KEY_CMD_EXEC10,
KEY_CMD_TOGGLE_PLAYLIST_FULL_PATHS,
KEY_CMD_TOGGLE_SOFTMIXER,
+ KEY_CMD_LYRICS,
KEY_CMD_WRONG
};

Index: moc/interface_elements.c
===================================================================
--- moc/interface_elements.c (revision 2093)
+++ moc/interface_elements.c (working copy)
@@ -56,6 +56,7 @@
#include "protocol.h"
#include "interface.h"
#include "utf8.h"
+#include "lyrics.h"

#define STARTUP_MESSAGE "Welcome to " PACKAGE_STRING "!"
#define HISTORY_SIZE 50
@@ -128,8 +129,11 @@
char *curr_file; /* currently played file. */

int in_help; /* are we displaying help screen? */
+ int in_lyrics; /* are we displaying lyrics screen? */
int too_small; /* is the terminal window too small to display mocp? */
int help_screen_top; /* first visible line of the help screen. */
+ int lyrics_screen_top; /* first visible line of the lyrics screen. */
+ int lyrics_nb_lines; /* line number of the current lyrics file. */

struct side_menu menus[3];
char *layout_fmt;
@@ -871,8 +875,11 @@

w->curr_file = NULL;
w->in_help = 0;
+ w->in_lyrics = 0;
w->too_small = 0;
w->help_screen_top = 0;
+ w->lyrics_screen_top = 0;
+ w->lyrics_nb_lines = 0;
w->layout_fmt = xstrdup (layout_fmt);

res = parse_layout (&l, layout_fmt);
@@ -1626,12 +1633,52 @@
}
}

-static void main_win_draw (const struct main_win *w)
+static void main_win_draw_lyrics_screen (struct main_win *w)
{
int i;
+ int max_lines;
+ int lyrics_lines;
+ char **lyrics;

+ assert (w != NULL);
+ assert (w->in_lyrics);
+
+ max_lines = w->lyrics_screen_top + LINES - 6;
+
+ lyrics = get_lyrics_text (w->win, w->curr_file, &lyrics_lines);
+ w->lyrics_nb_lines = lyrics_lines;
+
+ werase (w->win);
+ wbkgd (w->win, get_color(CLR_BACKGROUND));
+
+ wmove (w->win, 0, 0);
+ if (w->lyrics_screen_top != 0) {
+ wattrset (w->win, get_color(CLR_MESSAGE));
+ xmvwaddstr (w->win, 0, COLS/2 - (sizeof("...MORE...")-1)/2,
+ "...MORE...");
+ }
+ wmove (w->win, 1, 0);
+ wattrset (w->win, get_color(CLR_LEGEND));
+ for (i = w->lyrics_screen_top; i < max_lines && i < lyrics_lines; i++) {
+ xwaddstr (w->win, lyrics);
+ /* TODO supprimer ce \n
+ waddch (w->win, '\n');*/
+ }
+ if (i != lyrics_lines) {
+ wattrset (w->win, get_color(CLR_MESSAGE));
+ xmvwaddstr (w->win, LINES-5,
+ COLS/2 - (sizeof("...MORE...")-1)/2,
+ "...MORE...");
+ }
+}
+static void main_win_draw (struct main_win *w)
+{
+ int i;
+
if (w->in_help)
main_win_draw_help_screen (w);
+ else if (w->in_lyrics)
+ main_win_draw_lyrics_screen (w);
else if (w->too_small)
main_win_draw_too_small_screen (w);
else {
@@ -1740,6 +1787,14 @@
main_win_draw (w);
}

+static void main_win_switch_to_lyrics (struct main_win *w)
+{
+ assert (w != NULL);
+
+ w->in_lyrics = 1;
+ main_win_draw (w);
+}
+
static void main_win_create_themes_menu (struct main_win *w)
{
struct window_params p;
@@ -1791,6 +1846,13 @@
return w->in_help;
}

+static int main_win_in_lyrics (const struct main_win *w)
+{
+ assert (w != NULL);
+
+ return w->in_lyrics;
+}
+
static int main_win_in_plist_menu (const struct main_win *w)
{
assert (w != NULL);
@@ -1985,6 +2047,31 @@
main_win_draw (w);
}

+static void main_win_handle_lyrics_key (struct main_win *w,
+ const struct iface_key *k)
+{
+ assert (w != NULL);
+ assert (w->in_lyrics);
+
+ if ((k->type == IFACE_KEY_FUNCTION && (
+ k->key.func == KEY_DOWN
+ || k->key.func == KEY_NPAGE))
+ || (k->key.ucs == '\n')) {
+ if (w->lyrics_screen_top + LINES - 5 <= w->lyrics_nb_lines)
+ w->lyrics_screen_top++;
+ }
+ else {
+ if (k->type == IFACE_KEY_FUNCTION && (k->key.func == KEY_UP
+ || k->key.func == KEY_PPAGE)) {
+ if (w->lyrics_screen_top > 0)
+ w->lyrics_screen_top--;
+ }
+ else if (k->key.func != KEY_RESIZE)
+ w->in_lyrics = 0;
+ }
+
+ main_win_draw (w);
+}
static void main_win_swap_plist_items (struct main_win *w, const char *file1,
const char *file2)
{
@@ -3648,6 +3735,23 @@
iface_refresh_screen ();
}

+int iface_in_lyrics ()
+{
+ return main_win_in_lyrics (&main_win);
+}
+
+void iface_switch_to_lyrics ()
+{
+ main_win_switch_to_lyrics (&main_win);
+ iface_refresh_screen ();
+}
+
+void iface_handle_lyrics_key (const struct iface_key *k)
+{
+ main_win_handle_lyrics_key (&main_win, k);
+ iface_refresh_screen ();
+}
+
void iface_toggle_layout ()
{
static int curr_layout = 1;
Index: moc/interface_elements.h
===================================================================
--- moc/interface_elements.h (revision 2093)
+++ moc/interface_elements.h (working copy)
@@ -100,6 +100,9 @@
int iface_in_help ();
void iface_switch_to_help ();
void iface_handle_help_key (const struct iface_key *k);
+int iface_in_lyrics ();
+void iface_switch_to_lyrics ();
+void iface_handle_lyrics_key (const struct iface_key *k);
void iface_toggle_layout ();
void iface_swap_plist_items (const char *file1, const char *file2);
void iface_make_visible (const enum iface_menu menu, const char *file);
Index: moc/lyrics.c
===================================================================
--- moc/lyrics.c (revision 0)
+++ moc/lyrics.c (revision 0)
@@ -0,0 +1,103 @@
+/*
+ * MOC - music on console
+ * Copyright (C) 2004-2005 Damian Pietras
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "lyrics.h"
+#include "common.h"
+#include "files.h"
+
+#define LYRICS_LINE_NUMBER 128
+static char *lyrics[LYRICS_LINE_NUMBER];
+const unsigned short LINE_SIZE = 128;
+
+void lyrics_remove_prefix (const char *filename, char *new_name)
+{
+ unsigned short last_dot_pos = 0, i = 0;
+ for (i = 0; i < strlen(filename); i++) {
+ if (filename == '.')
+ last_dot_pos = i;
+ }
+ strncpy(new_name, filename, last_dot_pos);
+ new_name[last_dot_pos] = '\0';
+}
+
+void lyrics_cleanup ()
+{
+ unsigned int i;
+ for (i = 0; i < LYRICS_LINE_NUMBER; i++)
+ free (lyrics);
+}
+
+char **get_lyrics_text (const WINDOW *w, const char *filename, int *num)
+{
+ char *lyrics_filename;
+ char *lyrics_line;
+ FILE *lyrics_file = NULL;
+ unsigned short i = 0;
+ int x, y, space;
+
+ getmaxyx(w,x,y);
+ if (y > LINE_SIZE)
+ y = LINE_SIZE;
+
+ if (filename == NULL) {
+ lyrics[0] = xmalloc (sizeof(char) * 20);
+ strncpy (lyrics[0], "No file reading", 20);
+ *num = 1;
+ return lyrics;
+ }
+ else if (is_url(filename)) {
+ lyrics[0] = xmalloc (sizeof(char) * 30);
+ strncpy (lyrics[0], "URL lyrics is not supported", 30);
+ *num = 1;
+ return lyrics;
+ }
+ else {
+ lyrics_filename = xmalloc (sizeof(char) * 128);
+ lyrics_remove_prefix (filename, lyrics_filename);
+ }
+
+ lyrics_file = fopen (lyrics_filename, "r");
+ if (lyrics_file != NULL) {
+ lyrics_line = xmalloc (sizeof(char) * LINE_SIZE);
+ while (fgets(lyrics_line, y, lyrics_file) != NULL) {
+ lyrics = xmalloc (sizeof(char) * LINE_SIZE);
+ if (strlen(lyrics_line) < (y-1)) {
+ space = (y-strlen(lyrics_line))/2;
+ memset(lyrics, ' ', space);
+ strcat(lyrics, lyrics_line);
+ }
+ else {
+ strncpy (lyrics, lyrics_line, y-1);
+ lyrics[y] = '\0';
+ }
+ i++;
+ }
+ *num = i;
+ fclose (lyrics_file);
+ free (lyrics_line);
+ free (lyrics_filename);
+ return lyrics;
+ }
+ else {
+ lyrics[0] = xmalloc (sizeof(char) * 80);
+ strncpy (lyrics[0], "No lyrics found !", 79);
+ *num = 1;
+ free (lyrics_filename);
+ return lyrics;
+ }
+ free (lyrics_filename);
+ abort ();
+ return lyrics;
+}
+
Index: moc/lyrics.h
===================================================================
--- moc/lyrics.h (revision 0)
+++ moc/lyrics.h (revision 0)
@@ -0,0 +1,18 @@
+#ifndef LYRICS_H
+#define LYRICS_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#ifdef HAVE_NCURSESW_H
+# include
+#elif HAVE_NCURSES_H
+# include
+#elif HAVE_CURSES_H
+# include
+#endif
+
+void lyrics_cleanup ();
+char **get_lyrics_text (const WINDOW*, const char*, int*);
+
+#endif
Index: moc/Makefile.am
===================================================================
--- moc/Makefile.am (revision 2093)
+++ moc/Makefile.am (working copy)
@@ -56,7 +56,9 @@
utf8.c \
utf8.h \
softmixer.c \
- softmixer.h
+ softmixer.h \
+ lyrics.h \
+ lyrics.c
EXTRA_mocp_SOURCES = gnugetopt.h \
getopt.c \
getopt1.c \

Thanks for the patch. I have few questions/suggestions:

- Lyrics are expected to be in the same place where the played file is, but in a file without an extension?
- lyrics_remove_prefix() can be simplified using strrchr().
- I don't think you free memory in a proper way: lyrics_cleanup() calls free() for every lyrics line, but doesn't check if it was actually used (doesn't check if it's NULL). Loading a new lyric calls malloc() for every line but the previously loaded lyric's lines are not free()ed.

  • For example, if you are reading '/home/orphee/fs/music/yankee_bayonet.ogg', the lyrics are search in '/home/orphee/fs/music/yankee_bayonet'
  • reworked lyrics_remove_prefix() (I was quite sure there was a better way of doing this but I didn't manage to find it)
  • Now, I think the memory is better managed (get_lyrics_text() called less often and always after lyrics_cleanup()). But there is still a problem, if I remove
    memset (lyrics[i], '\0', strlen(lyrics[i]));

    , it's quite strange.

Here is the new patch:

<br /> Index: moc/interface.c<br /> ===================================================================<br /> --- moc/interface.c (revision 2094)<br /> +++ moc/interface.c (working copy)<br /> @@ -1577,7 +1577,7 @@<br /> }<br /> else<br /> logit ("The server already has my playlist");<br /> -<br /> + iface_load_lyrics (file);<br /> send_int_to_srv (CMD_PLAY);<br /> send_str_to_srv (file);</p> <p>@@ -2953,6 +2953,8 @@<br /> {<br /> if (iface_in_help())<br /> iface_handle_help_key (k);<br /> + if (iface_in_lyrics())<br /> + iface_handle_lyrics_key (k);<br /> else if (iface_in_entry())<br /> entry_key (k);<br /> else if (iface_in_theme_menu())<br /> @@ -3044,6 +3046,9 @@<br /> case KEY_CMD_HELP:<br /> iface_switch_to_help ();<br /> break;<br /> + case KEY_CMD_LYRICS:<br /> + iface_switch_to_lyrics ();<br /> + break;<br /> case KEY_CMD_HIDE_MESSAGE:<br /> iface_disable_message ();<br /> break;<br /> Index: moc/keys.c<br /> ===================================================================<br /> --- moc/keys.c (revision 2094)<br /> +++ moc/keys.c (working copy)<br /> @@ -736,6 +736,14 @@<br /> { KEY_F(10), -1 },<br /> 1<br /> },<br /> + {<br /> + KEY_CMD_LYRICS,<br /> + "show_lyrics",<br /> + "Display lyrics of the current song (if available)",<br /> + CON_MENU,<br /> + { 'L', -1 },<br /> + 1<br /> + },<br /> {<br /> KEY_CMD_TOGGLE_PLAYLIST_FULL_PATHS,<br /> "playlist_full_paths",<br /> Index: moc/keys.h<br /> ===================================================================<br /> --- moc/keys.h (revision 2094)<br /> +++ moc/keys.h (working copy)<br /> @@ -89,6 +89,7 @@<br /> KEY_CMD_EXEC10,<br /> KEY_CMD_TOGGLE_PLAYLIST_FULL_PATHS,<br /> KEY_CMD_TOGGLE_SOFTMIXER,<br /> + KEY_CMD_LYRICS,<br /> KEY_CMD_WRONG<br /> };</p> <p>Index: moc/interface_elements.c<br /> ===================================================================<br /> --- moc/interface_elements.c (revision 2094)<br /> +++ moc/interface_elements.c (working copy)<br /> @@ -56,6 +56,7 @@<br /> #include "protocol.h"<br /> #include "interface.h"<br /> #include "utf8.h"<br /> +#include "lyrics.h"</p> <p> #define STARTUP_MESSAGE "Welcome to " PACKAGE_STRING "!"<br /> #define HISTORY_SIZE 50<br /> @@ -130,7 +131,11 @@<br /> int in_help; /* are we displaying help screen? */<br /> int too_small; /* is the terminal window too small to display mocp? */<br /> int help_screen_top; /* first visible line of the help screen. */<br /> -<br /> + int in_lyrics; /* are we displaying lyrics screen? */<br /> + int lyrics_screen_top; /* first visible line of the lyrics screen. */<br /> + int lyrics_nb_lines; /* line number of the current lyrics file. */<br /> + char **lyrics_array; /* lyrics of the current song */<br /> +<br /> struct side_menu menus[3];<br /> char *layout_fmt;<br /> int selected_menu; /* which menu is currently selected by the user */<br /> @@ -871,8 +876,11 @@</p> <p> w->curr_file = NULL;<br /> w->in_help = 0;<br /> + w->in_lyrics = 0;<br /> w->too_small = 0;<br /> w->help_screen_top = 0;<br /> + w->lyrics_screen_top = 0;<br /> + w->lyrics_nb_lines = 0;<br /> w->layout_fmt = xstrdup (layout_fmt);</p> <p> res = parse_layout (&amp;l, layout_fmt);<br /> @@ -1626,12 +1634,45 @@<br /> }<br /> }</p> <p>-static void main_win_draw (const struct main_win *w)<br /> +static void main_win_draw_lyrics_screen (const struct main_win *w)<br /> {<br /> int i;<br /> + int max_lines;</p> <p>+ assert (w != NULL);<br /> + assert (w->in_lyrics);<br /> +<br /> + max_lines = w->lyrics_screen_top + LINES - 6;<br /> +<br /> + werase (w->win);<br /> + wbkgd (w->win, get_color(CLR_BACKGROUND));<br /> +<br /> + wmove (w->win, 0, 0);<br /> + if (w->lyrics_screen_top != 0) {<br /> + wattrset (w->win, get_color(CLR_MESSAGE));<br /> + xmvwaddstr (w->win, 0, COLS/2 - (sizeof("...MORE...")-1)/2,<br /> + "...MORE...");<br /> + }<br /> + wmove (w->win, 1, 0);<br /> + wattrset (w->win, get_color(CLR_LEGEND));<br /> + for (i = w->lyrics_screen_top; i < max_lines &amp;& i < w->lyrics_nb_lines; i++) {<br /> + xwaddstr (w->win, w->lyrics_array[i]);<br /> + }<br /> + if (i != w->lyrics_nb_lines) {<br /> + wattrset (w->win, get_color(CLR_MESSAGE));<br /> + xmvwaddstr (w->win, LINES-5,<br /> + COLS/2 - (sizeof("...MORE...")-1)/2,<br /> + "...MORE...");<br /> + }<br /> +}<br /> +static void main_win_draw (struct main_win *w)<br /> +{<br /> + int i;<br /> +<br /> if (w->in_help)<br /> main_win_draw_help_screen (w);<br /> + else if (w->in_lyrics)<br /> + main_win_draw_lyrics_screen (w);<br /> else if (w->too_small)<br /> main_win_draw_too_small_screen (w);<br /> else {<br /> @@ -1740,6 +1781,14 @@<br /> main_win_draw (w);<br /> }</p> <p>+static void main_win_switch_to_lyrics (struct main_win *w)<br /> +{<br /> + assert (w != NULL);<br /> +<br /> + w->in_lyrics = 1;<br /> + main_win_draw (w);<br /> +}<br /> +<br /> static void main_win_create_themes_menu (struct main_win *w)<br /> {<br /> struct window_params p;<br /> @@ -1791,6 +1840,13 @@<br /> return w->in_help;<br /> }</p> <p>+static int main_win_in_lyrics (const struct main_win *w)<br /> +{<br /> + assert (w != NULL);<br /> +<br /> + return w->in_lyrics;<br /> +}<br /> +<br /> static int main_win_in_plist_menu (const struct main_win *w)<br /> {<br /> assert (w != NULL);<br /> @@ -1985,6 +2041,31 @@<br /> main_win_draw (w);<br /> }</p> <p>+static void main_win_handle_lyrics_key (struct main_win *w,<br /> + const struct iface_key *k)<br /> +{<br /> + assert (w != NULL);<br /> + assert (w->in_lyrics);<br /> +<br /> + if ((k->type == IFACE_KEY_FUNCTION &amp;& (<br /> + k->key.func == KEY_DOWN<br /> + || k->key.func == KEY_NPAGE))<br /> + || (k->key.ucs == '\n')) {<br /> + if (w->lyrics_screen_top + LINES - 5 <= w->lyrics_nb_lines)<br /> + w->lyrics_screen_top++;<br /> + }<br /> + else {<br /> + if (k->type == IFACE_KEY_FUNCTION &amp;& (k->key.func == KEY_UP<br /> + || k->key.func == KEY_PPAGE)) {<br /> + if (w->lyrics_screen_top > 0)<br /> + w->lyrics_screen_top--;<br /> + }<br /> + else if (k->key.func != KEY_RESIZE)<br /> + w->in_lyrics = 0;<br /> + }<br /> +<br /> + main_win_draw (w);<br /> +}<br /> static void main_win_swap_plist_items (struct main_win *w, const char *file1,<br /> const char *file2)<br /> {<br /> @@ -3137,6 +3218,8 @@<br /> /* Make sure that the next line after we exit will be "clear". */<br /> putchar ('\n');<br /> }<br /> +<br /> + lyrics_cleanup (main_win.lyrics_nb_lines);<br /> }</p> <p> static void iface_refresh_screen ()<br /> @@ -3648,6 +3731,23 @@<br /> iface_refresh_screen ();<br /> }</p> <p>+int iface_in_lyrics ()<br /> +{<br /> + return main_win_in_lyrics (&amp;main_win);<br /> +}<br /> +<br /> +void iface_switch_to_lyrics ()<br /> +{<br /> + main_win_switch_to_lyrics (&amp;main_win);<br /> + iface_refresh_screen ();<br /> +}<br /> +<br /> +void iface_handle_lyrics_key (const struct iface_key *k)<br /> +{<br /> + main_win_handle_lyrics_key (&amp;main_win, k);<br /> + iface_refresh_screen ();<br /> +}<br /> +<br /> void iface_toggle_layout ()<br /> {<br /> static int curr_layout = 1;<br /> @@ -3716,3 +3816,11 @@<br /> if (!options_get_int("UseCursorSelection"))<br /> curs_set (0);<br /> }<br /> +<br /> +void iface_load_lyrics (const char *file)<br /> +{<br /> + int lines;<br /> + lyrics_cleanup (main_win.lyrics_nb_lines);<br /> + main_win.lyrics_array = get_lyrics_text (main_win.win, file, &amp;lines);<br /> + main_win.lyrics_nb_lines = lines;<br /> +}<br /> Index: moc/interface_elements.h<br /> ===================================================================<br /> --- moc/interface_elements.h (revision 2094)<br /> +++ moc/interface_elements.h (working copy)<br /> @@ -100,6 +100,9 @@<br /> int iface_in_help ();<br /> void iface_switch_to_help ();<br /> void iface_handle_help_key (const struct iface_key *k);<br /> +int iface_in_lyrics ();<br /> +void iface_switch_to_lyrics ();<br /> +void iface_handle_lyrics_key (const struct iface_key *k);<br /> void iface_toggle_layout ();<br /> void iface_swap_plist_items (const char *file1, const char *file2);<br /> void iface_make_visible (const enum iface_menu menu, const char *file);<br /> @@ -108,5 +111,6 @@<br /> const enum file_type type);<br /> void iface_temporary_exit ();<br /> void iface_restore ();<br /> +void iface_load_lyrics (const char *file);</p> <p> #endif<br /> Index: moc/lyrics.c<br /> ===================================================================<br /> --- moc/lyrics.c (revision 0)<br /> +++ moc/lyrics.c (revision 0)<br /> @@ -0,0 +1,103 @@<br /> +/*<br /> + * MOC - music on console<br /> + * Copyright (C) 2004-2005 Damian Pietras <daper@daper.net><br /> + *<br /> + * This program is free software; you can redistribute it and/or modify<br /> + * it under the terms of the GNU General Public License as published by<br /> + * the Free Software Foundation; either version 2 of the License, or<br /> + * (at your option) any later version.<br /> + *<br /> + */<br /> +<br /> +#ifdef HAVE_CONFIG_H<br /> +# include "config.h"<br /> +#endif<br /> +#include "lyrics.h"<br /> +#include "common.h"<br /> +#include "files.h"<br /> +#include "log.h"<br /> +<br /> +#define LYRICS_LINE_NUMBER 128<br /> +static char *lyrics[LYRICS_LINE_NUMBER];<br /> +<br /> +const unsigned short LINE_SIZE = 128;<br /> +const unsigned short FILENAME_SIZE = 200;<br /> +<br /> +void lyrics_remove_prefix (const char *filename, char *new_name)<br /> +{<br /> + strncpy(new_name, filename, strlen(filename)-strlen(strrchr(filename, '.')));<br /> +}<br /> +<br /> +void lyrics_cleanup (const unsigned int n)<br /> +{<br /> + unsigned int i;<br /> + for (i = 0; i < n &amp;& lyrics[i] != NULL; i++) {<br /> + memset (lyrics[i], '\0', strlen(lyrics[i]));<br /> + free (lyrics[i]);<br /> + }<br /> +}<br /> +<br /> +char **get_lyrics_text (const WINDOW *w, const char *filename, int *num)<br /> +{<br /> + char *lyrics_filename;<br /> + char *lyrics_line;<br /> + FILE *lyrics_file = NULL;<br /> + unsigned short i = 0;<br /> + int x, y, space;<br /> +<br /> + getmaxyx(w,x,y);<br /> + if (y > LINE_SIZE)<br /> + y = LINE_SIZE;<br /> +<br /> + if (filename == NULL) {<br /> + lyrics[0] = xmalloc (sizeof(char) * 20);<br /> + strncpy (lyrics[0], "No file reading", 20);<br /> + *num = 1;<br /> + return lyrics;<br /> + }<br /> +<br /> + if (is_url (filename)) {<br /> + lyrics[0] = xmalloc (sizeof(char) * 30);<br /> + strncpy (lyrics[0], "URL lyrics is not supported", 30);<br /> + *num = 1;<br /> + return lyrics;<br /> + }<br /> +<br /> + lyrics_filename = xmalloc (sizeof(char) * FILENAME_SIZE);<br /> + memset (lyrics_filename, '\0', FILENAME_SIZE);<br /> + lyrics_remove_prefix (filename, lyrics_filename);<br /> +<br /> + lyrics_file = fopen (lyrics_filename, "r");<br /> + if (lyrics_file != NULL) {<br /> + lyrics_line = xmalloc (sizeof(char) * LINE_SIZE);<br /> + while (fgets(lyrics_line, y, lyrics_file) != NULL) {<br /> + lyrics[i] = xmalloc (sizeof(char) * LINE_SIZE);<br /> + if (strlen(lyrics_line) < (y-1)) {<br /> + space = (y-strlen(lyrics_line))/2;<br /> + memset(lyrics[i], ' ', space);<br /> + strcat(lyrics[i], lyrics_line);<br /> + }<br /> + else {<br /> + strncpy (lyrics[i], lyrics_line, y-1);<br /> + lyrics[i][y] = '\0';<br /> + }<br /> + i++;<br /> + }<br /> + *num = i;<br /> + fclose (lyrics_file);<br /> + free (lyrics_line);<br /> + free (lyrics_filename);<br /> + return lyrics;<br /> + }<br /> + else {<br /> + lyrics[0] = xmalloc (sizeof(char) * 20);<br /> + strncpy (lyrics[0], "No lyrics found !", 20);<br /> + *num = 1;<br /> + free (lyrics_filename);<br /> + return lyrics;<br /> + }<br /> + free (lyrics_filename);<br /> + abort ();<br /> + return lyrics;<br /> +}<br /> +<br /> Index: moc/lyrics.h<br /> ===================================================================<br /> --- moc/lyrics.h (revision 0)<br /> +++ moc/lyrics.h (revision 0)<br /> @@ -0,0 +1,18 @@<br /> +#ifndef LYRICS_H<br /> +#define LYRICS_H<br /> +<br /> +#ifdef HAVE_CONFIG_H<br /> +# include "config.h"<br /> +#endif<br /> +#ifdef HAVE_NCURSESW_H<br /> +# include <ncursesw/curses.h><br /> +#elif HAVE_NCURSES_H<br /> +# include <ncurses.h><br /> +#elif HAVE_CURSES_H<br /> +# include <curses.h><br /> +#endif<br /> +<br /> +void lyrics_cleanup (const unsigned int n);<br /> +char **get_lyrics_text (const WINDOW*, const char*, int*);<br /> +<br /> +#endif<br /> Index: moc/Makefile.am<br /> ===================================================================<br /> --- moc/Makefile.am (revision 2094)<br /> +++ moc/Makefile.am (working copy)<br /> @@ -56,7 +56,9 @@<br /> utf8.c \<br /> utf8.h \<br /> softmixer.c \<br /> - softmixer.h<br /> + softmixer.h \<br /> + lyrics.h \<br /> + lyrics.c<br /> EXTRA_mocp_SOURCES = gnugetopt.h \<br /> getopt.c \<br /> getopt1.c \<br />

Sorry for the late response, I have not much time for MOC.

Doesn't it behave strange because of this?

<br /> lyrics[i] = xmalloc (sizeof(char) * LINE_SIZE);<br /> if (strlen(lyrics_line) < (y-1)) {<br /> space = (y-strlen(lyrics_line))/2;<br /> memset(lyrics[i], ' ', space);<br /> strcat(lyrics[i], lyrics_line);<br /> }<br />

You are using strcat() to append to a string that is not null-terminated. After memset there should be lyrics[i][space] = '\0'. If it works, I'll apply the patch.

You were right, it works with null-terminated string (after too python, string handling is a pain in C). I've also add some lines to load lyrics every time a new file is read.
The patch is here : http://geraudsoft.info/tmp/lyrics.patch

Works for me :) I'll include the patch, but I need your full name (to be put in the changelog and Copyright in the lyrics.c file).

Thanks. My name is Géraud Le Falher.

Thanks, patch applied.