summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBilal Akhtar <bilalakhtar@ubuntu.com>2011-05-03 10:34:47 +0530
committerBilal Akhtar <bilalakhtar@ubuntu.com>2011-05-03 10:34:47 +0530
commit95ef69053691c5c731d0a6538de118ea52a3cd0a (patch)
tree60a79db75770323a8af7783831aad06f6aef0a01 /src
parent2debbc92898682dfe0c81f1ce4999175887ec922 (diff)
Imported Upstream version 2.5.0
Diffstat (limited to 'src')
-rw-r--r--src/audacious/Makefile26
-rw-r--r--src/audacious/audconfig.c67
-rw-r--r--src/audacious/audconfig.h12
-rw-r--r--src/audacious/chardet.c32
-rw-r--r--src/audacious/compatibility.h26
-rw-r--r--src/audacious/configdb.c32
-rw-r--r--src/audacious/credits.c12
-rw-r--r--src/audacious/dbus-service.h2
-rw-r--r--src/audacious/dbus.c51
-rw-r--r--src/audacious/drct-api.h6
-rw-r--r--src/audacious/drct.c108
-rw-r--r--src/audacious/effect.c87
-rw-r--r--src/audacious/effect.h5
-rw-r--r--src/audacious/equalizer_preset.c9
-rw-r--r--src/audacious/folder-add.c203
-rw-r--r--src/audacious/general.c118
-rw-r--r--src/audacious/general.h11
-rwxr-xr-xsrc/audacious/glib-compat.h26
-rw-r--r--src/audacious/gtk-compat.h89
-rw-r--r--src/audacious/images/about-logo.pngbin19186 -> 20019 bytes
-rw-r--r--src/audacious/images/album.pngbin0 -> 29863 bytes
-rw-r--r--src/audacious/images/appearance.pngbin4023 -> 3426 bytes
-rw-r--r--src/audacious/images/audio.pngbin4732 -> 3314 bytes
-rw-r--r--src/audacious/images/connectivity.pngbin3299 -> 3241 bytes
-rw-r--r--src/audacious/images/menu_playlist.pngbin419 -> 688 bytes
-rw-r--r--src/audacious/images/menu_plugin.pngbin609 -> 960 bytes
-rw-r--r--src/audacious/images/menu_queue_toggle.pngbin611 -> 870 bytes
-rw-r--r--src/audacious/images/play.pngbin521 -> 0 bytes
-rw-r--r--src/audacious/images/playback.pngbin2494 -> 0 bytes
-rw-r--r--src/audacious/images/playlist.pngbin2945 -> 2337 bytes
-rw-r--r--src/audacious/images/plugins.pngbin3660 -> 4590 bytes
-rw-r--r--src/audacious/images/replay_gain.pngbin1897 -> 2177 bytes
-rw-r--r--src/audacious/interface.c131
-rw-r--r--src/audacious/interface.h19
-rw-r--r--src/audacious/intl/ChangeLog4
-rw-r--r--src/audacious/intl/Makefile40
-rw-r--r--src/audacious/intl/VERSION1
-rw-r--r--src/audacious/intl/bindtextdom.c374
-rw-r--r--src/audacious/intl/config.charset467
-rw-r--r--src/audacious/intl/dcgettext.c59
-rw-r--r--src/audacious/intl/dcigettext.c1238
-rw-r--r--src/audacious/intl/dcngettext.c60
-rw-r--r--src/audacious/intl/dgettext.c59
-rw-r--r--src/audacious/intl/dngettext.c61
-rw-r--r--src/audacious/intl/eval-plural.h114
-rw-r--r--src/audacious/intl/explodename.c192
-rw-r--r--src/audacious/intl/finddomain.c195
-rw-r--r--src/audacious/intl/gettext.c64
-rw-r--r--src/audacious/intl/gettextP.h224
-rw-r--r--src/audacious/intl/gmo.h148
-rw-r--r--src/audacious/intl/hash-string.h59
-rw-r--r--src/audacious/intl/intl-compat.c151
-rw-r--r--src/audacious/intl/l10nflist.c453
-rw-r--r--src/audacious/intl/libgnuintl.h309
-rw-r--r--src/audacious/intl/loadinfo.h156
-rw-r--r--src/audacious/intl/loadmsgcat.c1322
-rw-r--r--src/audacious/intl/localcharset.c398
-rw-r--r--src/audacious/intl/localcharset.h42
-rw-r--r--src/audacious/intl/locale.alias78
-rw-r--r--src/audacious/intl/localealias.c419
-rw-r--r--src/audacious/intl/localename.c772
-rw-r--r--src/audacious/intl/log.c104
-rw-r--r--src/audacious/intl/ngettext.c68
-rw-r--r--src/audacious/intl/os2compat.c98
-rw-r--r--src/audacious/intl/os2compat.h46
-rw-r--r--src/audacious/intl/osdep.c24
-rw-r--r--src/audacious/intl/plural-exp.c156
-rw-r--r--src/audacious/intl/plural-exp.h126
-rw-r--r--src/audacious/intl/plural.c1518
-rw-r--r--src/audacious/intl/plural.y409
-rw-r--r--src/audacious/intl/ref-add.sin31
-rw-r--r--src/audacious/intl/ref-del.sin26
-rw-r--r--src/audacious/intl/relocatable.c439
-rw-r--r--src/audacious/intl/relocatable.h67
-rw-r--r--src/audacious/intl/textdomain.c142
-rw-r--r--src/audacious/main.c676
-rw-r--r--src/audacious/main.h59
-rw-r--r--src/audacious/misc-api.h21
-rw-r--r--src/audacious/misc.h21
-rw-r--r--src/audacious/mpris-signals.c71
-rw-r--r--src/audacious/output.c551
-rw-r--r--src/audacious/output.h12
-rw-r--r--src/audacious/playback.c591
-rw-r--r--src/audacious/playback.h7
-rw-r--r--src/audacious/playlist-api.h80
-rw-r--r--src/audacious/playlist-files.c84
-rw-r--r--src/audacious/playlist-new.c729
-rw-r--r--src/audacious/playlist-utils.c82
-rw-r--r--src/audacious/playlist.h7
-rw-r--r--src/audacious/playlist_container.c83
-rw-r--r--src/audacious/playlist_container.h33
-rw-r--r--src/audacious/plugin-init.c298
-rw-r--r--src/audacious/plugin-registry.c356
-rw-r--r--src/audacious/plugin-view.c269
-rw-r--r--src/audacious/plugin.h321
-rw-r--r--src/audacious/pluginenum.c361
-rw-r--r--src/audacious/pluginenum.h42
-rw-r--r--src/audacious/plugins-api.h43
-rw-r--r--src/audacious/plugins.h34
-rw-r--r--src/audacious/preferences.h1
-rw-r--r--src/audacious/probe-buffer.c5
-rw-r--r--src/audacious/probe.c93
-rw-r--r--src/audacious/signals.c91
-rw-r--r--src/audacious/signals.h29
-rw-r--r--src/audacious/smclient.c75
-rw-r--r--src/audacious/types.h37
-rw-r--r--src/audacious/ui_preferences.c1191
-rw-r--r--src/audacious/ui_preferences.h9
-rw-r--r--src/audacious/util.c250
-rw-r--r--src/audacious/util.h7
-rw-r--r--src/audacious/vis_runner.c54
-rw-r--r--src/audacious/vis_runner.h8
-rw-r--r--src/audacious/visualization.c54
-rw-r--r--src/audacious/visualization.h9
-rw-r--r--src/audtool/Makefile10
-rw-r--r--src/audtool/main.c8
-rw-r--r--src/libaudclient/Makefile2
-rw-r--r--src/libaudcore/Makefile12
-rw-r--r--src/libaudcore/audstrings.c250
-rw-r--r--src/libaudcore/audstrings.h23
-rw-r--r--src/libaudcore/index.c41
-rw-r--r--src/libaudcore/index.h1
-rw-r--r--src/libaudcore/log.c409
-rw-r--r--src/libaudcore/log.h116
-rw-r--r--src/libaudcore/stringpool.c108
-rw-r--r--src/libaudcore/stringpool.h4
-rw-r--r--src/libaudcore/tuple.c248
-rw-r--r--src/libaudcore/tuple.h16
-rw-r--r--src/libaudcore/tuple_compiler.c4
-rw-r--r--src/libaudcore/tuple_formatter.c10
-rw-r--r--src/libaudcore/vfs.c266
-rw-r--r--src/libaudcore/vfs.h16
-rw-r--r--src/libaudcore/vfs_async.c2
-rw-r--r--src/libaudcore/vfs_buffer.c2
-rw-r--r--src/libaudcore/vfs_buffered_file.c2
-rw-r--r--src/libaudgui/Makefile7
-rw-r--r--src/libaudgui/audacious_logo.xpm454
-rw-r--r--src/libaudgui/confirm.c36
-rw-r--r--src/libaudgui/effects-menu.c21
-rw-r--r--src/libaudgui/icons-stock.c27
-rw-r--r--src/libaudgui/iface-menu.c8
-rw-r--r--src/libaudgui/infopopup.c15
-rw-r--r--src/libaudgui/infowin.c478
-rw-r--r--src/libaudgui/libaudgui-gtk.h14
-rw-r--r--src/libaudgui/libaudgui.h1
-rw-r--r--src/libaudgui/library-store.c367
-rwxr-xr-xsrc/libaudgui/list.c758
-rw-r--r--src/libaudgui/list.h61
-rw-r--r--src/libaudgui/ui_about.c160
-rw-r--r--src/libaudgui/ui_credits.c92
-rw-r--r--src/libaudgui/ui_credits.h9
-rwxr-xr-x[-rw-r--r--]src/libaudgui/ui_fileopener.c4
-rw-r--r--src/libaudgui/ui_gtk.c8
-rw-r--r--src/libaudgui/ui_jumptotrack.c21
-rw-r--r--src/libaudgui/ui_jumptotrack_cache.c9
-rw-r--r--src/libaudgui/ui_playlist_manager.c205
-rw-r--r--src/libaudgui/ui_regex.h (renamed from src/audacious/chardet.h)70
-rw-r--r--src/libaudgui/ui_urlopener.c7
-rw-r--r--src/libaudgui/util.c117
-rw-r--r--src/libaudtag/Makefile2
-rw-r--r--src/libaudtag/aac/aac.c10
-rwxr-xr-xsrc/libaudtag/ape/ape.c46
-rw-r--r--src/libaudtag/audtag.c7
-rw-r--r--src/libaudtag/audtag.h4
-rw-r--r--src/libaudtag/id3/id3-common.c12
-rw-r--r--src/libaudtag/id3/id3v1.c4
-rw-r--r--src/libaudtag/id3/id3v22.c51
-rw-r--r--src/libaudtag/id3/id3v24.c93
-rw-r--r--src/libaudtag/tag_module.c6
-rw-r--r--src/libaudtag/util.c34
-rw-r--r--src/libaudtag/util.h6
-rw-r--r--src/libaudtag/wma/guid.c32
-rw-r--r--src/libaudtag/wma/guid.h12
-rw-r--r--src/libaudtag/wma/wma.c58
-rw-r--r--src/libaudtag/wma/wma.h20
-rw-r--r--src/libaudtag/wma/wma_fmt.h12
-rw-r--r--src/libeggsmclient/eggdesktopfile.c302
-rw-r--r--src/libeggsmclient/eggdesktopfile.h51
-rw-r--r--src/libeggsmclient/eggsmclient-osx.c158
-rw-r--r--src/libeggsmclient/eggsmclient-private.h6
-rw-r--r--src/libeggsmclient/eggsmclient-win32.c154
-rw-r--r--src/libeggsmclient/eggsmclient-xsmp.c146
-rw-r--r--src/libeggsmclient/eggsmclient.c102
183 files changed, 6837 insertions, 17519 deletions
diff --git a/src/audacious/Makefile b/src/audacious/Makefile
index ccca7e5..8beefdc 100644
--- a/src/audacious/Makefile
+++ b/src/audacious/Makefile
@@ -1,8 +1,6 @@
include ../../extra.mk
-SUBDIRS = ${INTL_OBJECTIVE}
-
-PROG = audacious2${PROG_SUFFIX}
+PROG = audacious${PROG_SUFFIX}
SRCS = audconfig.c \
chardet.c \
configdb.c \
@@ -13,19 +11,23 @@ SRCS = audconfig.c \
equalizer_preset.c \
fft.c \
folder-add.c \
- general.c \
+ general.c \
interface.c \
main.c \
+ mpris-signals.c \
output.c \
playback.c \
- playlist_container.c \
+ playlist-files.c \
playlist-new.c \
playlist-utils.c \
pluginenum.c \
plugin-registry.c \
+ plugin-init.c \
+ plugin-view.c \
probe.c \
probe-buffer.c \
signals.c \
+ smclient.c \
ui_plugin_menu.c \
ui_preferences.c \
util.c \
@@ -50,6 +52,8 @@ INCLUDES = api.h \
debug.h \
drct.h \
drct-api.h \
+ glib-compat.h \
+ gtk-compat.h \
i18n.h \
interface.h \
misc.h \
@@ -63,6 +67,7 @@ INCLUDES = api.h \
types.h
DATA = images/about-logo.png \
+ images/album.png \
images/appearance.png \
images/audacious_eq.xpm \
images/audacious_player.xpm \
@@ -73,7 +78,6 @@ DATA = images/about-logo.png \
images/menu_playlist.png \
images/menu_plugin.png \
images/menu_queue_toggle.png \
- images/playback.png \
images/playlist.png \
images/plugins.png \
images/replay_gain.png
@@ -106,13 +110,13 @@ CPPFLAGS += -std=gnu99 \
${ARCH_DEFINES} \
${DBUS_CFLAGS} \
${REGEX_CFLAGS} \
+ ${PTHREAD_CFLAGS} \
${LIBMCS_CFLAGS} \
${SIMD_CFLAGS} \
-D_AUDACIOUS_CORE \
${EGGSM_CFLAGS} \
${LIBGUESS_CFLAGS} \
- -I.. -I../.. \
- -I./intl
+ -I.. -I../..
LIBS += ${LDADD} \
-lm \
@@ -128,6 +132,7 @@ LIBS += ${LDADD} \
${MOWGLI_LIBS} \
${LIBMCS_LIBS} \
${REGEX_LIBS} \
+ ${PTHREAD_LIBS} \
${LIBGUESS_LIBS}
LDFLAGS += ${PROG_IMPLIB_LDFLAGS} ${AUDLDFLAGS}
@@ -150,9 +155,6 @@ dbus-client-bindings.h: ${DBUS_BINDINGS_SOURCES}
${DBUS_BINDING_TOOL} --mode=glib-client --prefix=audacious_rc objects.xml > $@
install-extra:
- if test -h "${DESTDIR}${bindir}/audacious" ; then ${RM} "${DESTDIR}${bindir}/audacious" ; fi
- ${LN_S} audacious2 "${DESTDIR}${bindir}/audacious"
-
if test x"${PROG_IMPLIB_NEEDED}" = x"yes"; then \
for i in ${PROG}; do \
i="lib$$i.a"; \
@@ -166,8 +168,6 @@ install-extra:
fi
uninstall-extra:
- if test -h "${DESTDIR}${bindir}/audacious" ; then ${RM} "${DESTDIR}${bindir}/audacious" ; fi
-
if test x"${PROG_IMPLIB_NEEDED}" = x"yes"; then \
for i in ${PROG}; do \
i="lib$$i.a"; \
diff --git a/src/audacious/audconfig.c b/src/audacious/audconfig.c
index 15f868d..3556c37 100644
--- a/src/audacious/audconfig.c
+++ b/src/audacious/audconfig.c
@@ -26,20 +26,9 @@
#include <glib.h>
#include <libaudcore/hook.h>
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include "audconfig.h"
#include "configdb.h"
-#include "effect.h"
-#include "general.h"
-#include "output.h"
#include "playback.h"
-#include "pluginenum.h"
-#include "plugins.h"
-#include "util.h"
-#include "visualization.h"
AudConfig cfg = {
.shuffle = FALSE,
@@ -50,7 +39,11 @@ AudConfig cfg = {
.equalizer_visible = FALSE,
.player_visible = TRUE,
.show_numbers_in_pl = TRUE,
+ .leading_zero = TRUE,
.no_playlist_advance = FALSE,
+ .advance_on_delete = FALSE,
+ .clear_playlist = TRUE,
+ .open_to_temporary = FALSE,
.stopaftersong = FALSE,
.close_dialog_open = TRUE,
.equalizer_preamp = 0.0,
@@ -87,11 +80,6 @@ AudConfig cfg = {
.replay_gain_preamp = 0,
.default_gain = 0,
.sw_volume_left = 100, .sw_volume_right = 100,
- .clear_playlist = TRUE,
- .output_path = NULL,
- .output_number = -1,
- .iface_path = NULL,
- .iface_number = -1,
/* libaudgui stuff */
.no_confirm_playlist_delete = FALSE,
@@ -125,7 +113,11 @@ typedef struct aud_cfg_strent_t {
static aud_cfg_boolent aud_boolents[] = {
{"show_numbers_in_pl", &cfg.show_numbers_in_pl, TRUE},
+ {"leading_zero", & cfg.leading_zero, TRUE},
{"no_playlist_advance", &cfg.no_playlist_advance, TRUE},
+ {"advance_on_delete", & cfg.advance_on_delete, TRUE},
+ {"clear_playlist", & cfg.clear_playlist, TRUE},
+ {"open_to_temporary", & cfg.open_to_temporary, TRUE},
{"player_visible", &cfg.player_visible, TRUE},
{"shuffle", &cfg.shuffle, TRUE},
{"repeat", &cfg.repeat, TRUE},
@@ -147,7 +139,6 @@ static aud_cfg_boolent aud_boolents[] = {
{"enable_clipping_prevention", &cfg.enable_clipping_prevention, TRUE},
{"replay_gain_track", &cfg.replay_gain_track, TRUE},
{"replay_gain_album", &cfg.replay_gain_album, TRUE},
- {"clear_playlist", &cfg.clear_playlist, TRUE},
{"no_confirm_playlist_delete", &cfg.no_confirm_playlist_delete, TRUE},
{"playlist_manager_close_on_activate",
& cfg.playlist_manager_close_on_activate, TRUE},
@@ -166,8 +157,6 @@ static aud_cfg_nument aud_numents[] = {
{"output_bit_depth", &cfg.output_bit_depth, TRUE},
{"sw_volume_left", & cfg.sw_volume_left, TRUE},
{"sw_volume_right", & cfg.sw_volume_right, TRUE},
- {"output_number", & cfg.output_number, TRUE},
- {"iface_number", & cfg.iface_number, TRUE},
{"playlist_manager_x", & cfg.playlist_manager_x, TRUE},
{"playlist_manager_y", & cfg.playlist_manager_y, TRUE},
{"playlist_manager_width", & cfg.playlist_manager_width, TRUE},
@@ -186,25 +175,10 @@ static aud_cfg_strent aud_strents[] = {
{"chardet_fallback", &cfg.chardet_fallback, TRUE},
{"cover_name_include", &cfg.cover_name_include, TRUE},
{"cover_name_exclude", &cfg.cover_name_exclude, TRUE},
- {"output_path", & cfg.output_path, TRUE},
- {"iface_path", & cfg.iface_path, TRUE},
};
static gint ncfgsent = G_N_ELEMENTS(aud_strents);
-void
-aud_config_free(void)
-{
- gint i;
- for (i = 0; i < ncfgsent; ++i) {
- if ( *(aud_strents[i].se_vloc) != NULL )
- {
- g_free( *(aud_strents[i].se_vloc) );
- *(aud_strents[i].se_vloc) = NULL;
- }
- }
-}
-
void aud_config_chardet_update(void)
{
if (cfg.chardet_fallback_s != NULL)
@@ -219,7 +193,9 @@ aud_config_load(void)
mcs_handle_t *db;
gint i, length;
- db = cfg_db_open();
+ if (! (db = cfg_db_open ()))
+ return;
+
for (i = 0; i < ncfgbent; ++i) {
cfg_db_get_bool(db, NULL,
aud_boolents[i].be_vname,
@@ -276,26 +252,12 @@ aud_config_load(void)
aud_config_chardet_update();
if (!cfg.cover_name_include)
- cfg.cover_name_include = g_strdup("");
+ cfg.cover_name_include = g_strdup("album,folder");
if (!cfg.cover_name_exclude)
cfg.cover_name_exclude = g_strdup("back");
}
-static void save_output_path (void)
-{
- const gchar * path = NULL;
- gint type, number = -1;
-
- if (current_output_plugin != NULL)
- plugin_get_path (plugin_by_header (current_output_plugin), & path,
- & type, & number);
-
- g_free (cfg.output_path);
- cfg.output_path = (path != NULL) ? g_strdup (path) : NULL;
- cfg.output_number = number;
-}
-
void
aud_config_save(void)
{
@@ -311,9 +273,8 @@ aud_config_save(void)
cfg.resume_playback_on_startup_time = playback_get_playing () ?
playback_get_time () : 0;
- save_output_path ();
-
- db = cfg_db_open();
+ if (! (db = cfg_db_open ()))
+ return;
for (i = 0; i < ncfgbent; ++i)
if (aud_boolents[i].be_wrt)
diff --git a/src/audacious/audconfig.h b/src/audacious/audconfig.h
index 0995bbb..cf38773 100644
--- a/src/audacious/audconfig.h
+++ b/src/audacious/audconfig.h
@@ -38,8 +38,9 @@ struct _AudConfig {
gboolean shuffle, repeat;
gboolean equalizer_autoload, equalizer_active;
gboolean playlist_visible, equalizer_visible, player_visible;
- gboolean show_numbers_in_pl;
- gboolean no_playlist_advance;
+ gboolean show_numbers_in_pl, leading_zero;
+ gboolean no_playlist_advance, advance_on_delete, clear_playlist,
+ open_to_temporary;
gboolean stopaftersong;
gboolean close_dialog_open;
gfloat equalizer_preamp, equalizer_bands[AUD_EQUALIZER_NBANDS];
@@ -50,7 +51,6 @@ struct _AudConfig {
gint titlestring_preset;
gchar *gentitle_format;
gboolean resume_playback_on_startup;
- gint unused, unused2; /* for compatibility with v2.3 binary API */
gint resume_state;
gint resume_playback_on_startup_time;
gchar *chardet_detector;
@@ -76,11 +76,6 @@ struct _AudConfig {
gfloat replay_gain_preamp;
gfloat default_gain;
gint sw_volume_left, sw_volume_right;
- gboolean clear_playlist;
- gchar * output_path;
- gint output_number;
- gchar * iface_path;
- gint iface_number;
/* libaudgui stuff */
gboolean no_confirm_playlist_delete;
@@ -97,7 +92,6 @@ typedef struct _AudConfig AudConfig;
extern AudConfig cfg;
extern AudConfig aud_default_config;
-void aud_config_free(void);
void aud_config_load(void);
void aud_config_save(void);
diff --git a/src/audacious/chardet.c b/src/audacious/chardet.c
index 7723b32..9010db2 100644
--- a/src/audacious/chardet.c
+++ b/src/audacious/chardet.c
@@ -21,18 +21,31 @@
#include <libaudcore/audstrings.h>
#include "audconfig.h"
-#include "chardet.h"
#include "config.h"
#include "i18n.h"
-#include "main.h"
#include "debug.h"
#ifdef USE_CHARDET
# include <libguess.h>
#endif
-gchar *
-cd_str_to_utf8(const gchar * str)
+static gchar * cd_chardet_to_utf8 (const gchar * str, gssize len,
+ gsize * arg_bytes_read, gsize * arg_bytes_write, GError ** error);
+
+static gchar * str_to_utf8_fallback (const gchar * str)
+{
+ gchar * out = g_strconcat (str, _(" (invalid UTF-8)"), NULL);
+
+ for (gchar * c = out; * c; c ++)
+ {
+ if (* c & 0x80)
+ * c = '?';
+ }
+
+ return out;
+}
+
+static gchar * cd_str_to_utf8 (const gchar * str)
{
gchar *out_str;
@@ -78,9 +91,8 @@ cd_str_to_utf8(const gchar * str)
return str_to_utf8_fallback(str);
}
-gchar *
-cd_chardet_to_utf8(const gchar * str, gssize len, gsize * arg_bytes_read,
- gsize * arg_bytes_write, GError ** error)
+static gchar * cd_chardet_to_utf8 (const gchar * str, gssize len,
+ gsize * arg_bytes_read, gsize * arg_bytes_write, GError ** error)
{
if (error)
* error = NULL;
@@ -178,9 +190,7 @@ fallback:
return NULL; /* If we have no idea, return NULL. */
}
-
-void chardet_init(void)
+void chardet_init (void)
{
- str_to_utf8 = cd_str_to_utf8;
- chardet_to_utf8 = cd_chardet_to_utf8;
+ str_set_utf8_impl (cd_str_to_utf8, cd_chardet_to_utf8);
}
diff --git a/src/audacious/compatibility.h b/src/audacious/compatibility.h
deleted file mode 100644
index 6ea287c..0000000
--- a/src/audacious/compatibility.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#if ! GLIB_CHECK_VERSION (2, 14, 0)
-#define G_QUEUE_INIT {NULL, NULL, 0}
-#define g_queue_clear(q) do {g_list_free ((q)->head); (q)->head = NULL; (q)->tail = NULL; (q)->length = 0;} while (0)
-#define g_timeout_add_seconds(s, f, d) g_timeout_add (1000 * (s), (f), (d))
-#endif
-
-#ifdef GTK_CHECK_VERSION /* GTK headers included? */
-
-#if ! GTK_CHECK_VERSION (2, 10, 0)
-#define GDK_WINDOW_TYPE_HINT_TOOLTIP GDK_WINDOW_TYPE_HINT_MENU
-#endif
-
-#if ! GTK_CHECK_VERSION (2, 12, 0)
-#define gtk_widget_set_tooltip_text(...)
-#endif
-
-#if ! GTK_CHECK_VERSION (2, 14, 0)
-#define gtk_widget_get_window(w) ((w)->window)
-#endif
-
-#if ! GTK_CHECK_VERSION (2, 18, 0)
-#define gtk_widget_set_can_default(w, t) do {if (t) GTK_WIDGET_SET_FLAGS ((w), GTK_CAN_DEFAULT); else GTK_WIDGET_UNSET_FLAGS ((w), GTK_CAN_DEFAULT);} while (0)
-#define gtk_widget_set_can_focus(w, t) do {if (t) GTK_WIDGET_SET_FLAGS ((w), GTK_CAN_FOCUS); else GTK_WIDGET_UNSET_FLAGS ((w), GTK_CAN_FOCUS);} while (0)
-#endif
-
-#endif
diff --git a/src/audacious/configdb.c b/src/audacious/configdb.c
index da78137..dd9e68d 100644
--- a/src/audacious/configdb.c
+++ b/src/audacious/configdb.c
@@ -46,8 +46,16 @@ cfg_db_open()
}
if (! config_handle)
+ {
config_handle = mcs_new (RCFILE_DEFAULT_SECTION_NAME);
+ if (! config_handle)
+ {
+ fprintf (stderr, "MCS failure. Configuration will not be saved.\n");
+ return NULL;
+ }
+ }
+
config_refcount ++;
return config_handle;
}
@@ -58,7 +66,7 @@ cfg_db_open()
*/
void cfg_db_close (mcs_handle_t * handle)
{
- g_return_if_fail (handle == config_handle);
+ g_return_if_fail (handle && handle == config_handle);
g_return_if_fail (config_refcount > 0);
config_refcount --;
}
@@ -88,6 +96,8 @@ cfg_db_get_string(mcs_handle_t * db,
const gchar * key,
gchar ** value)
{
+ g_return_val_if_fail (db && db == config_handle, FALSE);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -117,6 +127,8 @@ gboolean
cfg_db_get_int(mcs_handle_t * db,
const gchar * section, const gchar * key, gint * value)
{
+ g_return_val_if_fail (db && db == config_handle, FALSE);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -138,6 +150,8 @@ cfg_db_get_bool(mcs_handle_t * db,
const gchar * key,
gboolean * value)
{
+ g_return_val_if_fail (db && db == config_handle, FALSE);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -160,6 +174,8 @@ cfg_db_get_float(mcs_handle_t * db,
const gchar * key,
gfloat * value)
{
+ g_return_val_if_fail (db && db == config_handle, FALSE);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -182,6 +198,8 @@ cfg_db_get_double(mcs_handle_t * db,
const gchar * key,
gdouble * value)
{
+ g_return_val_if_fail (db && db == config_handle, FALSE);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -203,6 +221,8 @@ cfg_db_set_string(mcs_handle_t * db,
const gchar * key,
const gchar * value)
{
+ g_return_if_fail (db && db == config_handle);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -227,6 +247,8 @@ cfg_db_set_int(mcs_handle_t * db,
const gchar * key,
gint value)
{
+ g_return_if_fail (db && db == config_handle);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -248,6 +270,8 @@ cfg_db_set_bool(mcs_handle_t * db,
const gchar * key,
gboolean value)
{
+ g_return_if_fail (db && db == config_handle);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -269,6 +293,8 @@ cfg_db_set_float(mcs_handle_t * db,
const gchar * key,
gfloat value)
{
+ g_return_if_fail (db && db == config_handle);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -290,6 +316,8 @@ cfg_db_set_double(mcs_handle_t * db,
const gchar * key,
gdouble value)
{
+ g_return_if_fail (db && db == config_handle);
+
if (!section)
section = RCFILE_DEFAULT_SECTION_NAME;
@@ -308,7 +336,7 @@ cfg_db_unset_key(mcs_handle_t * db,
const gchar * section,
const gchar * key)
{
- g_return_if_fail(db != NULL);
+ g_return_if_fail (db && db == config_handle);
g_return_if_fail(key != NULL);
if (!section)
diff --git a/src/audacious/credits.c b/src/audacious/credits.c
index 74fbe34..436c1d0 100644
--- a/src/audacious/credits.c
+++ b/src/audacious/credits.c
@@ -28,9 +28,8 @@
#include "misc.h"
static const gchar *audacious_brief =
- N_("<big><b>Audacious %s</b></big>\n"
- "An audio player for many platforms.\n"
- "Copyright (C) 2005-2011 Audacious Development Team");
+ "<big><b>Audacious %s</b></big>\n"
+ "Copyright (C) 2005-2011 Audacious Team";
static const gchar *credit_text[] = {
N_("Core developers:"),
@@ -105,6 +104,7 @@ static const gchar *credit_text[] = {
"Alex Maclean",
"Mikael Magnusson",
"Rodrigo Martins de Matos Ventura",
+ "Mihai Maruseac",
"Diego Pettenò",
"Mike Ryan",
"Michael Schwendt",
@@ -112,11 +112,13 @@ static const gchar *credit_text[] = {
"Kirill Shendrikowski",
"Kazuki Shimura",
"Valentine Sinitsyn",
+ "Will Storey",
"Johan Tavelin",
"Christoph J. Thompson",
"Bret Towe",
"Peter Wagner",
"John Wehle",
+ "Ben Wolfson",
"Tim Yamin",
"Ivan N. Zlatev",
NULL,
@@ -251,6 +253,9 @@ static const gchar *translators_text[] = {
N_("Korean:"),
"DongCheon Park",
NULL,
+ N_("Latvian:"),
+ "Einars Sprugis",
+ NULL,
N_("Lithuanian:"),
"Paul Daukas",
"Rimas Kudelis",
@@ -291,6 +296,7 @@ static const gchar *translators_text[] = {
"Jeki Sinneo Leinos",
"Francisco Javier F. Serrador",
"Gustavo D. Vranjes",
+ "Jorge Andrés",
NULL,
N_("Swedish:"),
"Martin Persenius",
diff --git a/src/audacious/dbus-service.h b/src/audacious/dbus-service.h
index 581556a..31c947d 100644
--- a/src/audacious/dbus-service.h
+++ b/src/audacious/dbus-service.h
@@ -59,6 +59,8 @@ typedef enum {
MPRIS_STATUS_STOP
} PlaybackStatus;
+extern MprisPlayer * mpris;
+
// MPRIS /
gboolean mpris_root_identity(MprisRoot *obj, gchar **identity,
GError **error);
diff --git a/src/audacious/dbus.c b/src/audacious/dbus.c
index 5e71a97..a4549d7 100644
--- a/src/audacious/dbus.c
+++ b/src/audacious/dbus.c
@@ -37,7 +37,6 @@
#include "debug.h"
#include "drct.h"
#include "equalizer.h"
-#include "main.h"
#include "playback.h"
#include "playlist.h"
#include "interface.h"
@@ -90,6 +89,8 @@ static DBusGConnection *dbus_conn = NULL;
static guint signals[LAST_SIG] = { 0 };
static guint tracklist_signals[LAST_TRACKLIST_SIG] = { 0 };
+MprisPlayer * mpris = NULL;
+
static GThread *main_thread;
static GMutex *info_mutex;
static GCond *info_cond;
@@ -772,38 +773,13 @@ gboolean mpris_player_get_caps(MprisPlayer * obj, gint * capabilities, GError **
gboolean mpris_player_volume_set(MprisPlayer * obj, gint vol, GError ** error)
{
- gint vl, vr, v;
-
- // get the current volume so we can maintain the balance
- input_get_volume(&vl, &vr);
-
- // sanity check
- vl = CLAMP(vl, 0, 100);
- vr = CLAMP(vr, 0, 100);
- v = CLAMP(vol, 0, 100);
-
- if (vl > vr)
- {
- input_set_volume(v, (gint) rint(((gdouble) vr / vl) * v));
- }
- else if (vl < vr)
- {
- input_set_volume((gint) rint(((gdouble) vl / vr) * v), v);
- }
- else
- {
- input_set_volume(v, v);
- }
+ drct_set_volume_main (vol);
return TRUE;
}
gboolean mpris_player_volume_get(MprisPlayer * obj, gint * vol, GError ** error)
{
- gint vl, vr;
- input_get_volume(&vl, &vr);
- // vl and vr may be different depending on the balance; the true volume is
- // the maximum of vl or vr.
- *vol = MAX(vl, vr);
+ drct_get_volume_main (vol);
return TRUE;
}
@@ -1095,32 +1071,19 @@ gboolean audacious_rc_seek(RemoteObject * obj, guint pos, GError * *error)
gboolean audacious_rc_volume(RemoteObject * obj, gint * vl, gint * vr, GError ** error)
{
- input_get_volume(vl, vr);
+ drct_get_volume (vl, vr);
return TRUE;
}
gboolean audacious_rc_set_volume(RemoteObject * obj, gint vl, gint vr, GError ** error)
{
- if (vl > 100)
- vl = 100;
- if (vr > 100)
- vr = 100;
- input_set_volume(vl, vr);
+ drct_set_volume (vl, vr);
return TRUE;
}
gboolean audacious_rc_balance(RemoteObject * obj, gint * balance, GError ** error)
{
- gint vl, vr;
- input_get_volume(&vl, &vr);
- if (vl < 0 || vr < 0)
- *balance = 0;
- else if (vl > vr)
- *balance = -100 + ((vr * 100) / vl);
- else if (vr > vl)
- *balance = 100 - ((vl * 100) / vr);
- else
- *balance = 0;
+ drct_get_volume_balance (balance);
return TRUE;
}
diff --git a/src/audacious/drct-api.h b/src/audacious/drct-api.h
index 41058f4..8b78301 100644
--- a/src/audacious/drct-api.h
+++ b/src/audacious/drct-api.h
@@ -1,6 +1,6 @@
/*
* drct-api.h
- * Copyright 2010 John Lindgren
+ * Copyright 2010-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -75,6 +75,7 @@ AUD_FUNC1 (void, drct_pl_open_temp, const gchar *, filename)
AUD_FUNC1 (void, drct_pl_open_temp_list, GList *, list)
AUD_FUNC1 (void, drct_pl_delete, gint, entry)
+AUD_FUNC0 (void, drct_pl_delete_selected)
AUD_FUNC0 (void, drct_pl_clear)
/* --- PLAYLIST QUEUE CONTROL --- */
@@ -86,3 +87,6 @@ AUD_FUNC1 (gint, drct_pq_get_queue_position, gint, entry)
AUD_FUNC1 (void, drct_pq_add, gint, entry)
AUD_FUNC1 (void, drct_pq_remove, gint, entry)
AUD_FUNC0 (void, drct_pq_clear)
+
+/* New in 2.5-alpha2 */
+AUD_FUNC0 (gboolean, drct_get_ready)
diff --git a/src/audacious/drct.c b/src/audacious/drct.c
index 95ba3e3..764295f 100644
--- a/src/audacious/drct.c
+++ b/src/audacious/drct.c
@@ -1,6 +1,6 @@
/*
* drct.c
- * Copyright 2009-2010 John Lindgren
+ * Copyright 2009-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -24,11 +24,10 @@
#include <libaudcore/vfs.h>
#include "audconfig.h"
-#include "compatibility.h"
#include "config.h"
#include "drct.h"
+#include "glib-compat.h"
#include "i18n.h"
-#include "main.h"
#include "playback.h"
#include "playlist.h"
@@ -36,7 +35,7 @@
void drct_quit (void)
{
- aud_quit ();
+ hook_call ("quit", NULL);
}
/* --- PLAYBACK CONTROL --- */
@@ -71,6 +70,11 @@ gboolean drct_get_playing (void)
return playback_get_playing ();
}
+gboolean drct_get_ready (void)
+{
+ return playback_get_ready ();
+}
+
gboolean drct_get_paused (void)
{
return playback_get_paused ();
@@ -105,14 +109,14 @@ void drct_seek (gint time)
void drct_get_volume (gint * left, gint * right)
{
- input_get_volume (left, right);
+ playback_get_volume (left, right);
* left = CLAMP (* left, 0, 100);
* right = CLAMP (* right, 0, 100);
}
void drct_set_volume (gint left, gint right)
{
- input_set_volume (CLAMP (left, 0, 100), CLAMP (right, 0, 100));
+ playback_set_volume (CLAMP (left, 0, 100), CLAMP (right, 0, 100));
}
void drct_get_volume_main (gint * volume)
@@ -244,8 +248,35 @@ gint drct_pl_get_time (gint pos)
return playlist_entry_get_length (playlist_get_active (), pos, FALSE);
}
-static void add_list (GList * list, gint at, gboolean play)
+static void activate_temp (void)
+{
+ gint playlists = playlist_count ();
+ const gchar * title = _("Temporary Playlist");
+
+ for (gint playlist = 0; playlist < playlists; playlist ++)
+ {
+ if (! strcmp (playlist_get_title (playlist), title))
+ {
+ playlist_set_active (playlist);
+ return;
+ }
+ }
+
+ if (! playlist_entry_count (playlist_get_active ()))
+ playlist_set_title (playlist_get_active (), title);
+ else
+ {
+ playlist_insert (playlists);
+ playlist_set_title (playlists, title);
+ playlist_set_active (playlists);
+ }
+}
+
+static void add_list (GList * list, gint at, gboolean to_temp, gboolean play)
{
+ if (to_temp)
+ activate_temp ();
+
gint playlist = playlist_get_active ();
if (play)
@@ -301,56 +332,37 @@ static void add_list (GList * list, gint at, gboolean play)
void drct_pl_add (const gchar * filename, gint at)
{
GList * list = g_list_prepend (NULL, (void *) filename);
- add_list (list, at, FALSE);
+ add_list (list, at, FALSE, FALSE);
g_list_free (list);
}
void drct_pl_add_list (GList * list, gint at)
{
- add_list (list, at, FALSE);
+ add_list (list, at, FALSE, FALSE);
}
void drct_pl_open (const gchar * filename)
{
GList * list = g_list_prepend (NULL, (void *) filename);
- add_list (list, -1, TRUE);
+ add_list (list, -1, cfg.open_to_temporary, TRUE);
g_list_free (list);
}
void drct_pl_open_list (GList * list)
{
- add_list (list, -1, TRUE);
-}
-
-static void activate_temp (void)
-{
- gint playlists = playlist_count ();
- const gchar * title = _("Temporary Playlist");
-
- for (gint playlist = 0; playlist < playlists; playlist ++)
- {
- if (! strcmp (playlist_get_title (playlist), title))
- {
- playlist_set_active (playlist);
- return;
- }
- }
-
- playlist_insert (playlists);
- playlist_set_title (playlists, title);
- playlist_set_active (playlists);
+ add_list (list, -1, cfg.open_to_temporary, TRUE);
}
void drct_pl_open_temp (const gchar * filename)
{
- activate_temp ();
- drct_pl_open (filename);
+ GList * list = g_list_prepend (NULL, (void *) filename);
+ add_list (list, -1, TRUE, TRUE);
+ g_list_free (list);
}
void drct_pl_open_temp_list (GList * list)
{
- activate_temp ();
- drct_pl_open_list (list);
+ add_list (list, -1, TRUE, TRUE);
}
void drct_pl_delete (gint entry)
@@ -358,6 +370,34 @@ void drct_pl_delete (gint entry)
playlist_entry_delete (playlist_get_active (), entry, 1);
}
+/* Advancing to the next song when the current one is deleted is tricky. First,
+ * we delete all the selected songs except the current one. We can then advance
+ * to a new song without worrying about picking one that is also selected.
+ * Finally, we can delete the former current song without stopping playback. */
+
+void drct_pl_delete_selected (void)
+{
+ gint list = playlist_get_active ();
+ gint pos = playlist_get_position (list);
+
+ if (cfg.advance_on_delete && ! cfg.no_playlist_advance
+ && playback_get_playing () && list == playlist_get_playing ()
+ && pos >= 0 && playlist_entry_get_selected (list, pos))
+ {
+ playlist_entry_set_selected (list, pos, FALSE);
+ playlist_delete_selected (list);
+ pos = playlist_get_position (list); /* it may have moved */
+
+ if (playlist_next_song (list, cfg.repeat)
+ && playlist_get_position (list) != pos)
+ playback_play (0, FALSE);
+
+ playlist_entry_delete (list, pos, 1);
+ }
+ else
+ playlist_delete_selected (list);
+}
+
void drct_pl_clear (void)
{
gint playlist = playlist_get_active ();
diff --git a/src/audacious/effect.c b/src/audacious/effect.c
index 1998e7a..f407099 100644
--- a/src/audacious/effect.c
+++ b/src/audacious/effect.c
@@ -23,7 +23,6 @@
#include "debug.h"
#include "effect.h"
-#include "output.h"
#include "playback.h"
#include "plugin.h"
#include "plugins.h"
@@ -35,7 +34,8 @@ typedef struct {
gboolean remove_flag;
} RunningEffect;
-static GList * running_effects = NULL;
+static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+static GList * running_effects = NULL; /* (RunningEffect *) */
static gint input_channels, input_rate;
typedef struct {
@@ -63,6 +63,8 @@ static gboolean effect_start_cb (PluginHandle * plugin, EffectStartState * state
void effect_start (gint * channels, gint * rate)
{
+ g_static_mutex_lock (& mutex);
+
AUDDBG ("Starting effects.\n");
g_list_foreach (running_effects, (GFunc) g_free, NULL);
g_list_free (running_effects);
@@ -75,10 +77,11 @@ void effect_start (gint * channels, gint * rate)
plugin_for_enabled (PLUGIN_TYPE_EFFECT, (PluginForEachFunc) effect_start_cb,
& state);
running_effects = g_list_reverse (running_effects);
+
+ g_static_mutex_unlock (& mutex);
}
-typedef struct
-{
+typedef struct {
gfloat * * data;
gint * samples;
} EffectProcessState;
@@ -100,36 +103,56 @@ static void effect_process_cb (RunningEffect * effect, EffectProcessState *
void effect_process (gfloat * * data, gint * samples)
{
+ g_static_mutex_lock (& mutex);
+
EffectProcessState state = {data, samples};
g_list_foreach (running_effects, (GFunc) effect_process_cb, & state);
+
+ g_static_mutex_unlock (& mutex);
}
void effect_flush (void)
{
+ g_static_mutex_lock (& mutex);
+
for (GList * node = running_effects; node != NULL; node = node->next)
((RunningEffect *) node->data)->header->flush ();
+
+ g_static_mutex_unlock (& mutex);
}
void effect_finish (gfloat * * data, gint * samples)
{
+ g_static_mutex_lock (& mutex);
+
for (GList * node = running_effects; node != NULL; node = node->next)
((RunningEffect *) node->data)->header->finish (data, samples);
+
+ g_static_mutex_unlock (& mutex);
}
gint effect_decoder_to_output_time (gint time)
{
+ g_static_mutex_lock (& mutex);
+
for (GList * node = running_effects; node != NULL; node = node->next)
time = ((RunningEffect *) node->data)->header->decoder_to_output_time
(time);
+
+ g_static_mutex_unlock (& mutex);
return time;
}
gint effect_output_to_decoder_time (gint time)
{
+ g_static_mutex_lock (& mutex);
+
for (GList * node = g_list_last (running_effects); node != NULL; node =
node->prev)
time = ((RunningEffect *) node->data)->header->output_to_decoder_time
(time);
+
+ g_static_mutex_unlock (& mutex);
return time;
}
@@ -193,26 +216,48 @@ static void effect_remove (PluginHandle * plugin)
((RunningEffect *) node->data)->remove_flag = TRUE;
}
-void effect_plugin_enable (PluginHandle * plugin, gboolean enable)
+static void effect_enable (PluginHandle * plugin, EffectPlugin * ep, gboolean
+ enable)
{
- plugin_set_enabled (plugin, enable);
+ if (ep->preserves_format)
+ {
+ g_static_mutex_lock (& mutex);
+
+ if (enable)
+ effect_insert (plugin, ep);
+ else
+ effect_remove (plugin);
+ g_static_mutex_unlock (& mutex);
+ }
+ else
+ {
+ AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
+ gint time = playback_get_time ();
+ gboolean paused = playback_get_paused ();
+ playback_stop ();
+ playback_play (time, paused);
+ }
+}
+
+gboolean effect_plugin_start (PluginHandle * plugin)
+{
if (playback_get_playing ())
{
- EffectPlugin * header = plugin_get_header (plugin);
- g_return_if_fail (header != NULL);
-
- if (header->preserves_format)
- {
- if (enable)
- effect_insert (plugin, header);
- else
- effect_remove (plugin);
- }
- else
- {
- AUDDBG ("Reset to add/remove %s.\n", plugin_get_name (plugin));
- set_current_output_plugin (current_output_plugin);
- }
+ EffectPlugin * ep = plugin_get_header (plugin);
+ g_return_val_if_fail (ep != NULL, FALSE);
+ effect_enable (plugin, ep, TRUE);
+ }
+
+ return TRUE;
+}
+
+void effect_plugin_stop (PluginHandle * plugin)
+{
+ if (playback_get_playing ())
+ {
+ EffectPlugin * ep = plugin_get_header (plugin);
+ g_return_if_fail (ep != NULL);
+ effect_enable (plugin, ep, FALSE);
}
}
diff --git a/src/audacious/effect.h b/src/audacious/effect.h
index 701c55b..14afce4 100644
--- a/src/audacious/effect.h
+++ b/src/audacious/effect.h
@@ -25,6 +25,8 @@
#include <glib.h>
+#include "types.h"
+
void effect_start (gint * channels, gint * rate);
void effect_process (gfloat * * data, gint * samples);
void effect_flush (void);
@@ -32,4 +34,7 @@ void effect_finish (gfloat * * data, gint * samples);
gint effect_decoder_to_output_time (gint time);
gint effect_output_to_decoder_time (gint time);
+gboolean effect_plugin_start (PluginHandle * plugin);
+void effect_plugin_stop (PluginHandle * plugin);
+
#endif
diff --git a/src/audacious/equalizer_preset.c b/src/audacious/equalizer_preset.c
index 52605b3..34a564b 100644
--- a/src/audacious/equalizer_preset.c
+++ b/src/audacious/equalizer_preset.c
@@ -23,7 +23,6 @@
#include "debug.h"
#include "i18n.h"
#include "interface.h"
-#include "main.h"
#include "misc.h"
static EqualizerPreset * equalizer_preset_new (const gchar * name)
@@ -43,13 +42,14 @@ equalizer_read_presets(const gchar *basename)
gint i, p = 0;
EqualizerPreset *preset;
- filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL);
+ filename = g_build_filename (get_path (AUD_PATH_USER_DIR), basename, NULL);
rcfile = g_key_file_new();
if (!g_key_file_load_from_file(rcfile, filename, G_KEY_FILE_NONE, &error))
{
g_free(filename);
- filename = g_build_filename(DATA_DIR, basename, NULL);
+ filename = g_build_filename (get_path (AUD_PATH_DATA_DIR), basename,
+ NULL);
error = NULL;
if (!g_key_file_load_from_file(rcfile, filename, G_KEY_FILE_NONE, &error))
@@ -131,8 +131,7 @@ gboolean equalizer_write_preset_file (GList * list, const gchar * basename)
}
}
-
- filename = g_build_filename(aud_paths[BMP_PATH_USER_DIR], basename, NULL);
+ filename = g_build_filename (get_path (AUD_PATH_USER_DIR), basename, NULL);
data = g_key_file_to_data(rcfile, &len, &error);
gboolean success = g_file_set_contents (filename, data, len, & error);
diff --git a/src/audacious/folder-add.c b/src/audacious/folder-add.c
index 48ce73d..4435872 100644
--- a/src/audacious/folder-add.c
+++ b/src/audacious/folder-add.c
@@ -1,6 +1,6 @@
/*
* folder-add.c
- * Copyright 2009 John Lindgren
+ * Copyright 2009-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -20,31 +20,39 @@
*/
#include <dirent.h>
-#include <glib.h>
-#include <gtk/gtk.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
+#include <gtk/gtk.h>
+
#include <libaudcore/audstrings.h>
#include "audconfig.h"
#include "config.h"
+#include "glib-compat.h"
#include "i18n.h"
#include "misc.h"
#include "playback.h"
#include "playlist.h"
-static GList * add_queue = NULL;
+typedef struct {
+ gchar * filename;
+ PluginHandle * decoder;
+} AddFile;
+
+typedef struct {
+ gint playlist_id, at;
+ GQueue folders; // (gchar *)
+ gboolean play;
+} AddGroup;
+
+static GQueue add_queue = G_QUEUE_INIT; // (AddGroup *)
static gint add_source = 0;
-static gint add_playlist, add_at;
-static gboolean add_play;
static GtkWidget * add_window = NULL, * add_progress_path, * add_progress_count;
static void show_progress (const gchar * path, gint count)
{
- gchar scratch[128];
-
if (add_window == NULL)
{
GtkWidget * vbox;
@@ -76,6 +84,8 @@ static void show_progress (const gchar * path, gint count)
}
gtk_label_set_text (GTK_LABEL(add_progress_path), path);
+
+ gchar scratch[128];
snprintf (scratch, sizeof scratch, dngettext (PACKAGE, "%d file found",
"%d files found", count), count);
gtk_label_set_text (GTK_LABEL(add_progress_count), scratch);
@@ -86,34 +96,49 @@ static void show_done (void)
gtk_widget_destroy (add_window);
}
+static gint sort_cb (const AddFile * a, const AddFile * b)
+{
+ return string_compare_encoded (a->filename, b->filename);
+}
+
static gboolean add_cb (void * unused)
{
- static GList * stack = NULL;
- static struct index * index;
- gint count;
+ static GList * stack = NULL; // (gchar *) and (DIR *) alternately
+ static GList * big_list = NULL, * little_list = NULL; // (AddFile *)
- if (stack == NULL)
+ if (! stack)
{
- stack = g_list_prepend (stack, add_queue->data);
- index = index_new ();
+ AddGroup * group = g_queue_peek_head (& add_queue);
+ g_return_val_if_fail (group, FALSE);
+ gchar * folder = g_queue_pop_head (& group->folders);
+ g_return_val_if_fail (folder, FALSE);
+ stack = g_list_prepend (NULL, folder);
}
- show_progress ((gchar *) stack->data, index_count (index));
+ show_progress (stack->data, g_list_length (big_list) + g_list_length
+ (little_list));
- for (count = 0; count < 30; count ++)
+ for (gint count = 0; count < 30; count ++)
{
struct stat info;
- struct dirent * entry;
- if (stat (stack->data, & info) == 0)
+ /* top of stack is (gchar *) */
+
+ if (! stat (stack->data, & info))
{
if (S_ISREG (info.st_mode))
{
gchar * filename = filename_to_uri (stack->data);
+ PluginHandle * decoder = (filename == NULL) ? NULL :
+ file_find_decoder (filename, TRUE);
- if (filename != NULL && file_find_decoder (filename, TRUE) !=
- NULL)
- index_append (index, filename);
+ if (decoder)
+ {
+ AddFile * file = g_slice_new (AddFile);
+ file->filename = filename;
+ file->decoder = decoder;
+ little_list = g_list_prepend (little_list, file);
+ }
else
g_free (filename);
}
@@ -121,7 +146,7 @@ static gboolean add_cb (void * unused)
{
DIR * folder = opendir (stack->data);
- if (folder != NULL)
+ if (folder)
{
stack = g_list_prepend (stack, folder);
goto READ;
@@ -133,18 +158,20 @@ static gboolean add_cb (void * unused)
stack = g_list_delete_link (stack, stack);
READ:
- if (stack == NULL)
+ if (! stack)
break;
- entry = readdir (stack->data);
+ /* top of stack is (DIR *) */
+
+ struct dirent * entry = readdir (stack->data);
- if (entry != NULL)
+ if (entry)
{
if (entry->d_name[0] == '.')
goto READ;
- stack = g_list_prepend (stack, g_strdup_printf ("%s/%s", (gchar *)
- stack->next->data, entry->d_name));
+ stack = g_list_prepend (stack, g_strdup_printf ("%s"
+ G_DIR_SEPARATOR_S "%s", (gchar *) stack->next->data, entry->d_name));
}
else
{
@@ -156,64 +183,114 @@ static gboolean add_cb (void * unused)
}
}
- if (stack == NULL)
- {
- index_sort (index, (gint (*) (const void *, const void *))
- string_compare_encoded);
+ if (stack)
+ return TRUE; /* not done yet */
- count = playlist_count ();
+ AddGroup * group = g_queue_peek_head (& add_queue);
+ g_return_val_if_fail (group, FALSE);
- if (add_playlist > count - 1)
- add_playlist = count - 1;
+ little_list = g_list_sort (little_list, (GCompareFunc) sort_cb);
+ big_list = g_list_concat (big_list, little_list);
+ little_list = NULL;
- count = playlist_entry_count (add_playlist);
+ if (! g_queue_is_empty (& group->folders))
+ return TRUE; /* not done yet */
- if (add_at < 0 || add_at > count)
- add_at = count;
+ gint playlist = playlist_by_unique_id (group->playlist_id);
- playlist_entry_insert_batch (add_playlist, add_at, index, NULL);
-
- if (add_play && playlist_entry_count (add_playlist) > count)
+ if (playlist < 0) /* ouch! playlist deleted */
+ {
+ for (GList * node = big_list; node; node = node->next)
{
- playlist_set_playing (add_playlist);
- if (! cfg.shuffle)
- playlist_set_position (add_playlist, add_at);
- playback_play (0, FALSE);
- add_play = FALSE;
+ AddFile * file = node->data;
+ g_free (file->filename);
+ g_slice_free (AddFile, file);
}
- add_at += playlist_entry_count (add_playlist) - count;
+ g_list_free (big_list);
+ big_list = NULL;
+ goto ADDED;
+ }
- add_queue = g_list_delete_link (add_queue, add_queue);
+ struct index * filenames = index_new ();
+ struct index * decoders = index_new ();
- if (add_queue == NULL)
- {
- show_done ();
- add_source = 0;
- return FALSE;
- }
+ for (GList * node = big_list; node; node = node->next)
+ {
+ AddFile * file = node->data;
+ index_append (filenames, file->filename);
+ index_append (decoders, file->decoder);
+ g_slice_free (AddFile, file);
}
- return TRUE;
+ g_list_free (big_list);
+ big_list = NULL;
+
+ gint count = playlist_entry_count (playlist);
+ if (group->at < 0 || group->at > count)
+ group->at = count;
+
+ playlist_entry_insert_batch_with_decoders (playlist, group->at,
+ filenames, decoders, NULL);
+
+ if (group->play && playlist_entry_count (playlist) > count)
+ {
+ playlist_set_playing (playlist);
+ if (! cfg.shuffle)
+ playlist_set_position (playlist, group->at);
+ playback_play (0, FALSE);
+ }
+
+ADDED:
+ g_slice_free (AddGroup, group);
+ g_queue_pop_head (& add_queue);
+
+ if (! g_queue_is_empty (& add_queue))
+ return TRUE; /* not done yet */
+
+ show_done ();
+ add_source = 0;
+ return FALSE;
}
void playlist_insert_folder (gint playlist, gint at, const gchar * folder,
gboolean play)
{
- gchar * unix_name = uri_to_filename (folder);
-
- add_playlist = playlist;
- add_at = at;
- add_play |= play;
+ gint playlist_id = playlist_get_unique_id (playlist);
+ g_return_if_fail (playlist_id >= 0);
- if (unix_name == NULL)
- return;
+ gchar * unix_name = uri_to_filename (folder);
+ g_return_if_fail (unix_name);
if (unix_name[strlen (unix_name) - 1] == '/')
unix_name[strlen (unix_name) - 1] = 0;
- add_queue = g_list_append (add_queue, unix_name);
+ AddGroup * group = NULL;
+
+ for (GList * node = g_queue_peek_head_link (& add_queue); node; node =
+ node->next)
+ {
+ AddGroup * test = node->data;
+ if (test->playlist_id == playlist_id && test->at == at)
+ {
+ group = test;
+ break;
+ }
+ }
+
+ if (! group)
+ {
+ group = g_slice_new (AddGroup);
+ group->playlist_id = playlist_id;
+ group->at = at;
+ g_queue_init (& group->folders);
+ group->play = FALSE;
+ g_queue_push_tail (& add_queue, group);
+ }
+
+ g_queue_push_tail (& group->folders, unix_name);
+ group->play |= play;
- if (add_source == 0)
+ if (! add_source)
add_source = g_idle_add (add_cb, NULL);
}
diff --git a/src/audacious/general.c b/src/audacious/general.c
index 1c1e05c..7c8e60a 100644
--- a/src/audacious/general.c
+++ b/src/audacious/general.c
@@ -1,6 +1,6 @@
/*
* general.c
- * Copyright 2010 John Lindgren
+ * Copyright 2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -19,45 +19,78 @@
* using our public API to be a derived work.
*/
-#include <glib.h>
+#include <gtk/gtk.h>
#include "debug.h"
#include "general.h"
+#include "interface.h"
#include "plugin.h"
#include "plugins.h"
+#include "ui_preferences.h"
+typedef struct {
+ PluginHandle * plugin;
+ GeneralPlugin * gp;
+ GtkWidget * widget;
+} LoadedGeneral;
+
+static gint running = FALSE;
static GList * loaded_general_plugins = NULL;
+static gint general_find_cb (LoadedGeneral * general, PluginHandle * plugin)
+{
+ return (general->plugin == plugin) ? 0 : -1;
+}
+
static void general_load (PluginHandle * plugin)
{
- GList * node = g_list_find (loaded_general_plugins, plugin);
+ GList * node = g_list_find_custom (loaded_general_plugins, plugin,
+ (GCompareFunc) general_find_cb);
if (node != NULL)
return;
AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
- GeneralPlugin * header = plugin_get_header (plugin);
- g_return_if_fail (header != NULL);
-
- if (header->init != NULL)
- header->init ();
-
- loaded_general_plugins = g_list_prepend (loaded_general_plugins, plugin);
+ GeneralPlugin * gp = plugin_get_header (plugin);
+ g_return_if_fail (gp != NULL);
+
+ LoadedGeneral * general = g_slice_new (LoadedGeneral);
+ general->plugin = plugin;
+ general->gp = gp;
+ general->widget = NULL;
+
+ if (gp->get_widget != NULL)
+ general->widget = gp->get_widget ();
+
+ if (general->widget != NULL)
+ {
+ AUDDBG ("Adding %s to interface.\n", plugin_get_name (plugin));
+ g_signal_connect (general->widget, "destroy", (GCallback)
+ gtk_widget_destroyed, & general->widget);
+ interface_add_plugin_widget (plugin, general->widget);
+ }
+
+ loaded_general_plugins = g_list_prepend (loaded_general_plugins, general);
}
static void general_unload (PluginHandle * plugin)
{
- GList * node = g_list_find (loaded_general_plugins, plugin);
+ GList * node = g_list_find_custom (loaded_general_plugins, plugin,
+ (GCompareFunc) general_find_cb);
if (node == NULL)
return;
AUDDBG ("Unloading %s.\n", plugin_get_name (plugin));
- GeneralPlugin * header = plugin_get_header (plugin);
- g_return_if_fail (header != NULL);
-
+ LoadedGeneral * general = node->data;
loaded_general_plugins = g_list_delete_link (loaded_general_plugins, node);
- if (header->cleanup != NULL)
- header->cleanup ();
+ if (general->widget != NULL)
+ {
+ AUDDBG ("Removing %s from interface.\n", plugin_get_name (plugin));
+ interface_remove_plugin_widget (plugin, general->widget);
+ g_return_if_fail (general->widget == NULL); /* not destroyed? */
+ }
+
+ g_slice_free (LoadedGeneral, general);
}
static gboolean general_init_cb (PluginHandle * plugin)
@@ -68,21 +101,64 @@ static gboolean general_init_cb (PluginHandle * plugin)
void general_init (void)
{
+ g_return_if_fail (! running);
+ running = TRUE;
+
plugin_for_enabled (PLUGIN_TYPE_GENERAL, (PluginForEachFunc)
general_init_cb, NULL);
}
+static void general_cleanup_cb (LoadedGeneral * general)
+{
+ general_unload (general->plugin);
+}
+
void general_cleanup (void)
{
- g_list_foreach (loaded_general_plugins, (GFunc) general_unload, NULL);
+ g_return_if_fail (running);
+ running = FALSE;
+
+ g_list_foreach (loaded_general_plugins, (GFunc) general_cleanup_cb, NULL);
}
-void general_plugin_enable (PluginHandle * plugin, gboolean enable)
+gboolean general_plugin_start (PluginHandle * plugin)
{
- plugin_set_enabled (plugin, enable);
+ GeneralPlugin * gp = plugin_get_header (plugin);
+ g_return_val_if_fail (gp != NULL, FALSE);
+
+ if (gp->init != NULL && ! gp->init ())
+ return FALSE;
- if (enable)
+ if (running)
general_load (plugin);
- else
+
+ return TRUE;
+}
+
+void general_plugin_stop (PluginHandle * plugin)
+{
+ GeneralPlugin * gp = plugin_get_header (plugin);
+ g_return_if_fail (gp != NULL);
+
+ if (running)
general_unload (plugin);
+
+ if (gp->settings != NULL)
+ plugin_preferences_cleanup (gp->settings);
+ if (gp->cleanup != NULL)
+ gp->cleanup ();
+}
+
+PluginHandle * general_plugin_by_widget (/* GtkWidget * */ void * widget)
+{
+ g_return_val_if_fail (widget, NULL);
+
+ for (GList * node = loaded_general_plugins; node; node = node->next)
+ {
+ LoadedGeneral * general = node->data;
+ if (general->widget == widget)
+ return general->plugin;
+ }
+
+ return NULL;
}
diff --git a/src/audacious/general.h b/src/audacious/general.h
index cf29eb7..b96dbff 100644
--- a/src/audacious/general.h
+++ b/src/audacious/general.h
@@ -1,6 +1,6 @@
/*
* general.h
- * Copyright 2010 John Lindgren
+ * Copyright 2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -22,7 +22,16 @@
#ifndef AUDACIOUS_GENERAL_H
#define AUDACIOUS_GENERAL_H
+#include <glib.h>
+
+#include "plugins.h"
+
void general_init (void);
void general_cleanup (void);
+gboolean general_plugin_start (PluginHandle * plugin);
+void general_plugin_stop (PluginHandle * plugin);
+
+PluginHandle * general_plugin_by_widget (/* GtkWidget * */ void * widget);
+
#endif
diff --git a/src/audacious/glib-compat.h b/src/audacious/glib-compat.h
new file mode 100755
index 0000000..be639d9
--- /dev/null
+++ b/src/audacious/glib-compat.h
@@ -0,0 +1,26 @@
+/* Compatibility macros to make supporting multiple GLib versions easier.
+ * Public domain. */
+
+#ifndef AUD_GLIB_COMPAT_H
+#define AUD_GLIB_COMPAT_H
+
+#if ! GLIB_CHECK_VERSION (2, 14, 0)
+
+static inline void g_queue_init (GQueue * q)
+{
+ q->head = q->tail = NULL;
+ q->length = 0;
+}
+
+static inline void g_queue_clear (GQueue * q)
+{
+ g_list_free (q->head);
+ q->head = q->tail = NULL;
+ q->length = 0;
+}
+
+#define G_QUEUE_INIT {NULL, NULL, 0}
+#define g_timeout_add_seconds(s, f, d) g_timeout_add (1000 * (s), (f), (d))
+#endif
+
+#endif /* AUD_GLIB_COMPAT_H */
diff --git a/src/audacious/gtk-compat.h b/src/audacious/gtk-compat.h
new file mode 100644
index 0000000..91d8d20
--- /dev/null
+++ b/src/audacious/gtk-compat.h
@@ -0,0 +1,89 @@
+/* Compatibility macros to make supporting multiple GTK versions easier.
+ * Public domain. */
+
+#ifndef AUD_GTK_COMPAT_H
+#define AUD_GTK_COMPAT_H
+
+#include <string.h>
+
+#if defined GDK_KEY_Tab && ! defined GDK_Tab
+#include <gdk/gdkkeysyms-compat.h>
+#endif
+
+#if ! GTK_CHECK_VERSION (2, 10, 0)
+#define GDK_WINDOW_TYPE_HINT_TOOLTIP GDK_WINDOW_TYPE_HINT_MENU
+#define gtk_label_set_line_wrap_mode(...)
+#endif
+
+#if ! GTK_CHECK_VERSION (2, 12, 0)
+
+static inline void gtk_tree_view_convert_widget_to_bin_window_coords
+ (GtkTreeView * tree, gint wx, gint wy, gint * bx, gint * by)
+{
+ gint bx0, by0;
+ gdk_window_get_position (gtk_tree_view_get_bin_window (tree), & bx0, & by0);
+ * bx = wx - bx0;
+ * by = wy - by0;
+}
+
+#define gtk_widget_set_tooltip_text(...)
+#endif
+
+#if ! GTK_CHECK_VERSION (2, 14, 0)
+#define gtk_adjustment_get_page_size(a) ((a)->page_size)
+#define gtk_adjustment_get_upper(a) ((a)->upper)
+#define gtk_dialog_get_action_area(d) ((d)->action_area)
+#define gtk_dialog_get_content_area(d) ((d)->vbox)
+#define gtk_selection_data_get_data(s) ((s)->data)
+#define gtk_selection_data_get_length(s) ((s)->length)
+#define gtk_widget_get_window(w) ((w)->window)
+#endif
+
+#if ! GTK_CHECK_VERSION (2, 18, 0)
+
+static inline void gtk_widget_set_can_default (GtkWidget * w, gboolean b)
+{
+ if (b)
+ GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
+ else
+ GTK_WIDGET_UNSET_FLAGS (w, GTK_CAN_DEFAULT);
+}
+
+static inline void gtk_widget_set_can_focus (GtkWidget * w, gboolean b)
+{
+ if (b)
+ GTK_WIDGET_SET_FLAGS (w, GTK_CAN_FOCUS);
+ else
+ GTK_WIDGET_UNSET_FLAGS (w, GTK_CAN_FOCUS);
+}
+
+#define gtk_widget_get_allocation(w, a) memcpy ((a), & (w)->allocation, sizeof (GtkAllocation))
+#define gtk_widget_get_sensitive GTK_WIDGET_SENSITIVE
+#define gtk_widget_get_visible GTK_WIDGET_VISIBLE
+#define gtk_widget_is_toplevel GTK_WIDGET_TOPLEVEL
+#endif
+
+#if ! GTK_CHECK_VERSION (2, 20, 0)
+#define gtk_widget_is_drawable GTK_WIDGET_DRAWABLE
+#endif
+
+#if ! GTK_CHECK_VERSION (3, 0, 0)
+
+static inline void gdk_window_get_geometry_compat (GdkWindow * win, gint * x,
+ gint * y, gint * w, gint * h)
+{
+ gdk_window_get_geometry (win, x, y, w, h, NULL);
+}
+
+#define GtkComboBoxText GtkComboBox
+#define gdk_window_get_geometry gdk_window_get_geometry_compat
+#define gtk_combo_box_text_new gtk_combo_box_new_text
+#define gtk_combo_box_text_new_with_entry gtk_combo_box_entry_new_text
+#define gtk_combo_box_text_append_text gtk_combo_box_append_text
+#endif
+
+#if GTK_CHECK_VERSION (3, 0, 0)
+#define gtk_range_set_update_policy(...)
+#endif
+
+#endif /* AUD_GTK_COMPAT_H */
diff --git a/src/audacious/images/about-logo.png b/src/audacious/images/about-logo.png
index f3dc1f1..32fb69f 100644
--- a/src/audacious/images/about-logo.png
+++ b/src/audacious/images/about-logo.png
Binary files differ
diff --git a/src/audacious/images/album.png b/src/audacious/images/album.png
new file mode 100644
index 0000000..decbcdb
--- /dev/null
+++ b/src/audacious/images/album.png
Binary files differ
diff --git a/src/audacious/images/appearance.png b/src/audacious/images/appearance.png
index baf5f8a..b06f9b6 100644
--- a/src/audacious/images/appearance.png
+++ b/src/audacious/images/appearance.png
Binary files differ
diff --git a/src/audacious/images/audio.png b/src/audacious/images/audio.png
index 8d3ecb5..4cbf294 100644
--- a/src/audacious/images/audio.png
+++ b/src/audacious/images/audio.png
Binary files differ
diff --git a/src/audacious/images/connectivity.png b/src/audacious/images/connectivity.png
index 23dfd56..d6be3b8 100644
--- a/src/audacious/images/connectivity.png
+++ b/src/audacious/images/connectivity.png
Binary files differ
diff --git a/src/audacious/images/menu_playlist.png b/src/audacious/images/menu_playlist.png
index fd877cb..a96f899 100644
--- a/src/audacious/images/menu_playlist.png
+++ b/src/audacious/images/menu_playlist.png
Binary files differ
diff --git a/src/audacious/images/menu_plugin.png b/src/audacious/images/menu_plugin.png
index 0d49f9d..507ff2a 100644
--- a/src/audacious/images/menu_plugin.png
+++ b/src/audacious/images/menu_plugin.png
Binary files differ
diff --git a/src/audacious/images/menu_queue_toggle.png b/src/audacious/images/menu_queue_toggle.png
index 2ecbd15..d2cfa4e 100644
--- a/src/audacious/images/menu_queue_toggle.png
+++ b/src/audacious/images/menu_queue_toggle.png
Binary files differ
diff --git a/src/audacious/images/play.png b/src/audacious/images/play.png
deleted file mode 100644
index 7fc2172..0000000
--- a/src/audacious/images/play.png
+++ /dev/null
Binary files differ
diff --git a/src/audacious/images/playback.png b/src/audacious/images/playback.png
deleted file mode 100644
index bcc2ecc..0000000
--- a/src/audacious/images/playback.png
+++ /dev/null
Binary files differ
diff --git a/src/audacious/images/playlist.png b/src/audacious/images/playlist.png
index 00c51ba..787a1e0 100644
--- a/src/audacious/images/playlist.png
+++ b/src/audacious/images/playlist.png
Binary files differ
diff --git a/src/audacious/images/plugins.png b/src/audacious/images/plugins.png
index f8b8180..47d3e42 100644
--- a/src/audacious/images/plugins.png
+++ b/src/audacious/images/plugins.png
Binary files differ
diff --git a/src/audacious/images/replay_gain.png b/src/audacious/images/replay_gain.png
index 75ab421..4fce8c3 100644
--- a/src/audacious/images/replay_gain.png
+++ b/src/audacious/images/replay_gain.png
Binary files differ
diff --git a/src/audacious/interface.c b/src/audacious/interface.c
index 65aca42..e43a33b 100644
--- a/src/audacious/interface.c
+++ b/src/audacious/interface.c
@@ -2,6 +2,7 @@
* Audacious2
* Copyright (c) 2008 William Pitcock <nenolod@dereferenced.org>
* Copyright (c) 2008-2009 Tomasz Moń <desowin@gmail.com>
+ * Copyright (c) 2010 John Lindgren <john.lindgren@tds.net>
*
* 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
@@ -27,14 +28,17 @@
#include "audconfig.h"
#include "config.h"
#include "debug.h"
+#include "general.h"
#include "i18n.h"
#include "interface.h"
+#include "misc.h"
#include "plugins.h"
#include "ui_preferences.h"
+#include "visualization.h"
-static Interface *current_interface = NULL;
+static Iface *current_interface = NULL;
-static InterfaceOps interface_ops = {
+static IfaceOps interface_ops = {
.create_prefs_window = create_prefs_window,
.show_prefs_window = show_prefs_window,
.hide_prefs_window = hide_prefs_window,
@@ -42,48 +46,11 @@ static InterfaceOps interface_ops = {
.prefswin_page_new = prefswin_page_new,
};
-static InterfaceCbs interface_cbs = { NULL };
-
-static gboolean interface_search_cb (PluginHandle * plugin, PluginHandle * *
- pluginp)
-{
- * pluginp = plugin;
- return FALSE;
-}
-
-PluginHandle * interface_get_default (void)
-{
- PluginHandle * plugin = NULL;
-
- if (cfg.iface_path == NULL || (plugin = plugin_by_path (cfg.iface_path,
- PLUGIN_TYPE_IFACE, cfg.iface_number)) == NULL || ! plugin_get_enabled
- (plugin))
- {
- AUDDBG ("Searching for an interface.\n");
- plugin_for_enabled (PLUGIN_TYPE_IFACE, (PluginForEachFunc)
- interface_search_cb, & plugin);
- if (plugin == NULL)
- return NULL;
-
- interface_set_default (plugin);
- }
-
- return plugin;
-}
-
-void interface_set_default (PluginHandle * plugin)
-{
- const gchar * path;
- gint type;
-
- g_free (cfg.iface_path);
- plugin_get_path (plugin, & path, & type, & cfg.iface_number);
- cfg.iface_path = g_strdup (path);
-}
+static IfaceCbs interface_cbs = { NULL };
gboolean interface_load (PluginHandle * plugin)
{
- Interface * i = plugin_get_header (plugin);
+ Iface * i = (Iface *) plugin_get_header (plugin);
g_return_val_if_fail (i != NULL, FALSE);
current_interface = i;
@@ -189,7 +156,7 @@ interface_show_about_window(gboolean show)
static gboolean delete_cb (GtkWidget * window, GdkEvent * event, PluginHandle *
plugin)
{
- vis_plugin_enable (plugin, FALSE);
+ plugin_enable (plugin, FALSE);
return TRUE;
}
@@ -216,6 +183,24 @@ void interface_remove_plugin_widget (PluginHandle * plugin, GtkWidget * widget)
}
void
+interface_install_toolbar(void *widget)
+{
+ if (interface_cbs.install_toolbar != NULL)
+ interface_cbs.install_toolbar(widget);
+ else
+ AUDDBG ("Interface didn't register install_toolbar function.\n");
+}
+
+void
+interface_uninstall_toolbar(void *widget)
+{
+ if (interface_cbs.uninstall_toolbar != NULL)
+ interface_cbs.uninstall_toolbar(widget);
+ else
+ AUDDBG ("Interface didn't register uninstall_toolbar function.\n");
+}
+
+void
interface_toggle_shuffle(void)
{
if (interface_cbs.toggle_shuffle != NULL)
@@ -244,7 +229,7 @@ typedef enum {
HOOK_ABOUTWIN_SHOW,
HOOK_TOGGLE_SHUFFLE,
HOOK_TOGGLE_REPEAT,
-} InterfaceHookID;
+} IfaceHookID;
void
interface_hook_handler(gpointer hook_data, gpointer user_data)
@@ -287,10 +272,10 @@ interface_hook_handler(gpointer hook_data, gpointer user_data)
typedef struct {
const gchar *name;
- InterfaceHookID id;
-} InterfaceHooks;
+ IfaceHookID id;
+} IfaceHooks;
-static InterfaceHooks hooks[] = {
+static IfaceHooks hooks[] = {
{"prefswin show", HOOK_PREFSWIN_SHOW},
{"filebrowser show", HOOK_FILEBROWSER_SHOW},
{"filebrowser hide", HOOK_FILEBROWSER_HIDE},
@@ -314,3 +299,57 @@ register_interface_hooks(void)
}
+static gboolean probe_cb (PluginHandle * p, PluginHandle * * pp)
+{
+ * pp = p;
+ return FALSE;
+}
+
+PluginHandle * iface_plugin_probe (void)
+{
+ PluginHandle * p = NULL;
+ plugin_for_each (PLUGIN_TYPE_IFACE, (PluginForEachFunc) probe_cb, & p);
+ return p;
+}
+
+static PluginHandle * current_plugin = NULL;
+
+PluginHandle * iface_plugin_get_current (void)
+{
+ return current_plugin;
+}
+
+gboolean iface_plugin_set_current (PluginHandle * plugin)
+{
+ if (current_plugin != NULL)
+ {
+ AUDDBG ("Unloading plugin widgets.\n");
+ general_cleanup ();
+
+ AUDDBG ("Unloading visualizers.\n");
+ vis_cleanup ();
+
+ AUDDBG ("Unloading %s.\n", plugin_get_name (current_plugin));
+ interface_unload ();
+
+ current_plugin = NULL;
+ }
+
+ if (plugin != NULL)
+ {
+ AUDDBG ("Loading %s.\n", plugin_get_name (plugin));
+
+ if (! interface_load (plugin))
+ return FALSE;
+
+ current_plugin = plugin;
+
+ AUDDBG ("Loading visualizers.\n");
+ vis_init ();
+
+ AUDDBG ("Loading plugin widgets.\n");
+ general_init ();
+ }
+
+ return TRUE;
+}
diff --git a/src/audacious/interface.h b/src/audacious/interface.h
index e03df24..4ce4c5b 100644
--- a/src/audacious/interface.h
+++ b/src/audacious/interface.h
@@ -42,7 +42,7 @@ typedef struct {
const gchar * imgurl); */
gint (* prefswin_page_new) (void * container, const gchar * name,
const gchar * imgurl);
-} InterfaceOps;
+} IfaceOps;
typedef struct {
void (*show_prefs_window)(gboolean show);
@@ -60,15 +60,18 @@ typedef struct {
void * (* run_gtk_plugin) (void * parent, const gchar * name);
/* GtkWidget * (* stop_gtk_plugin) (GtkWidget * parent); */
void * (* stop_gtk_plugin) (void * parent);
-} InterfaceCbs;
-struct _Interface {
+ void (*install_toolbar)(void * button);
+ void (*uninstall_toolbar)(void * button);
+} IfaceCbs;
+
+struct _Iface {
gchar *id; /* simple ID like 'skinned' */
gchar *desc; /* description like 'Skinned Interface' */
- gboolean (*init)(InterfaceCbs *cbs); /* init UI */
+ gboolean (*init)(IfaceCbs *cbs); /* init UI */
gboolean (*fini)(void); /* shutdown UI */
- InterfaceOps *ops;
+ IfaceOps *ops;
};
#ifdef _AUDACIOUS_CORE
@@ -76,8 +79,6 @@ struct _Interface {
#include <gtk/gtk.h>
#include <audacious/plugins.h>
-PluginHandle * interface_get_default (void);
-void interface_set_default (PluginHandle * plugin);
gboolean interface_load (PluginHandle * plugin);
void interface_unload (void);
@@ -97,5 +98,9 @@ void interface_toggle_repeat(void);
void register_interface_hooks(void);
+PluginHandle * iface_plugin_probe (void);
+PluginHandle * iface_plugin_get_current (void);
+gboolean iface_plugin_set_current (PluginHandle * plugin);
+
#endif
#endif
diff --git a/src/audacious/intl/ChangeLog b/src/audacious/intl/ChangeLog
deleted file mode 100644
index eed2d21..0000000
--- a/src/audacious/intl/ChangeLog
+++ /dev/null
@@ -1,4 +0,0 @@
-2003-05-22 GNU <bug-gnu-gettext@gnu.org>
-
- * Version 0.12.1 released.
-
diff --git a/src/audacious/intl/Makefile b/src/audacious/intl/Makefile
deleted file mode 100644
index 44217e1..0000000
--- a/src/audacious/intl/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-STATIC_LIB_NOINST = libintl.a
-SRCS = bindtextdom.c \
- dcgettext.c \
- dgettext.c \
- gettext.c \
- finddomain.c \
- loadmsgcat.c \
- localealias.c \
- textdomain.c \
- l10nflist.c \
- explodename.c \
- dcigettext.c \
- dcngettext.c \
- dngettext.c \
- ngettext.c \
- plural.c \
- plural-exp.c \
- localcharset.c \
- relocatable.c \
- localename.c \
- log.c \
- osdep.c \
- os2compat.c \
- intl-compat.c
-
-include ../../../buildsys.mk
-include ../../../extra.mk
-
-localedir = ${datadir)}locale
-gettextsrcdir = ${datadir}/gettext/intl
-aliaspath = ${localedir}
-
-DEFS += -DLOCALEDIR=\"${localedir}\" -DLOCALE_ALIAS_PATH=\"${aliaspath}\" \
- -DLIBDIR=\"${libdir}\" -DIN_LIBINTL \
- -DENABLE_RELOCATABLE=1 -DIN_LIBRARY -DINSTALLDIR=\"${libdir}\" -DINSTALLPREFIX=\"${libdir}\" -DNO_XMALLOC \
- -Dset_relocation_prefix=libintl_set_relocation_prefix \
- -Drelocate=libintl_relocate \
- -DDEPENDS_ON_LIBICONV=1
-
-CPPFLAGS += -I../../.. -I../.. -I. ${DEFS}
diff --git a/src/audacious/intl/VERSION b/src/audacious/intl/VERSION
deleted file mode 100644
index 1303183..0000000
--- a/src/audacious/intl/VERSION
+++ /dev/null
@@ -1 +0,0 @@
-GNU gettext library from gettext-0.12.1
diff --git a/src/audacious/intl/bindtextdom.c b/src/audacious/intl/bindtextdom.c
deleted file mode 100644
index ff0ec62..0000000
--- a/src/audacious/intl/bindtextdom.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/* Implementation of the bindtextdomain(3) function
- Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-#include "gettextP.h"
-
-#ifdef _LIBC
-/* We have to handle multi-threaded applications. */
-# include <bits/libc-lock.h>
-#else
-/* Provide dummy implementation if this is outside glibc. */
-# define __libc_rwlock_define(CLASS, NAME)
-# define __libc_rwlock_wrlock(NAME)
-# define __libc_rwlock_unlock(NAME)
-#endif
-
-/* The internal variables in the standalone libintl.a must have different
- names than the internal variables in GNU libc, otherwise programs
- using libintl.a cannot be linked statically. */
-#if !defined _LIBC
-# define _nl_default_dirname libintl_nl_default_dirname
-# define _nl_domain_bindings libintl_nl_domain_bindings
-#endif
-
-/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
-#ifndef offsetof
-# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Contains the default location of the message catalogs. */
-extern const char _nl_default_dirname[];
-#ifdef _LIBC
-extern const char _nl_default_dirname_internal[] attribute_hidden;
-#else
-# define INTUSE(name) name
-#endif
-
-/* List with bindings of specific domains. */
-extern struct binding *_nl_domain_bindings;
-
-/* Lock variable to protect the global data in the gettext implementation. */
-__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
-
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define BINDTEXTDOMAIN __bindtextdomain
-# define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
-# ifndef strdup
-# define strdup(str) __strdup (str)
-# endif
-#else
-# define BINDTEXTDOMAIN libintl_bindtextdomain
-# define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
-#endif
-
-/* Prototypes for local functions. */
-static void set_binding_values PARAMS ((const char *domainname,
- const char **dirnamep,
- const char **codesetp));
-
-/* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
- to be used for the DOMAINNAME message catalog.
- If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
- modified, only the current value is returned.
- If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
- modified nor returned. */
-static void
-set_binding_values (domainname, dirnamep, codesetp)
- const char *domainname;
- const char **dirnamep;
- const char **codesetp;
-{
- struct binding *binding;
- int modified;
-
- /* Some sanity checks. */
- if (domainname == NULL || domainname[0] == '\0')
- {
- if (dirnamep)
- *dirnamep = NULL;
- if (codesetp)
- *codesetp = NULL;
- return;
- }
-
- __libc_rwlock_wrlock (_nl_state_lock);
-
- modified = 0;
-
- for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
- {
- int compare = strcmp (domainname, binding->domainname);
- if (compare == 0)
- /* We found it! */
- break;
- if (compare < 0)
- {
- /* It is not in the list. */
- binding = NULL;
- break;
- }
- }
-
- if (binding != NULL)
- {
- if (dirnamep)
- {
- const char *dirname = *dirnamep;
-
- if (dirname == NULL)
- /* The current binding has be to returned. */
- *dirnamep = binding->dirname;
- else
- {
- /* The domain is already bound. If the new value and the old
- one are equal we simply do nothing. Otherwise replace the
- old binding. */
- char *result = binding->dirname;
- if (strcmp (dirname, result) != 0)
- {
- if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
- result = (char *) INTUSE(_nl_default_dirname);
- else
- {
-#if defined _LIBC || defined HAVE_STRDUP
- result = strdup (dirname);
-#else
- size_t len = strlen (dirname) + 1;
- result = (char *) malloc (len);
- if (__builtin_expect (result != NULL, 1))
- memcpy (result, dirname, len);
-#endif
- }
-
- if (__builtin_expect (result != NULL, 1))
- {
- if (binding->dirname != INTUSE(_nl_default_dirname))
- free (binding->dirname);
-
- binding->dirname = result;
- modified = 1;
- }
- }
- *dirnamep = result;
- }
- }
-
- if (codesetp)
- {
- const char *codeset = *codesetp;
-
- if (codeset == NULL)
- /* The current binding has be to returned. */
- *codesetp = binding->codeset;
- else
- {
- /* The domain is already bound. If the new value and the old
- one are equal we simply do nothing. Otherwise replace the
- old binding. */
- char *result = binding->codeset;
- if (result == NULL || strcmp (codeset, result) != 0)
- {
-#if defined _LIBC || defined HAVE_STRDUP
- result = strdup (codeset);
-#else
- size_t len = strlen (codeset) + 1;
- result = (char *) malloc (len);
- if (__builtin_expect (result != NULL, 1))
- memcpy (result, codeset, len);
-#endif
-
- if (__builtin_expect (result != NULL, 1))
- {
- if (binding->codeset != NULL)
- free (binding->codeset);
-
- binding->codeset = result;
- binding->codeset_cntr++;
- modified = 1;
- }
- }
- *codesetp = result;
- }
- }
- }
- else if ((dirnamep == NULL || *dirnamep == NULL)
- && (codesetp == NULL || *codesetp == NULL))
- {
- /* Simply return the default values. */
- if (dirnamep)
- *dirnamep = INTUSE(_nl_default_dirname);
- if (codesetp)
- *codesetp = NULL;
- }
- else
- {
- /* We have to create a new binding. */
- size_t len = strlen (domainname) + 1;
- struct binding *new_binding =
- (struct binding *) malloc (offsetof (struct binding, domainname) + len);
-
- if (__builtin_expect (new_binding == NULL, 0))
- goto failed;
-
- memcpy (new_binding->domainname, domainname, len);
-
- if (dirnamep)
- {
- const char *dirname = *dirnamep;
-
- if (dirname == NULL)
- /* The default value. */
- dirname = INTUSE(_nl_default_dirname);
- else
- {
- if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
- dirname = INTUSE(_nl_default_dirname);
- else
- {
- char *result;
-#if defined _LIBC || defined HAVE_STRDUP
- result = strdup (dirname);
- if (__builtin_expect (result == NULL, 0))
- goto failed_dirname;
-#else
- size_t len = strlen (dirname) + 1;
- result = (char *) malloc (len);
- if (__builtin_expect (result == NULL, 0))
- goto failed_dirname;
- memcpy (result, dirname, len);
-#endif
- dirname = result;
- }
- }
- *dirnamep = dirname;
- new_binding->dirname = (char *) dirname;
- }
- else
- /* The default value. */
- new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
-
- new_binding->codeset_cntr = 0;
-
- if (codesetp)
- {
- const char *codeset = *codesetp;
-
- if (codeset != NULL)
- {
- char *result;
-
-#if defined _LIBC || defined HAVE_STRDUP
- result = strdup (codeset);
- if (__builtin_expect (result == NULL, 0))
- goto failed_codeset;
-#else
- size_t len = strlen (codeset) + 1;
- result = (char *) malloc (len);
- if (__builtin_expect (result == NULL, 0))
- goto failed_codeset;
- memcpy (result, codeset, len);
-#endif
- codeset = result;
- new_binding->codeset_cntr++;
- }
- *codesetp = codeset;
- new_binding->codeset = (char *) codeset;
- }
- else
- new_binding->codeset = NULL;
-
- /* Now enqueue it. */
- if (_nl_domain_bindings == NULL
- || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
- {
- new_binding->next = _nl_domain_bindings;
- _nl_domain_bindings = new_binding;
- }
- else
- {
- binding = _nl_domain_bindings;
- while (binding->next != NULL
- && strcmp (domainname, binding->next->domainname) > 0)
- binding = binding->next;
-
- new_binding->next = binding->next;
- binding->next = new_binding;
- }
-
- modified = 1;
-
- /* Here we deal with memory allocation failures. */
- if (0)
- {
- failed_codeset:
- if (new_binding->dirname != INTUSE(_nl_default_dirname))
- free (new_binding->dirname);
- failed_dirname:
- free (new_binding);
- failed:
- if (dirnamep)
- *dirnamep = NULL;
- if (codesetp)
- *codesetp = NULL;
- }
- }
-
- /* If we modified any binding, we flush the caches. */
- if (modified)
- ++_nl_msg_cat_cntr;
-
- __libc_rwlock_unlock (_nl_state_lock);
-}
-
-/* Specify that the DOMAINNAME message catalog will be found
- in DIRNAME rather than in the system locale data base. */
-char *
-BINDTEXTDOMAIN (domainname, dirname)
- const char *domainname;
- const char *dirname;
-{
- set_binding_values (domainname, &dirname, NULL);
- return (char *) dirname;
-}
-
-/* Specify the character encoding in which the messages from the
- DOMAINNAME message catalog will be returned. */
-char *
-BIND_TEXTDOMAIN_CODESET (domainname, codeset)
- const char *domainname;
- const char *codeset;
-{
- set_binding_values (domainname, NULL, &codeset);
- return (char *) codeset;
-}
-
-#ifdef _LIBC
-/* Aliases for function names in GNU C Library. */
-weak_alias (__bindtextdomain, bindtextdomain);
-weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
-#endif
diff --git a/src/audacious/intl/config.charset b/src/audacious/intl/config.charset
deleted file mode 100644
index 11b3b5f..0000000
--- a/src/audacious/intl/config.charset
+++ /dev/null
@@ -1,467 +0,0 @@
-#! /bin/sh
-# Output a system dependent table of character encoding aliases.
-#
-# Copyright (C) 2000-2003 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-#
-# The table consists of lines of the form
-# ALIAS CANONICAL
-#
-# ALIAS is the (system dependent) result of "nl_langinfo (CODESET)".
-# ALIAS is compared in a case sensitive way.
-#
-# CANONICAL is the GNU canonical name for this character encoding.
-# It must be an encoding supported by libiconv. Support by GNU libc is
-# also desirable. CANONICAL is case insensitive. Usually an upper case
-# MIME charset name is preferred.
-# The current list of GNU canonical charset names is as follows.
-#
-# name used by which systems a MIME name?
-# ASCII, ANSI_X3.4-1968 glibc solaris freebsd
-# ISO-8859-1 glibc aix hpux irix osf solaris freebsd yes
-# ISO-8859-2 glibc aix hpux irix osf solaris freebsd yes
-# ISO-8859-3 glibc solaris yes
-# ISO-8859-4 osf solaris freebsd yes
-# ISO-8859-5 glibc aix hpux irix osf solaris freebsd yes
-# ISO-8859-6 glibc aix hpux solaris yes
-# ISO-8859-7 glibc aix hpux irix osf solaris yes
-# ISO-8859-8 glibc aix hpux osf solaris yes
-# ISO-8859-9 glibc aix hpux irix osf solaris yes
-# ISO-8859-13 glibc
-# ISO-8859-14 glibc
-# ISO-8859-15 glibc aix osf solaris freebsd
-# KOI8-R glibc solaris freebsd yes
-# KOI8-U glibc freebsd yes
-# KOI8-T glibc
-# CP437 dos
-# CP775 dos
-# CP850 aix osf dos
-# CP852 dos
-# CP855 dos
-# CP856 aix
-# CP857 dos
-# CP861 dos
-# CP862 dos
-# CP864 dos
-# CP865 dos
-# CP866 freebsd dos
-# CP869 dos
-# CP874 woe32 dos
-# CP922 aix
-# CP932 aix woe32 dos
-# CP943 aix
-# CP949 osf woe32 dos
-# CP950 woe32 dos
-# CP1046 aix
-# CP1124 aix
-# CP1125 dos
-# CP1129 aix
-# CP1250 woe32
-# CP1251 glibc solaris woe32
-# CP1252 aix woe32
-# CP1253 woe32
-# CP1254 woe32
-# CP1255 glibc woe32
-# CP1256 woe32
-# CP1257 woe32
-# GB2312 glibc aix hpux irix solaris freebsd yes
-# EUC-JP glibc aix hpux irix osf solaris freebsd yes
-# EUC-KR glibc aix hpux irix osf solaris freebsd yes
-# EUC-TW glibc aix hpux irix osf solaris
-# BIG5 glibc aix hpux osf solaris freebsd yes
-# BIG5-HKSCS glibc solaris
-# GBK glibc aix osf solaris woe32 dos
-# GB18030 glibc solaris
-# SHIFT_JIS hpux osf solaris freebsd yes
-# JOHAB glibc solaris woe32
-# TIS-620 glibc aix hpux osf solaris
-# VISCII glibc yes
-# TCVN5712-1 glibc
-# GEORGIAN-PS glibc
-# HP-ROMAN8 hpux
-# HP-ARABIC8 hpux
-# HP-GREEK8 hpux
-# HP-HEBREW8 hpux
-# HP-TURKISH8 hpux
-# HP-KANA8 hpux
-# DEC-KANJI osf
-# DEC-HANYU osf
-# UTF-8 glibc aix hpux osf solaris yes
-#
-# Note: Names which are not marked as being a MIME name should not be used in
-# Internet protocols for information interchange (mail, news, etc.).
-#
-# Note: ASCII and ANSI_X3.4-1968 are synonymous canonical names. Applications
-# must understand both names and treat them as equivalent.
-#
-# The first argument passed to this file is the canonical host specification,
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-
-host="$1"
-os=`echo "$host" | sed -e 's/^[^-]*-[^-]*-\(.*\)$/\1/'`
-echo "# This file contains a table of character encoding aliases,"
-echo "# suitable for operating system '${os}'."
-echo "# It was automatically generated from config.charset."
-# List of references, updated during installation:
-echo "# Packages using this file: "
-case "$os" in
- linux* | *-gnu*)
- # With glibc-2.1 or newer, we don't need any canonicalization,
- # because glibc has iconv and both glibc and libiconv support all
- # GNU canonical names directly. Therefore, the Makefile does not
- # need to install the alias file at all.
- # The following applies only to glibc-2.0.x and older libcs.
- echo "ISO_646.IRV:1983 ASCII"
- ;;
- aix*)
- echo "ISO8859-1 ISO-8859-1"
- echo "ISO8859-2 ISO-8859-2"
- echo "ISO8859-5 ISO-8859-5"
- echo "ISO8859-6 ISO-8859-6"
- echo "ISO8859-7 ISO-8859-7"
- echo "ISO8859-8 ISO-8859-8"
- echo "ISO8859-9 ISO-8859-9"
- echo "ISO8859-15 ISO-8859-15"
- echo "IBM-850 CP850"
- echo "IBM-856 CP856"
- echo "IBM-921 ISO-8859-13"
- echo "IBM-922 CP922"
- echo "IBM-932 CP932"
- echo "IBM-943 CP943"
- echo "IBM-1046 CP1046"
- echo "IBM-1124 CP1124"
- echo "IBM-1129 CP1129"
- echo "IBM-1252 CP1252"
- echo "IBM-eucCN GB2312"
- echo "IBM-eucJP EUC-JP"
- echo "IBM-eucKR EUC-KR"
- echo "IBM-eucTW EUC-TW"
- echo "big5 BIG5"
- echo "GBK GBK"
- echo "TIS-620 TIS-620"
- echo "UTF-8 UTF-8"
- ;;
- hpux*)
- echo "iso88591 ISO-8859-1"
- echo "iso88592 ISO-8859-2"
- echo "iso88595 ISO-8859-5"
- echo "iso88596 ISO-8859-6"
- echo "iso88597 ISO-8859-7"
- echo "iso88598 ISO-8859-8"
- echo "iso88599 ISO-8859-9"
- echo "iso885915 ISO-8859-15"
- echo "roman8 HP-ROMAN8"
- echo "arabic8 HP-ARABIC8"
- echo "greek8 HP-GREEK8"
- echo "hebrew8 HP-HEBREW8"
- echo "turkish8 HP-TURKISH8"
- echo "kana8 HP-KANA8"
- echo "tis620 TIS-620"
- echo "big5 BIG5"
- echo "eucJP EUC-JP"
- echo "eucKR EUC-KR"
- echo "eucTW EUC-TW"
- echo "hp15CN GB2312"
- #echo "ccdc ?" # what is this?
- echo "SJIS SHIFT_JIS"
- echo "utf8 UTF-8"
- ;;
- irix*)
- echo "ISO8859-1 ISO-8859-1"
- echo "ISO8859-2 ISO-8859-2"
- echo "ISO8859-5 ISO-8859-5"
- echo "ISO8859-7 ISO-8859-7"
- echo "ISO8859-9 ISO-8859-9"
- echo "eucCN GB2312"
- echo "eucJP EUC-JP"
- echo "eucKR EUC-KR"
- echo "eucTW EUC-TW"
- ;;
- osf*)
- echo "ISO8859-1 ISO-8859-1"
- echo "ISO8859-2 ISO-8859-2"
- echo "ISO8859-4 ISO-8859-4"
- echo "ISO8859-5 ISO-8859-5"
- echo "ISO8859-7 ISO-8859-7"
- echo "ISO8859-8 ISO-8859-8"
- echo "ISO8859-9 ISO-8859-9"
- echo "ISO8859-15 ISO-8859-15"
- echo "cp850 CP850"
- echo "big5 BIG5"
- echo "dechanyu DEC-HANYU"
- echo "dechanzi GB2312"
- echo "deckanji DEC-KANJI"
- echo "deckorean EUC-KR"
- echo "eucJP EUC-JP"
- echo "eucKR EUC-KR"
- echo "eucTW EUC-TW"
- echo "GBK GBK"
- echo "KSC5601 CP949"
- echo "sdeckanji EUC-JP"
- echo "SJIS SHIFT_JIS"
- echo "TACTIS TIS-620"
- echo "UTF-8 UTF-8"
- ;;
- solaris*)
- echo "646 ASCII"
- echo "ISO8859-1 ISO-8859-1"
- echo "ISO8859-2 ISO-8859-2"
- echo "ISO8859-3 ISO-8859-3"
- echo "ISO8859-4 ISO-8859-4"
- echo "ISO8859-5 ISO-8859-5"
- echo "ISO8859-6 ISO-8859-6"
- echo "ISO8859-7 ISO-8859-7"
- echo "ISO8859-8 ISO-8859-8"
- echo "ISO8859-9 ISO-8859-9"
- echo "ISO8859-15 ISO-8859-15"
- echo "koi8-r KOI8-R"
- echo "ansi-1251 CP1251"
- echo "BIG5 BIG5"
- echo "Big5-HKSCS BIG5-HKSCS"
- echo "gb2312 GB2312"
- echo "GBK GBK"
- echo "GB18030 GB18030"
- echo "cns11643 EUC-TW"
- echo "5601 EUC-KR"
- echo "ko_KR.johap92 JOHAB"
- echo "eucJP EUC-JP"
- echo "PCK SHIFT_JIS"
- echo "TIS620.2533 TIS-620"
- #echo "sun_eu_greek ?" # what is this?
- echo "UTF-8 UTF-8"
- ;;
- freebsd* | os2*)
- # FreeBSD 4.2 doesn't have nl_langinfo(CODESET); therefore
- # localcharset.c falls back to using the full locale name
- # from the environment variables.
- # Likewise for OS/2. OS/2 has XFree86 just like FreeBSD. Just
- # reuse FreeBSD's locale data for OS/2.
- echo "C ASCII"
- echo "US-ASCII ASCII"
- for l in la_LN lt_LN; do
- echo "$l.ASCII ASCII"
- done
- for l in da_DK de_AT de_CH de_DE en_AU en_CA en_GB en_US es_ES \
- fi_FI fr_BE fr_CA fr_CH fr_FR is_IS it_CH it_IT la_LN \
- lt_LN nl_BE nl_NL no_NO pt_PT sv_SE; do
- echo "$l.ISO_8859-1 ISO-8859-1"
- echo "$l.DIS_8859-15 ISO-8859-15"
- done
- for l in cs_CZ hr_HR hu_HU la_LN lt_LN pl_PL sl_SI; do
- echo "$l.ISO_8859-2 ISO-8859-2"
- done
- for l in la_LN lt_LT; do
- echo "$l.ISO_8859-4 ISO-8859-4"
- done
- for l in ru_RU ru_SU; do
- echo "$l.KOI8-R KOI8-R"
- echo "$l.ISO_8859-5 ISO-8859-5"
- echo "$l.CP866 CP866"
- done
- echo "uk_UA.KOI8-U KOI8-U"
- echo "zh_TW.BIG5 BIG5"
- echo "zh_TW.Big5 BIG5"
- echo "zh_CN.EUC GB2312"
- echo "ja_JP.EUC EUC-JP"
- echo "ja_JP.SJIS SHIFT_JIS"
- echo "ja_JP.Shift_JIS SHIFT_JIS"
- echo "ko_KR.EUC EUC-KR"
- ;;
- netbsd*)
- echo "646 ASCII"
- echo "ISO8859-1 ISO-8859-1"
- echo "ISO8859-2 ISO-8859-2"
- echo "ISO8859-4 ISO-8859-4"
- echo "ISO8859-5 ISO-8859-5"
- echo "ISO8859-15 ISO-8859-15"
- echo "eucCN GB2312"
- echo "eucJP EUC-JP"
- echo "eucKR EUC-KR"
- echo "eucTW EUC-TW"
- echo "BIG5 BIG5"
- echo "SJIS SHIFT_JIS"
- ;;
- beos*)
- # BeOS has a single locale, and it has UTF-8 encoding.
- echo "* UTF-8"
- ;;
- msdosdjgpp*)
- # DJGPP 2.03 doesn't have nl_langinfo(CODESET); therefore
- # localcharset.c falls back to using the full locale name
- # from the environment variables.
- echo "#"
- echo "# The encodings given here may not all be correct."
- echo "# If you find that the encoding given for your language and"
- echo "# country is not the one your DOS machine actually uses, just"
- echo "# correct it in this file, and send a mail to"
- echo "# Juan Manuel Guerrero <st001906@hrz1.hrz.tu-darmstadt.de>"
- echo "# and Bruno Haible <bruno@clisp.org>."
- echo "#"
- echo "C ASCII"
- # ISO-8859-1 languages
- echo "ca CP850"
- echo "ca_ES CP850"
- echo "da CP865" # not CP850 ??
- echo "da_DK CP865" # not CP850 ??
- echo "de CP850"
- echo "de_AT CP850"
- echo "de_CH CP850"
- echo "de_DE CP850"
- echo "en CP850"
- echo "en_AU CP850" # not CP437 ??
- echo "en_CA CP850"
- echo "en_GB CP850"
- echo "en_NZ CP437"
- echo "en_US CP437"
- echo "en_ZA CP850" # not CP437 ??
- echo "es CP850"
- echo "es_AR CP850"
- echo "es_BO CP850"
- echo "es_CL CP850"
- echo "es_CO CP850"
- echo "es_CR CP850"
- echo "es_CU CP850"
- echo "es_DO CP850"
- echo "es_EC CP850"
- echo "es_ES CP850"
- echo "es_GT CP850"
- echo "es_HN CP850"
- echo "es_MX CP850"
- echo "es_NI CP850"
- echo "es_PA CP850"
- echo "es_PY CP850"
- echo "es_PE CP850"
- echo "es_SV CP850"
- echo "es_UY CP850"
- echo "es_VE CP850"
- echo "et CP850"
- echo "et_EE CP850"
- echo "eu CP850"
- echo "eu_ES CP850"
- echo "fi CP850"
- echo "fi_FI CP850"
- echo "fr CP850"
- echo "fr_BE CP850"
- echo "fr_CA CP850"
- echo "fr_CH CP850"
- echo "fr_FR CP850"
- echo "ga CP850"
- echo "ga_IE CP850"
- echo "gd CP850"
- echo "gd_GB CP850"
- echo "gl CP850"
- echo "gl_ES CP850"
- echo "id CP850" # not CP437 ??
- echo "id_ID CP850" # not CP437 ??
- echo "is CP861" # not CP850 ??
- echo "is_IS CP861" # not CP850 ??
- echo "it CP850"
- echo "it_CH CP850"
- echo "it_IT CP850"
- echo "lt CP775"
- echo "lt_LT CP775"
- echo "lv CP775"
- echo "lv_LV CP775"
- echo "nb CP865" # not CP850 ??
- echo "nb_NO CP865" # not CP850 ??
- echo "nl CP850"
- echo "nl_BE CP850"
- echo "nl_NL CP850"
- echo "nn CP865" # not CP850 ??
- echo "nn_NO CP865" # not CP850 ??
- echo "no CP865" # not CP850 ??
- echo "no_NO CP865" # not CP850 ??
- echo "pt CP850"
- echo "pt_BR CP850"
- echo "pt_PT CP850"
- echo "sv CP850"
- echo "sv_SE CP850"
- # ISO-8859-2 languages
- echo "cs CP852"
- echo "cs_CZ CP852"
- echo "hr CP852"
- echo "hr_HR CP852"
- echo "hu CP852"
- echo "hu_HU CP852"
- echo "pl CP852"
- echo "pl_PL CP852"
- echo "ro CP852"
- echo "ro_RO CP852"
- echo "sk CP852"
- echo "sk_SK CP852"
- echo "sl CP852"
- echo "sl_SI CP852"
- echo "sq CP852"
- echo "sq_AL CP852"
- echo "sr CP852" # CP852 or CP866 or CP855 ??
- echo "sr_YU CP852" # CP852 or CP866 or CP855 ??
- # ISO-8859-3 languages
- echo "mt CP850"
- echo "mt_MT CP850"
- # ISO-8859-5 languages
- echo "be CP866"
- echo "be_BE CP866"
- echo "bg CP866" # not CP855 ??
- echo "bg_BG CP866" # not CP855 ??
- echo "mk CP866" # not CP855 ??
- echo "mk_MK CP866" # not CP855 ??
- echo "ru CP866"
- echo "ru_RU CP866"
- echo "uk CP1125"
- echo "uk_UA CP1125"
- # ISO-8859-6 languages
- echo "ar CP864"
- echo "ar_AE CP864"
- echo "ar_DZ CP864"
- echo "ar_EG CP864"
- echo "ar_IQ CP864"
- echo "ar_IR CP864"
- echo "ar_JO CP864"
- echo "ar_KW CP864"
- echo "ar_MA CP864"
- echo "ar_OM CP864"
- echo "ar_QA CP864"
- echo "ar_SA CP864"
- echo "ar_SY CP864"
- # ISO-8859-7 languages
- echo "el CP869"
- echo "el_GR CP869"
- # ISO-8859-8 languages
- echo "he CP862"
- echo "he_IL CP862"
- # ISO-8859-9 languages
- echo "tr CP857"
- echo "tr_TR CP857"
- # Japanese
- echo "ja CP932"
- echo "ja_JP CP932"
- # Chinese
- echo "zh_CN GBK"
- echo "zh_TW CP950" # not CP938 ??
- # Korean
- echo "kr CP949" # not CP934 ??
- echo "kr_KR CP949" # not CP934 ??
- # Thai
- echo "th CP874"
- echo "th_TH CP874"
- # Other
- echo "eo CP850"
- echo "eo_EO CP850"
- ;;
-esac
diff --git a/src/audacious/intl/dcgettext.c b/src/audacious/intl/dcgettext.c
deleted file mode 100644
index 253d4ec..0000000
--- a/src/audacious/intl/dcgettext.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Implementation of the dcgettext(3) function.
- Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define DCGETTEXT __dcgettext
-# define DCIGETTEXT __dcigettext
-#else
-# define DCGETTEXT libintl_dcgettext
-# define DCIGETTEXT libintl_dcigettext
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
- locale. */
-char *
-DCGETTEXT (domainname, msgid, category)
- const char *domainname;
- const char *msgid;
- int category;
-{
- return DCIGETTEXT (domainname, msgid, NULL, 0, 0, category);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-INTDEF(__dcgettext)
-weak_alias (__dcgettext, dcgettext);
-#endif
diff --git a/src/audacious/intl/dcigettext.c b/src/audacious/intl/dcigettext.c
deleted file mode 100644
index 418a4c2..0000000
--- a/src/audacious/intl/dcigettext.c
+++ /dev/null
@@ -1,1238 +0,0 @@
-/* Implementation of the internal dcigettext function.
- Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Tell glibc's <string.h> to provide a prototype for mempcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sys/types.h>
-
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-# define HAVE_ALLOCA 1
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#include <errno.h>
-#ifndef errno
-extern int errno;
-#endif
-#ifndef __set_errno
-# define __set_errno(val) errno = (val)
-#endif
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-#endif
-
-#include <locale.h>
-
-#ifdef _LIBC
- /* Guess whether integer division by zero raises signal SIGFPE.
- Set to 1 only if you know for sure. In case of doubt, set to 0. */
-# if defined __alpha__ || defined __arm__ || defined __i386__ \
- || defined __m68k__ || defined __s390__
-# define INTDIV0_RAISES_SIGFPE 1
-# else
-# define INTDIV0_RAISES_SIGFPE 0
-# endif
-#endif
-#if !INTDIV0_RAISES_SIGFPE
-# include <signal.h>
-#endif
-
-#if defined HAVE_SYS_PARAM_H || defined _LIBC
-# include <sys/param.h>
-#endif
-
-#include "gettextP.h"
-#include "plural-exp.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-#include "hash-string.h"
-
-/* Thread safetyness. */
-#ifdef _LIBC
-# include <bits/libc-lock.h>
-#else
-/* Provide dummy implementation if this is outside glibc. */
-# define __libc_lock_define_initialized(CLASS, NAME)
-# define __libc_lock_lock(NAME)
-# define __libc_lock_unlock(NAME)
-# define __libc_rwlock_define_initialized(CLASS, NAME)
-# define __libc_rwlock_rdlock(NAME)
-# define __libc_rwlock_unlock(NAME)
-#endif
-
-/* Alignment of types. */
-#if defined __GNUC__ && __GNUC__ >= 2
-# define alignof(TYPE) __alignof__ (TYPE)
-#else
-# define alignof(TYPE) \
- ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
-#endif
-
-/* The internal variables in the standalone libintl.a must have different
- names than the internal variables in GNU libc, otherwise programs
- using libintl.a cannot be linked statically. */
-#if !defined _LIBC
-# define _nl_default_default_domain libintl_nl_default_default_domain
-# define _nl_current_default_domain libintl_nl_current_default_domain
-# define _nl_default_dirname libintl_nl_default_dirname
-# define _nl_domain_bindings libintl_nl_domain_bindings
-#endif
-
-/* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
-#ifndef offsetof
-# define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ANSI C functions. This is required by the standard
- because some ANSI C functions will require linking with this object
- file and the name space must not be polluted. */
-# define getcwd __getcwd
-# ifndef stpcpy
-# define stpcpy __stpcpy
-# endif
-# define tfind __tfind
-#else
-# if !defined HAVE_GETCWD
-char *getwd ();
-# define getcwd(buf, max) getwd (buf)
-# else
-char *getcwd ();
-# endif
-# ifndef HAVE_STPCPY
-static char *stpcpy PARAMS ((char *dest, const char *src));
-# endif
-# ifndef HAVE_MEMPCPY
-static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
-# endif
-#endif
-
-/* Amount to increase buffer size by in each try. */
-#define PATH_INCR 32
-
-/* The following is from pathmax.h. */
-/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
- PATH_MAX but might cause redefinition warnings when sys/param.h is
- later included (as on MORE/BSD 4.3). */
-#if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
-# include <limits.h>
-#endif
-
-#ifndef _POSIX_PATH_MAX
-# define _POSIX_PATH_MAX 255
-#endif
-
-#if !defined PATH_MAX && defined _PC_PATH_MAX
-# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
-#endif
-
-/* Don't include sys/param.h if it already has been. */
-#if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
-# include <sys/param.h>
-#endif
-
-#if !defined PATH_MAX && defined MAXPATHLEN
-# define PATH_MAX MAXPATHLEN
-#endif
-
-#ifndef PATH_MAX
-# define PATH_MAX _POSIX_PATH_MAX
-#endif
-
-/* Pathname support.
- ISSLASH(C) tests whether C is a directory separator character.
- IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
- it may be concatenated to a directory pathname.
- IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
- */
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS */
-# define ISSLASH(C) ((C) == '/' || (C) == '\\')
-# define HAS_DEVICE(P) \
- ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
- && (P)[1] == ':')
-# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
-# define IS_PATH_WITH_DIR(P) \
- (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
-#else
- /* Unix */
-# define ISSLASH(C) ((C) == '/')
-# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
-# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
-#endif
-
-/* This is the type used for the search tree where known translations
- are stored. */
-struct known_translation_t
-{
- /* Domain in which to search. */
- char *domainname;
-
- /* The category. */
- int category;
-
- /* State of the catalog counter at the point the string was found. */
- int counter;
-
- /* Catalog where the string was found. */
- struct loaded_l10nfile *domain;
-
- /* And finally the translation. */
- const char *translation;
- size_t translation_length;
-
- /* Pointer to the string in question. */
- char msgid[ZERO];
-};
-
-/* Root of the search tree with known translations. We can use this
- only if the system provides the `tsearch' function family. */
-#if defined HAVE_TSEARCH || defined _LIBC
-# include <search.h>
-
-static void *root;
-
-# ifdef _LIBC
-# define tsearch __tsearch
-# endif
-
-/* Function to compare two entries in the table of known translations. */
-static int transcmp PARAMS ((const void *p1, const void *p2));
-static int
-transcmp (p1, p2)
- const void *p1;
- const void *p2;
-{
- const struct known_translation_t *s1;
- const struct known_translation_t *s2;
- int result;
-
- s1 = (const struct known_translation_t *) p1;
- s2 = (const struct known_translation_t *) p2;
-
- result = strcmp (s1->msgid, s2->msgid);
- if (result == 0)
- {
- result = strcmp (s1->domainname, s2->domainname);
- if (result == 0)
- /* We compare the category last (though this is the cheapest
- operation) since it is hopefully always the same (namely
- LC_MESSAGES). */
- result = s1->category - s2->category;
- }
-
- return result;
-}
-#endif
-
-#ifndef INTVARDEF
-# define INTVARDEF(name)
-#endif
-#ifndef INTUSE
-# define INTUSE(name) name
-#endif
-
-/* Name of the default domain used for gettext(3) prior any call to
- textdomain(3). The default value for this is "messages". */
-const char _nl_default_default_domain[] attribute_hidden = "messages";
-
-/* Value used as the default domain for gettext(3). */
-const char *_nl_current_default_domain attribute_hidden
- = _nl_default_default_domain;
-
-/* Contains the default location of the message catalogs. */
-#if defined __EMX__
-extern const char _nl_default_dirname[];
-#else
-const char _nl_default_dirname[] = LOCALEDIR;
-INTVARDEF (_nl_default_dirname)
-#endif
-
-/* List with bindings of specific domains created by bindtextdomain()
- calls. */
-struct binding *_nl_domain_bindings;
-
-/* Prototypes for local functions. */
-static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
- unsigned long int n,
- const char *translation,
- size_t translation_len))
- internal_function;
-static const char *guess_category_value PARAMS ((int category,
- const char *categoryname))
- internal_function;
-#ifdef _LIBC
-# include "../locale/localeinfo.h"
-# define category_to_name(category) _nl_category_names[category]
-#else
-static const char *category_to_name PARAMS ((int category)) internal_function;
-#endif
-
-
-/* For those loosing systems which don't have `alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-/* Nothing has to be done. */
-# define freea(p) /* nothing */
-# define ADD_BLOCK(list, address) /* nothing */
-# define FREE_BLOCKS(list) /* nothing */
-#else
-struct block_list
-{
- void *address;
- struct block_list *next;
-};
-# define ADD_BLOCK(list, addr) \
- do { \
- struct block_list *newp = (struct block_list *) malloc (sizeof (*newp)); \
- /* If we cannot get a free block we cannot add the new element to \
- the list. */ \
- if (newp != NULL) { \
- newp->address = (addr); \
- newp->next = (list); \
- (list) = newp; \
- } \
- } while (0)
-# define FREE_BLOCKS(list) \
- do { \
- while (list != NULL) { \
- struct block_list *old = list; \
- list = list->next; \
- free (old->address); \
- free (old); \
- } \
- } while (0)
-# undef alloca
-# define alloca(size) (malloc (size))
-# define freea(p) free (p)
-#endif /* have alloca */
-
-
-#ifdef _LIBC
-/* List of blocks allocated for translations. */
-typedef struct transmem_list
-{
- struct transmem_list *next;
- char data[ZERO];
-} transmem_block_t;
-static struct transmem_list *transmem_list;
-#else
-typedef unsigned char transmem_block_t;
-#endif
-
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define DCIGETTEXT __dcigettext
-#else
-# define DCIGETTEXT libintl_dcigettext
-#endif
-
-/* Lock variable to protect the global data in the gettext implementation. */
-#ifdef _LIBC
-__libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
-#endif
-
-/* Checking whether the binaries runs SUID must be done and glibc provides
- easier methods therefore we make a difference here. */
-#ifdef _LIBC
-# define ENABLE_SECURE __libc_enable_secure
-# define DETERMINE_SECURE
-#else
-# ifndef HAVE_GETUID
-# define getuid() 0
-# endif
-# ifndef HAVE_GETGID
-# define getgid() 0
-# endif
-# ifndef HAVE_GETEUID
-# define geteuid() getuid()
-# endif
-# ifndef HAVE_GETEGID
-# define getegid() getgid()
-# endif
-static int enable_secure;
-# define ENABLE_SECURE (enable_secure == 1)
-# define DETERMINE_SECURE \
- if (enable_secure == 0) \
- { \
- if (getuid () != geteuid () || getgid () != getegid ()) \
- enable_secure = 1; \
- else \
- enable_secure = -1; \
- }
-#endif
-
-/* Get the function to evaluate the plural expression. */
-#include "eval-plural.h"
-
-/* Look up MSGID in the DOMAINNAME message catalog for the current
- CATEGORY locale and, if PLURAL is nonzero, search over string
- depending on the plural form determined by N. */
-char *
-DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- int plural;
- unsigned long int n;
- int category;
-{
-#ifndef HAVE_ALLOCA
- struct block_list *block_list = NULL;
-#endif
- struct loaded_l10nfile *domain;
- struct binding *binding;
- const char *categoryname;
- const char *categoryvalue;
- char *dirname, *xdomainname;
- char *single_locale;
- char *retval;
- size_t retlen;
- int saved_errno;
-#if defined HAVE_TSEARCH || defined _LIBC
- struct known_translation_t *search;
- struct known_translation_t **foundp = NULL;
- size_t msgid_len;
-#endif
- size_t domainname_len;
-
- /* If no real MSGID is given return NULL. */
- if (msgid1 == NULL)
- return NULL;
-
-#ifdef _LIBC
- if (category < 0 || category >= __LC_LAST || category == LC_ALL)
- /* Bogus. */
- return (plural == 0
- ? (char *) msgid1
- /* Use the Germanic plural rule. */
- : n == 1 ? (char *) msgid1 : (char *) msgid2);
-#endif
-
- __libc_rwlock_rdlock (_nl_state_lock);
-
- /* If DOMAINNAME is NULL, we are interested in the default domain. If
- CATEGORY is not LC_MESSAGES this might not make much sense but the
- definition left this undefined. */
- if (domainname == NULL)
- domainname = _nl_current_default_domain;
-
- /* OS/2 specific: backward compatibility with older libintl versions */
-#ifdef LC_MESSAGES_COMPAT
- if (category == LC_MESSAGES_COMPAT)
- category = LC_MESSAGES;
-#endif
-
-#if defined HAVE_TSEARCH || defined _LIBC
- msgid_len = strlen (msgid1) + 1;
-
- /* Try to find the translation among those which we found at
- some time. */
- search = (struct known_translation_t *)
- alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
- memcpy (search->msgid, msgid1, msgid_len);
- search->domainname = (char *) domainname;
- search->category = category;
-
- foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
- freea (search);
- if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
- {
- /* Now deal with plural. */
- if (plural)
- retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
- (*foundp)->translation_length);
- else
- retval = (char *) (*foundp)->translation;
-
- __libc_rwlock_unlock (_nl_state_lock);
- return retval;
- }
-#endif
-
- /* Preserve the `errno' value. */
- saved_errno = errno;
-
- /* See whether this is a SUID binary or not. */
- DETERMINE_SECURE;
-
- /* First find matching binding. */
- for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
- {
- int compare = strcmp (domainname, binding->domainname);
- if (compare == 0)
- /* We found it! */
- break;
- if (compare < 0)
- {
- /* It is not in the list. */
- binding = NULL;
- break;
- }
- }
-
- if (binding == NULL)
- dirname = (char *) INTUSE(_nl_default_dirname);
- else if (IS_ABSOLUTE_PATH (binding->dirname))
- dirname = binding->dirname;
- else
- {
- /* We have a relative path. Make it absolute now. */
- size_t dirname_len = strlen (binding->dirname) + 1;
- size_t path_max;
- char *ret;
-
- path_max = (unsigned int) PATH_MAX;
- path_max += 2; /* The getcwd docs say to do this. */
-
- for (;;)
- {
- dirname = (char *) alloca (path_max + dirname_len);
- ADD_BLOCK (block_list, dirname);
-
- __set_errno (0);
- ret = getcwd (dirname, path_max);
- if (ret != NULL || errno != ERANGE)
- break;
-
- path_max += path_max / 2;
- path_max += PATH_INCR;
- }
-
- if (ret == NULL)
- /* We cannot get the current working directory. Don't signal an
- error but simply return the default string. */
- goto return_untranslated;
-
- stpcpy (stpcpy (strchr (dirname, '\0'), "/"), binding->dirname);
- }
-
- /* Now determine the symbolic name of CATEGORY and its value. */
- categoryname = category_to_name (category);
- categoryvalue = guess_category_value (category, categoryname);
-
- domainname_len = strlen (domainname);
- xdomainname = (char *) alloca (strlen (categoryname)
- + domainname_len + 5);
- ADD_BLOCK (block_list, xdomainname);
-
- stpcpy (mempcpy (stpcpy (stpcpy (xdomainname, categoryname), "/"),
- domainname, domainname_len),
- ".mo");
-
- /* Creating working area. */
- single_locale = (char *) alloca (strlen (categoryvalue) + 1);
- ADD_BLOCK (block_list, single_locale);
-
-
- /* Search for the given string. This is a loop because we perhaps
- got an ordered list of languages to consider for the translation. */
- while (1)
- {
- /* Make CATEGORYVALUE point to the next element of the list. */
- while (categoryvalue[0] != '\0' && categoryvalue[0] == ':')
- ++categoryvalue;
- if (categoryvalue[0] == '\0')
- {
- /* The whole contents of CATEGORYVALUE has been searched but
- no valid entry has been found. We solve this situation
- by implicitly appending a "C" entry, i.e. no translation
- will take place. */
- single_locale[0] = 'C';
- single_locale[1] = '\0';
- }
- else
- {
- char *cp = single_locale;
- while (categoryvalue[0] != '\0' && categoryvalue[0] != ':')
- *cp++ = *categoryvalue++;
- *cp = '\0';
-
- /* When this is a SUID binary we must not allow accessing files
- outside the dedicated directories. */
- if (ENABLE_SECURE && IS_PATH_WITH_DIR (single_locale))
- /* Ingore this entry. */
- continue;
- }
-
- /* If the current locale value is C (or POSIX) we don't load a
- domain. Return the MSGID. */
- if (strcmp (single_locale, "C") == 0
- || strcmp (single_locale, "POSIX") == 0)
- break;
-
- /* Find structure describing the message catalog matching the
- DOMAINNAME and CATEGORY. */
- domain = _nl_find_domain (dirname, single_locale, xdomainname, binding);
-
- if (domain != NULL)
- {
- retval = _nl_find_msg (domain, binding, msgid1, &retlen);
-
- if (retval == NULL)
- {
- int cnt;
-
- for (cnt = 0; domain->successor[cnt] != NULL; ++cnt)
- {
- retval = _nl_find_msg (domain->successor[cnt], binding,
- msgid1, &retlen);
-
- if (retval != NULL)
- {
- domain = domain->successor[cnt];
- break;
- }
- }
- }
-
- if (retval != NULL)
- {
- /* Found the translation of MSGID1 in domain DOMAIN:
- starting at RETVAL, RETLEN bytes. */
- FREE_BLOCKS (block_list);
-#if defined HAVE_TSEARCH || defined _LIBC
- if (foundp == NULL)
- {
- /* Create a new entry and add it to the search tree. */
- struct known_translation_t *newp;
-
- newp = (struct known_translation_t *)
- malloc (offsetof (struct known_translation_t, msgid)
- + msgid_len + domainname_len + 1);
- if (newp != NULL)
- {
- newp->domainname =
- mempcpy (newp->msgid, msgid1, msgid_len);
- memcpy (newp->domainname, domainname, domainname_len + 1);
- newp->category = category;
- newp->counter = _nl_msg_cat_cntr;
- newp->domain = domain;
- newp->translation = retval;
- newp->translation_length = retlen;
-
- /* Insert the entry in the search tree. */
- foundp = (struct known_translation_t **)
- tsearch (newp, &root, transcmp);
- if (foundp == NULL
- || __builtin_expect (*foundp != newp, 0))
- /* The insert failed. */
- free (newp);
- }
- }
- else
- {
- /* We can update the existing entry. */
- (*foundp)->counter = _nl_msg_cat_cntr;
- (*foundp)->domain = domain;
- (*foundp)->translation = retval;
- (*foundp)->translation_length = retlen;
- }
-#endif
- __set_errno (saved_errno);
-
- /* Now deal with plural. */
- if (plural)
- retval = plural_lookup (domain, n, retval, retlen);
-
- __libc_rwlock_unlock (_nl_state_lock);
- return retval;
- }
- }
- }
-
- return_untranslated:
- /* Return the untranslated MSGID. */
- FREE_BLOCKS (block_list);
- __libc_rwlock_unlock (_nl_state_lock);
-#ifndef _LIBC
- if (!ENABLE_SECURE)
- {
- extern void _nl_log_untranslated PARAMS ((const char *logfilename,
- const char *domainname,
- const char *msgid1,
- const char *msgid2,
- int plural));
- const char *logfilename = getenv ("GETTEXT_LOG_UNTRANSLATED");
-
- if (logfilename != NULL && logfilename[0] != '\0')
- _nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural);
- }
-#endif
- __set_errno (saved_errno);
- return (plural == 0
- ? (char *) msgid1
- /* Use the Germanic plural rule. */
- : n == 1 ? (char *) msgid1 : (char *) msgid2);
-}
-
-
-char *
-internal_function
-_nl_find_msg (domain_file, domainbinding, msgid, lengthp)
- struct loaded_l10nfile *domain_file;
- struct binding *domainbinding;
- const char *msgid;
- size_t *lengthp;
-{
- struct loaded_domain *domain;
- nls_uint32 nstrings;
- size_t act;
- char *result;
- size_t resultlen;
-
- if (domain_file->decided == 0)
- _nl_load_domain (domain_file, domainbinding);
-
- if (domain_file->data == NULL)
- return NULL;
-
- domain = (struct loaded_domain *) domain_file->data;
-
- nstrings = domain->nstrings;
-
- /* Locate the MSGID and its translation. */
- if (domain->hash_tab != NULL)
- {
- /* Use the hashing table. */
- nls_uint32 len = strlen (msgid);
- nls_uint32 hash_val = hash_string (msgid);
- nls_uint32 idx = hash_val % domain->hash_size;
- nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
-
- while (1)
- {
- nls_uint32 nstr =
- W (domain->must_swap_hash_tab, domain->hash_tab[idx]);
-
- if (nstr == 0)
- /* Hash table entry is empty. */
- return NULL;
-
- nstr--;
-
- /* Compare msgid with the original string at index nstr.
- We compare the lengths with >=, not ==, because plural entries
- are represented by strings with an embedded NUL. */
- if (nstr < nstrings
- ? W (domain->must_swap, domain->orig_tab[nstr].length) >= len
- && (strcmp (msgid,
- domain->data + W (domain->must_swap,
- domain->orig_tab[nstr].offset))
- == 0)
- : domain->orig_sysdep_tab[nstr - nstrings].length > len
- && (strcmp (msgid,
- domain->orig_sysdep_tab[nstr - nstrings].pointer)
- == 0))
- {
- act = nstr;
- goto found;
- }
-
- if (idx >= domain->hash_size - incr)
- idx -= domain->hash_size - incr;
- else
- idx += incr;
- }
- /* NOTREACHED */
- }
- else
- {
- /* Try the default method: binary search in the sorted array of
- messages. */
- size_t top, bottom;
-
- bottom = 0;
- top = nstrings;
- while (bottom < top)
- {
- int cmp_val;
-
- act = (bottom + top) / 2;
- cmp_val = strcmp (msgid, (domain->data
- + W (domain->must_swap,
- domain->orig_tab[act].offset)));
- if (cmp_val < 0)
- top = act;
- else if (cmp_val > 0)
- bottom = act + 1;
- else
- goto found;
- }
- /* No translation was found. */
- return NULL;
- }
-
- found:
- /* The translation was found at index ACT. If we have to convert the
- string to use a different character set, this is the time. */
- if (act < nstrings)
- {
- result = (char *)
- (domain->data + W (domain->must_swap, domain->trans_tab[act].offset));
- resultlen = W (domain->must_swap, domain->trans_tab[act].length) + 1;
- }
- else
- {
- result = (char *) domain->trans_sysdep_tab[act - nstrings].pointer;
- resultlen = domain->trans_sysdep_tab[act - nstrings].length;
- }
-
-#if defined _LIBC || HAVE_ICONV
- if (domain->codeset_cntr
- != (domainbinding != NULL ? domainbinding->codeset_cntr : 0))
- {
- /* The domain's codeset has changed through bind_textdomain_codeset()
- since the message catalog was initialized or last accessed. We
- have to reinitialize the converter. */
- _nl_free_domain_conv (domain);
- _nl_init_domain_conv (domain_file, domain, domainbinding);
- }
-
- if (
-# ifdef _LIBC
- domain->conv != (__gconv_t) -1
-# else
-# if HAVE_ICONV
- domain->conv != (iconv_t) -1
-# endif
-# endif
- )
- {
- /* We are supposed to do a conversion. First allocate an
- appropriate table with the same structure as the table
- of translations in the file, where we can put the pointers
- to the converted strings in.
- There is a slight complication with plural entries. They
- are represented by consecutive NUL terminated strings. We
- handle this case by converting RESULTLEN bytes, including
- NULs. */
-
- if (domain->conv_tab == NULL
- && ((domain->conv_tab =
- (char **) calloc (nstrings + domain->n_sysdep_strings,
- sizeof (char *)))
- == NULL))
- /* Mark that we didn't succeed allocating a table. */
- domain->conv_tab = (char **) -1;
-
- if (__builtin_expect (domain->conv_tab == (char **) -1, 0))
- /* Nothing we can do, no more memory. */
- goto converted;
-
- if (domain->conv_tab[act] == NULL)
- {
- /* We haven't used this string so far, so it is not
- translated yet. Do this now. */
- /* We use a bit more efficient memory handling.
- We allocate always larger blocks which get used over
- time. This is faster than many small allocations. */
- __libc_lock_define_initialized (static, lock)
-# define INITIAL_BLOCK_SIZE 4080
- static unsigned char *freemem;
- static size_t freemem_size;
-
- const unsigned char *inbuf;
- unsigned char *outbuf;
- int malloc_count;
-# ifndef _LIBC
- transmem_block_t *transmem_list = NULL;
-# endif
-
- __libc_lock_lock (lock);
-
- inbuf = (const unsigned char *) result;
- outbuf = freemem + sizeof (size_t);
-
- malloc_count = 0;
- while (1)
- {
- transmem_block_t *newmem;
-# ifdef _LIBC
- size_t non_reversible;
- int res;
-
- if (freemem_size < sizeof (size_t))
- goto resize_freemem;
-
- res = __gconv (domain->conv,
- &inbuf, inbuf + resultlen,
- &outbuf,
- outbuf + freemem_size - sizeof (size_t),
- &non_reversible);
-
- if (res == __GCONV_OK || res == __GCONV_EMPTY_INPUT)
- break;
-
- if (res != __GCONV_FULL_OUTPUT)
- {
- __libc_lock_unlock (lock);
- goto converted;
- }
-
- inbuf = result;
-# else
-# if HAVE_ICONV
- const char *inptr = (const char *) inbuf;
- size_t inleft = resultlen;
- char *outptr = (char *) outbuf;
- size_t outleft;
-
- if (freemem_size < sizeof (size_t))
- goto resize_freemem;
-
- outleft = freemem_size - sizeof (size_t);
- if (iconv (domain->conv,
- (ICONV_CONST char **) &inptr, &inleft,
- &outptr, &outleft)
- != (size_t) (-1))
- {
- outbuf = (unsigned char *) outptr;
- break;
- }
- if (errno != E2BIG)
- {
- __libc_lock_unlock (lock);
- goto converted;
- }
-# endif
-# endif
-
- resize_freemem:
- /* We must allocate a new buffer or resize the old one. */
- if (malloc_count > 0)
- {
- ++malloc_count;
- freemem_size = malloc_count * INITIAL_BLOCK_SIZE;
- newmem = (transmem_block_t *) realloc (transmem_list,
- freemem_size);
-# ifdef _LIBC
- if (newmem != NULL)
- transmem_list = transmem_list->next;
- else
- {
- struct transmem_list *old = transmem_list;
-
- transmem_list = transmem_list->next;
- free (old);
- }
-# endif
- }
- else
- {
- malloc_count = 1;
- freemem_size = INITIAL_BLOCK_SIZE;
- newmem = (transmem_block_t *) malloc (freemem_size);
- }
- if (__builtin_expect (newmem == NULL, 0))
- {
- freemem = NULL;
- freemem_size = 0;
- __libc_lock_unlock (lock);
- goto converted;
- }
-
-# ifdef _LIBC
- /* Add the block to the list of blocks we have to free
- at some point. */
- newmem->next = transmem_list;
- transmem_list = newmem;
-
- freemem = newmem->data;
- freemem_size -= offsetof (struct transmem_list, data);
-# else
- transmem_list = newmem;
- freemem = newmem;
-# endif
-
- outbuf = freemem + sizeof (size_t);
- }
-
- /* We have now in our buffer a converted string. Put this
- into the table of conversions. */
- *(size_t *) freemem = outbuf - freemem - sizeof (size_t);
- domain->conv_tab[act] = (char *) freemem;
- /* Shrink freemem, but keep it aligned. */
- freemem_size -= outbuf - freemem;
- freemem = outbuf;
- freemem += freemem_size & (alignof (size_t) - 1);
- freemem_size = freemem_size & ~ (alignof (size_t) - 1);
-
- __libc_lock_unlock (lock);
- }
-
- /* Now domain->conv_tab[act] contains the translation of all
- the plural variants. */
- result = domain->conv_tab[act] + sizeof (size_t);
- resultlen = *(size_t *) domain->conv_tab[act];
- }
-
- converted:
- /* The result string is converted. */
-
-#endif /* _LIBC || HAVE_ICONV */
-
- *lengthp = resultlen;
- return result;
-}
-
-
-/* Look up a plural variant. */
-static char *
-internal_function
-plural_lookup (domain, n, translation, translation_len)
- struct loaded_l10nfile *domain;
- unsigned long int n;
- const char *translation;
- size_t translation_len;
-{
- struct loaded_domain *domaindata = (struct loaded_domain *) domain->data;
- unsigned long int index;
- const char *p;
-
- index = plural_eval (domaindata->plural, n);
- if (index >= domaindata->nplurals)
- /* This should never happen. It means the plural expression and the
- given maximum value do not match. */
- index = 0;
-
- /* Skip INDEX strings at TRANSLATION. */
- p = translation;
- while (index-- > 0)
- {
-#ifdef _LIBC
- p = __rawmemchr (p, '\0');
-#else
- p = strchr (p, '\0');
-#endif
- /* And skip over the NUL byte. */
- p++;
-
- if (p >= translation + translation_len)
- /* This should never happen. It means the plural expression
- evaluated to a value larger than the number of variants
- available for MSGID1. */
- return (char *) translation;
- }
- return (char *) p;
-}
-
-#ifndef _LIBC
-/* Return string representation of locale CATEGORY. */
-static const char *
-internal_function
-category_to_name (category)
- int category;
-{
- const char *retval;
-
- switch (category)
- {
-#ifdef LC_COLLATE
- case LC_COLLATE:
- retval = "LC_COLLATE";
- break;
-#endif
-#ifdef LC_CTYPE
- case LC_CTYPE:
- retval = "LC_CTYPE";
- break;
-#endif
-#ifdef LC_MONETARY
- case LC_MONETARY:
- retval = "LC_MONETARY";
- break;
-#endif
-#ifdef LC_NUMERIC
- case LC_NUMERIC:
- retval = "LC_NUMERIC";
- break;
-#endif
-#ifdef LC_TIME
- case LC_TIME:
- retval = "LC_TIME";
- break;
-#endif
-#ifdef LC_MESSAGES
- case LC_MESSAGES:
- retval = "LC_MESSAGES";
- break;
-#endif
-#ifdef LC_RESPONSE
- case LC_RESPONSE:
- retval = "LC_RESPONSE";
- break;
-#endif
-#ifdef LC_ALL
- case LC_ALL:
- /* This might not make sense but is perhaps better than any other
- value. */
- retval = "LC_ALL";
- break;
-#endif
- default:
- /* If you have a better idea for a default value let me know. */
- retval = "LC_XXX";
- }
-
- return retval;
-}
-#endif
-
-/* Guess value of current locale from value of the environment variables. */
-static const char *
-internal_function
-guess_category_value (category, categoryname)
- int category;
- const char *categoryname;
-{
- const char *language;
- const char *retval;
-
- /* The highest priority value is the `LANGUAGE' environment
- variable. But we don't use the value if the currently selected
- locale is the C locale. This is a GNU extension. */
- language = getenv ("LANGUAGE");
- if (language != NULL && language[0] == '\0')
- language = NULL;
-
- /* We have to proceed with the POSIX methods of looking to `LC_ALL',
- `LC_xxx', and `LANG'. On some systems this can be done by the
- `setlocale' function itself. */
-#ifdef _LIBC
- retval = __current_locale_name (category);
-#else
- retval = _nl_locale_name (category, categoryname);
-#endif
-
- /* Ignore LANGUAGE if the locale is set to "C" because
- 1. "C" locale usually uses the ASCII encoding, and most international
- messages use non-ASCII characters. These characters get displayed
- as question marks (if using glibc's iconv()) or as invalid 8-bit
- characters (because other iconv()s refuse to convert most non-ASCII
- characters to ASCII). In any case, the output is ugly.
- 2. The precise output of some programs in the "C" locale is specified
- by POSIX and should not depend on environment variables like
- "LANGUAGE". We allow such programs to use gettext(). */
- return language != NULL && strcmp (retval, "C") != 0 ? language : retval;
-}
-
-/* @@ begin of epilog @@ */
-
-/* We don't want libintl.a to depend on any other library. So we
- avoid the non-standard function stpcpy. In GNU C Library this
- function is available, though. Also allow the symbol HAVE_STPCPY
- to be defined. */
-#if !_LIBC && !HAVE_STPCPY
-static char *
-stpcpy (dest, src)
- char *dest;
- const char *src;
-{
- while ((*dest++ = *src++) != '\0')
- /* Do nothing. */ ;
- return dest - 1;
-}
-#endif
-
-#if !_LIBC && !HAVE_MEMPCPY
-static void *
-mempcpy (dest, src, n)
- void *dest;
- const void *src;
- size_t n;
-{
- return (void *) ((char *) memcpy (dest, src, n) + n);
-}
-#endif
-
-
-#ifdef _LIBC
-/* If we want to free all resources we have to do some work at
- program's end. */
-libc_freeres_fn (free_mem)
-{
- void *old;
-
- while (_nl_domain_bindings != NULL)
- {
- struct binding *oldp = _nl_domain_bindings;
- _nl_domain_bindings = _nl_domain_bindings->next;
- if (oldp->dirname != INTUSE(_nl_default_dirname))
- /* Yes, this is a pointer comparison. */
- free (oldp->dirname);
- free (oldp->codeset);
- free (oldp);
- }
-
- if (_nl_current_default_domain != _nl_default_default_domain)
- /* Yes, again a pointer comparison. */
- free ((char *) _nl_current_default_domain);
-
- /* Remove the search tree with the known translations. */
- __tdestroy (root, free);
- root = NULL;
-
- while (transmem_list != NULL)
- {
- old = transmem_list;
- transmem_list = transmem_list->next;
- free (old);
- }
-}
-#endif
diff --git a/src/audacious/intl/dcngettext.c b/src/audacious/intl/dcngettext.c
deleted file mode 100644
index 7006978..0000000
--- a/src/audacious/intl/dcngettext.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/* Implementation of the dcngettext(3) function.
- Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define DCNGETTEXT __dcngettext
-# define DCIGETTEXT __dcigettext
-#else
-# define DCNGETTEXT libintl_dcngettext
-# define DCIGETTEXT libintl_dcigettext
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
- locale. */
-char *
-DCNGETTEXT (domainname, msgid1, msgid2, n, category)
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
- int category;
-{
- return DCIGETTEXT (domainname, msgid1, msgid2, 1, n, category);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__dcngettext, dcngettext);
-#endif
diff --git a/src/audacious/intl/dgettext.c b/src/audacious/intl/dgettext.c
deleted file mode 100644
index 01789d3..0000000
--- a/src/audacious/intl/dgettext.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Implementation of the dgettext(3) function.
- Copyright (C) 1995-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <locale.h>
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define DGETTEXT __dgettext
-# define DCGETTEXT INTUSE(__dcgettext)
-#else
-# define DGETTEXT libintl_dgettext
-# define DCGETTEXT libintl_dcgettext
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog of the current
- LC_MESSAGES locale. */
-char *
-DGETTEXT (domainname, msgid)
- const char *domainname;
- const char *msgid;
-{
- return DCGETTEXT (domainname, msgid, LC_MESSAGES);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__dgettext, dgettext);
-#endif
diff --git a/src/audacious/intl/dngettext.c b/src/audacious/intl/dngettext.c
deleted file mode 100644
index cfcae12..0000000
--- a/src/audacious/intl/dngettext.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Implementation of the dngettext(3) function.
- Copyright (C) 1995-1997, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <locale.h>
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define DNGETTEXT __dngettext
-# define DCNGETTEXT __dcngettext
-#else
-# define DNGETTEXT libintl_dngettext
-# define DCNGETTEXT libintl_dcngettext
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog of the current
- LC_MESSAGES locale and skip message according to the plural form. */
-char *
-DNGETTEXT (domainname, msgid1, msgid2, n)
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
-{
- return DCNGETTEXT (domainname, msgid1, msgid2, n, LC_MESSAGES);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__dngettext, dngettext);
-#endif
diff --git a/src/audacious/intl/eval-plural.h b/src/audacious/intl/eval-plural.h
deleted file mode 100644
index 18f40ae..0000000
--- a/src/audacious/intl/eval-plural.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/* Plural expression evaluation.
- Copyright (C) 2000-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef STATIC
-#define STATIC static
-#endif
-
-/* Evaluate the plural expression and return an index value. */
-STATIC unsigned long int plural_eval PARAMS ((struct expression *pexp,
- unsigned long int n))
- internal_function;
-
-STATIC
-unsigned long int
-internal_function
-plural_eval (pexp, n)
- struct expression *pexp;
- unsigned long int n;
-{
- switch (pexp->nargs)
- {
- case 0:
- switch (pexp->operation)
- {
- case var:
- return n;
- case num:
- return pexp->val.num;
- default:
- break;
- }
- /* NOTREACHED */
- break;
- case 1:
- {
- /* pexp->operation must be lnot. */
- unsigned long int arg = plural_eval (pexp->val.args[0], n);
- return ! arg;
- }
- case 2:
- {
- unsigned long int leftarg = plural_eval (pexp->val.args[0], n);
- if (pexp->operation == lor)
- return leftarg || plural_eval (pexp->val.args[1], n);
- else if (pexp->operation == land)
- return leftarg && plural_eval (pexp->val.args[1], n);
- else
- {
- unsigned long int rightarg = plural_eval (pexp->val.args[1], n);
-
- switch (pexp->operation)
- {
- case mult:
- return leftarg * rightarg;
- case divide:
-#if !INTDIV0_RAISES_SIGFPE
- if (rightarg == 0)
- raise (SIGFPE);
-#endif
- return leftarg / rightarg;
- case module:
-#if !INTDIV0_RAISES_SIGFPE
- if (rightarg == 0)
- raise (SIGFPE);
-#endif
- return leftarg % rightarg;
- case plus:
- return leftarg + rightarg;
- case minus:
- return leftarg - rightarg;
- case less_than:
- return leftarg < rightarg;
- case greater_than:
- return leftarg > rightarg;
- case less_or_equal:
- return leftarg <= rightarg;
- case greater_or_equal:
- return leftarg >= rightarg;
- case equal:
- return leftarg == rightarg;
- case not_equal:
- return leftarg != rightarg;
- default:
- break;
- }
- }
- /* NOTREACHED */
- break;
- }
- case 3:
- {
- /* pexp->operation must be qmop. */
- unsigned long int boolarg = plural_eval (pexp->val.args[0], n);
- return plural_eval (pexp->val.args[boolarg ? 1 : 2], n);
- }
- }
- /* NOTREACHED */
- return 0;
-}
diff --git a/src/audacious/intl/explodename.c b/src/audacious/intl/explodename.c
deleted file mode 100644
index c47ef63..0000000
--- a/src/audacious/intl/explodename.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* Copyright (C) 1995-1998, 2000, 2001 Free Software Foundation, Inc.
- Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "loadinfo.h"
-
-/* On some strange systems still no definition of NULL is found. Sigh! */
-#ifndef NULL
-# if defined __STDC__ && __STDC__
-# define NULL ((void *) 0)
-# else
-# define NULL 0
-# endif
-#endif
-
-/* @@ end of prolog @@ */
-
-char *
-_nl_find_language (name)
- const char *name;
-{
- while (name[0] != '\0' && name[0] != '_' && name[0] != '@'
- && name[0] != '+' && name[0] != ',')
- ++name;
-
- return (char *) name;
-}
-
-
-int
-_nl_explode_name (name, language, modifier, territory, codeset,
- normalized_codeset, special, sponsor, revision)
- char *name;
- const char **language;
- const char **modifier;
- const char **territory;
- const char **codeset;
- const char **normalized_codeset;
- const char **special;
- const char **sponsor;
- const char **revision;
-{
- enum { undecided, xpg, cen } syntax;
- char *cp;
- int mask;
-
- *modifier = NULL;
- *territory = NULL;
- *codeset = NULL;
- *normalized_codeset = NULL;
- *special = NULL;
- *sponsor = NULL;
- *revision = NULL;
-
- /* Now we determine the single parts of the locale name. First
- look for the language. Termination symbols are `_' and `@' if
- we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
- mask = 0;
- syntax = undecided;
- *language = cp = name;
- cp = _nl_find_language (*language);
-
- if (*language == cp)
- /* This does not make sense: language has to be specified. Use
- this entry as it is without exploding. Perhaps it is an alias. */
- cp = strchr (*language, '\0');
- else if (cp[0] == '_')
- {
- /* Next is the territory. */
- cp[0] = '\0';
- *territory = ++cp;
-
- while (cp[0] != '\0' && cp[0] != '.' && cp[0] != '@'
- && cp[0] != '+' && cp[0] != ',' && cp[0] != '_')
- ++cp;
-
- mask |= TERRITORY;
-
- if (cp[0] == '.')
- {
- /* Next is the codeset. */
- syntax = xpg;
- cp[0] = '\0';
- *codeset = ++cp;
-
- while (cp[0] != '\0' && cp[0] != '@')
- ++cp;
-
- mask |= XPG_CODESET;
-
- if (*codeset != cp && (*codeset)[0] != '\0')
- {
- *normalized_codeset = _nl_normalize_codeset (*codeset,
- cp - *codeset);
- if (strcmp (*codeset, *normalized_codeset) == 0)
- free ((char *) *normalized_codeset);
- else
- mask |= XPG_NORM_CODESET;
- }
- }
- }
-
- if (cp[0] == '@' || (syntax != xpg && cp[0] == '+'))
- {
- /* Next is the modifier. */
- syntax = cp[0] == '@' ? xpg : cen;
- cp[0] = '\0';
- *modifier = ++cp;
-
- while (syntax == cen && cp[0] != '\0' && cp[0] != '+'
- && cp[0] != ',' && cp[0] != '_')
- ++cp;
-
- mask |= XPG_MODIFIER | CEN_AUDIENCE;
- }
-
- if (syntax != xpg && (cp[0] == '+' || cp[0] == ',' || cp[0] == '_'))
- {
- syntax = cen;
-
- if (cp[0] == '+')
- {
- /* Next is special application (CEN syntax). */
- cp[0] = '\0';
- *special = ++cp;
-
- while (cp[0] != '\0' && cp[0] != ',' && cp[0] != '_')
- ++cp;
-
- mask |= CEN_SPECIAL;
- }
-
- if (cp[0] == ',')
- {
- /* Next is sponsor (CEN syntax). */
- cp[0] = '\0';
- *sponsor = ++cp;
-
- while (cp[0] != '\0' && cp[0] != '_')
- ++cp;
-
- mask |= CEN_SPONSOR;
- }
-
- if (cp[0] == '_')
- {
- /* Next is revision (CEN syntax). */
- cp[0] = '\0';
- *revision = ++cp;
-
- mask |= CEN_REVISION;
- }
- }
-
- /* For CEN syntax values it might be important to have the
- separator character in the file name, not for XPG syntax. */
- if (syntax == xpg)
- {
- if (*territory != NULL && (*territory)[0] == '\0')
- mask &= ~TERRITORY;
-
- if (*codeset != NULL && (*codeset)[0] == '\0')
- mask &= ~XPG_CODESET;
-
- if (*modifier != NULL && (*modifier)[0] == '\0')
- mask &= ~XPG_MODIFIER;
- }
-
- return mask;
-}
diff --git a/src/audacious/intl/finddomain.c b/src/audacious/intl/finddomain.c
deleted file mode 100644
index 5d209fb..0000000
--- a/src/audacious/intl/finddomain.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Handle list of needed message catalogs
- Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@gnu.org>, 1995.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-#endif
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-/* List of already loaded domains. */
-static struct loaded_l10nfile *_nl_loaded_domains;
-
-
-/* Return a data structure describing the message catalog described by
- the DOMAINNAME and CATEGORY parameters with respect to the currently
- established bindings. */
-struct loaded_l10nfile *
-internal_function
-_nl_find_domain (dirname, locale, domainname, domainbinding)
- const char *dirname;
- char *locale;
- const char *domainname;
- struct binding *domainbinding;
-{
- struct loaded_l10nfile *retval;
- const char *language;
- const char *modifier;
- const char *territory;
- const char *codeset;
- const char *normalized_codeset;
- const char *special;
- const char *sponsor;
- const char *revision;
- const char *alias_value;
- int mask;
-
- /* LOCALE can consist of up to four recognized parts for the XPG syntax:
-
- language[_territory[.codeset]][@modifier]
-
- and six parts for the CEN syntax:
-
- language[_territory][+audience][+special][,[sponsor][_revision]]
-
- Beside the first part all of them are allowed to be missing. If
- the full specified locale is not found, the less specific one are
- looked for. The various parts will be stripped off according to
- the following order:
- (1) revision
- (2) sponsor
- (3) special
- (4) codeset
- (5) normalized codeset
- (6) territory
- (7) audience/modifier
- */
-
- /* If we have already tested for this locale entry there has to
- be one data set in the list of loaded domains. */
- retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
- strlen (dirname) + 1, 0, locale, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, domainname, 0);
- if (retval != NULL)
- {
- /* We know something about this locale. */
- int cnt;
-
- if (retval->decided == 0)
- _nl_load_domain (retval, domainbinding);
-
- if (retval->data != NULL)
- return retval;
-
- for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
- {
- if (retval->successor[cnt]->decided == 0)
- _nl_load_domain (retval->successor[cnt], domainbinding);
-
- if (retval->successor[cnt]->data != NULL)
- break;
- }
- return cnt >= 0 ? retval : NULL;
- /* NOTREACHED */
- }
-
- /* See whether the locale value is an alias. If yes its value
- *overwrites* the alias name. No test for the original value is
- done. */
- alias_value = _nl_expand_alias (locale);
- if (alias_value != NULL)
- {
-#if defined _LIBC || defined HAVE_STRDUP
- locale = strdup (alias_value);
- if (locale == NULL)
- return NULL;
-#else
- size_t len = strlen (alias_value) + 1;
- locale = (char *) malloc (len);
- if (locale == NULL)
- return NULL;
-
- memcpy (locale, alias_value, len);
-#endif
- }
-
- /* Now we determine the single parts of the locale name. First
- look for the language. Termination symbols are `_' and `@' if
- we use XPG4 style, and `_', `+', and `,' if we use CEN syntax. */
- mask = _nl_explode_name (locale, &language, &modifier, &territory,
- &codeset, &normalized_codeset, &special,
- &sponsor, &revision);
-
- /* Create all possible locale entries which might be interested in
- generalization. */
- retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
- strlen (dirname) + 1, mask, language, territory,
- codeset, normalized_codeset, modifier, special,
- sponsor, revision, domainname, 1);
- if (retval == NULL)
- /* This means we are out of core. */
- return NULL;
-
- if (retval->decided == 0)
- _nl_load_domain (retval, domainbinding);
- if (retval->data == NULL)
- {
- int cnt;
- for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
- {
- if (retval->successor[cnt]->decided == 0)
- _nl_load_domain (retval->successor[cnt], domainbinding);
- if (retval->successor[cnt]->data != NULL)
- break;
- }
- }
-
- /* The room for an alias was dynamically allocated. Free it now. */
- if (alias_value != NULL)
- free (locale);
-
- /* The space for normalized_codeset is dynamically allocated. Free it. */
- if (mask & XPG_NORM_CODESET)
- free ((void *) normalized_codeset);
-
- return retval;
-}
-
-
-#ifdef _LIBC
-libc_freeres_fn (free_mem)
-{
- struct loaded_l10nfile *runp = _nl_loaded_domains;
-
- while (runp != NULL)
- {
- struct loaded_l10nfile *here = runp;
- if (runp->data != NULL)
- _nl_unload_domain ((struct loaded_domain *) runp->data);
- runp = runp->next;
- free ((char *) here->filename);
- free (here);
- }
-}
-#endif
diff --git a/src/audacious/intl/gettext.c b/src/audacious/intl/gettext.c
deleted file mode 100644
index affc1a0..0000000
--- a/src/audacious/intl/gettext.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Implementation of gettext(3) function.
- Copyright (C) 1995, 1997, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef _LIBC
-# define __need_NULL
-# include <stddef.h>
-#else
-# include <stdlib.h> /* Just for NULL. */
-#endif
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define GETTEXT __gettext
-# define DCGETTEXT INTUSE(__dcgettext)
-#else
-# define GETTEXT libintl_gettext
-# define DCGETTEXT libintl_dcgettext
-#endif
-
-/* Look up MSGID in the current default message catalog for the current
- LC_MESSAGES locale. If not found, returns MSGID itself (the default
- text). */
-char *
-GETTEXT (msgid)
- const char *msgid;
-{
- return DCGETTEXT (NULL, msgid, LC_MESSAGES);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__gettext, gettext);
-#endif
diff --git a/src/audacious/intl/gettextP.h b/src/audacious/intl/gettextP.h
deleted file mode 100644
index 5df0552..0000000
--- a/src/audacious/intl/gettextP.h
+++ /dev/null
@@ -1,224 +0,0 @@
-/* Header describing internals of libintl library.
- Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@cygnus.com>, 1995.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _GETTEXTP_H
-#define _GETTEXTP_H
-
-#include <stddef.h> /* Get size_t. */
-
-#ifdef _LIBC
-# include "../iconv/gconv_int.h"
-#else
-# if HAVE_ICONV
-# include <iconv.h>
-# endif
-#endif
-
-#include "loadinfo.h"
-
-#include "gmo.h" /* Get nls_uint32. */
-
-/* @@ end of prolog @@ */
-
-#ifndef PARAMS
-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
-# define PARAMS(args) args
-# else
-# define PARAMS(args) ()
-# endif
-#endif
-
-#ifndef internal_function
-# define internal_function
-#endif
-
-#ifndef attribute_hidden
-# define attribute_hidden
-#endif
-
-/* Tell the compiler when a conditional or integer expression is
- almost always true or almost always false. */
-#ifndef HAVE_BUILTIN_EXPECT
-# define __builtin_expect(expr, val) (expr)
-#endif
-
-#ifndef W
-# define W(flag, data) ((flag) ? SWAP (data) : (data))
-#endif
-
-
-#ifdef _LIBC
-# include <byteswap.h>
-# define SWAP(i) bswap_32 (i)
-#else
-static inline nls_uint32
-SWAP (i)
- nls_uint32 i;
-{
- return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24);
-}
-#endif
-
-
-/* In-memory representation of system dependent string. */
-struct sysdep_string_desc
-{
- /* Length of addressed string, including the trailing NUL. */
- size_t length;
- /* Pointer to addressed string. */
- const char *pointer;
-};
-
-/* The representation of an opened message catalog. */
-struct loaded_domain
-{
- /* Pointer to memory containing the .mo file. */
- const char *data;
- /* 1 if the memory is mmap()ed, 0 if the memory is malloc()ed. */
- int use_mmap;
- /* Size of mmap()ed memory. */
- size_t mmap_size;
- /* 1 if the .mo file uses a different endianness than this machine. */
- int must_swap;
- /* Pointer to additional malloc()ed memory. */
- void *malloced;
-
- /* Number of static strings pairs. */
- nls_uint32 nstrings;
- /* Pointer to descriptors of original strings in the file. */
- const struct string_desc *orig_tab;
- /* Pointer to descriptors of translated strings in the file. */
- const struct string_desc *trans_tab;
-
- /* Number of system dependent strings pairs. */
- nls_uint32 n_sysdep_strings;
- /* Pointer to descriptors of original sysdep strings. */
- const struct sysdep_string_desc *orig_sysdep_tab;
- /* Pointer to descriptors of translated sysdep strings. */
- const struct sysdep_string_desc *trans_sysdep_tab;
-
- /* Size of hash table. */
- nls_uint32 hash_size;
- /* Pointer to hash table. */
- const nls_uint32 *hash_tab;
- /* 1 if the hash table uses a different endianness than this machine. */
- int must_swap_hash_tab;
-
- int codeset_cntr;
-#ifdef _LIBC
- __gconv_t conv;
-#else
-# if HAVE_ICONV
- iconv_t conv;
-# endif
-#endif
- char **conv_tab;
-
- struct expression *plural;
- unsigned long int nplurals;
-};
-
-/* We want to allocate a string at the end of the struct. But ISO C
- doesn't allow zero sized arrays. */
-#ifdef __GNUC__
-# define ZERO 0
-#else
-# define ZERO 1
-#endif
-
-/* A set of settings bound to a message domain. Used to store settings
- from bindtextdomain() and bind_textdomain_codeset(). */
-struct binding
-{
- struct binding *next;
- char *dirname;
- int codeset_cntr; /* Incremented each time codeset changes. */
- char *codeset;
- char domainname[ZERO];
-};
-
-/* A counter which is incremented each time some previous translations
- become invalid.
- This variable is part of the external ABI of the GNU libintl. */
-extern int _nl_msg_cat_cntr;
-
-#ifndef _LIBC
-const char *_nl_locale_name PARAMS ((int category, const char *categoryname));
-#endif
-
-struct loaded_l10nfile *_nl_find_domain PARAMS ((const char *__dirname,
- char *__locale,
- const char *__domainname,
- struct binding *__domainbinding))
- internal_function;
-void _nl_load_domain PARAMS ((struct loaded_l10nfile *__domain,
- struct binding *__domainbinding))
- internal_function;
-void _nl_unload_domain PARAMS ((struct loaded_domain *__domain))
- internal_function;
-const char *_nl_init_domain_conv PARAMS ((struct loaded_l10nfile *__domain_file,
- struct loaded_domain *__domain,
- struct binding *__domainbinding))
- internal_function;
-void _nl_free_domain_conv PARAMS ((struct loaded_domain *__domain))
- internal_function;
-
-char *_nl_find_msg PARAMS ((struct loaded_l10nfile *domain_file,
- struct binding *domainbinding,
- const char *msgid, size_t *lengthp))
- internal_function;
-
-#ifdef _LIBC
-extern char *__gettext PARAMS ((const char *__msgid));
-extern char *__dgettext PARAMS ((const char *__domainname,
- const char *__msgid));
-extern char *__dcgettext PARAMS ((const char *__domainname,
- const char *__msgid, int __category));
-extern char *__ngettext PARAMS ((const char *__msgid1, const char *__msgid2,
- unsigned long int __n));
-extern char *__dngettext PARAMS ((const char *__domainname,
- const char *__msgid1, const char *__msgid2,
- unsigned long int n));
-extern char *__dcngettext PARAMS ((const char *__domainname,
- const char *__msgid1, const char *__msgid2,
- unsigned long int __n, int __category));
-extern char *__dcigettext PARAMS ((const char *__domainname,
- const char *__msgid1, const char *__msgid2,
- int __plural, unsigned long int __n,
- int __category));
-extern char *__textdomain PARAMS ((const char *__domainname));
-extern char *__bindtextdomain PARAMS ((const char *__domainname,
- const char *__dirname));
-extern char *__bind_textdomain_codeset PARAMS ((const char *__domainname,
- const char *__codeset));
-#else
-/* Declare the exported libintl_* functions, in a way that allows us to
- call them under their real name. */
-# define _INTL_REDIRECT_MACROS
-# include "libgnuintl.h"
-extern char *libintl_dcigettext PARAMS ((const char *__domainname,
- const char *__msgid1,
- const char *__msgid2,
- int __plural, unsigned long int __n,
- int __category));
-#endif
-
-/* @@ begin of epilog @@ */
-
-#endif /* gettextP.h */
diff --git a/src/audacious/intl/gmo.h b/src/audacious/intl/gmo.h
deleted file mode 100644
index 5c71e06..0000000
--- a/src/audacious/intl/gmo.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Description of GNU message catalog format: general file layout.
- Copyright (C) 1995, 1997, 2000-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _GETTEXT_H
-#define _GETTEXT_H 1
-
-#include <limits.h>
-
-/* @@ end of prolog @@ */
-
-/* The magic number of the GNU message catalog format. */
-#define _MAGIC 0x950412de
-#define _MAGIC_SWAPPED 0xde120495
-
-/* Revision number of the currently used .mo (binary) file format. */
-#define MO_REVISION_NUMBER 0
-
-/* The following contortions are an attempt to use the C preprocessor
- to determine an unsigned integral type that is 32 bits wide. An
- alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
- as of version autoconf-2.13, the AC_CHECK_SIZEOF macro doesn't work
- when cross-compiling. */
-
-#if __STDC__
-# define UINT_MAX_32_BITS 4294967295U
-#else
-# define UINT_MAX_32_BITS 0xFFFFFFFF
-#endif
-
-/* If UINT_MAX isn't defined, assume it's a 32-bit type.
- This should be valid for all systems GNU cares about because
- that doesn't include 16-bit systems, and only modern systems
- (that certainly have <limits.h>) have 64+-bit integral types. */
-
-#ifndef UINT_MAX
-# define UINT_MAX UINT_MAX_32_BITS
-#endif
-
-#if UINT_MAX == UINT_MAX_32_BITS
-typedef unsigned nls_uint32;
-#else
-# if USHRT_MAX == UINT_MAX_32_BITS
-typedef unsigned short nls_uint32;
-# else
-# if ULONG_MAX == UINT_MAX_32_BITS
-typedef unsigned long nls_uint32;
-# else
- /* The following line is intended to throw an error. Using #error is
- not portable enough. */
- "Cannot determine unsigned 32-bit data type."
-# endif
-# endif
-#endif
-
-
-/* Header for binary .mo file format. */
-struct mo_file_header
-{
- /* The magic number. */
- nls_uint32 magic;
- /* The revision number of the file format. */
- nls_uint32 revision;
-
- /* The following are only used in .mo files with major revision 0. */
-
- /* The number of strings pairs. */
- nls_uint32 nstrings;
- /* Offset of table with start offsets of original strings. */
- nls_uint32 orig_tab_offset;
- /* Offset of table with start offsets of translated strings. */
- nls_uint32 trans_tab_offset;
- /* Size of hash table. */
- nls_uint32 hash_tab_size;
- /* Offset of first hash table entry. */
- nls_uint32 hash_tab_offset;
-
- /* The following are only used in .mo files with minor revision >= 1. */
-
- /* The number of system dependent segments. */
- nls_uint32 n_sysdep_segments;
- /* Offset of table describing system dependent segments. */
- nls_uint32 sysdep_segments_offset;
- /* The number of system dependent strings pairs. */
- nls_uint32 n_sysdep_strings;
- /* Offset of table with start offsets of original sysdep strings. */
- nls_uint32 orig_sysdep_tab_offset;
- /* Offset of table with start offsets of translated sysdep strings. */
- nls_uint32 trans_sysdep_tab_offset;
-};
-
-/* Descriptor for static string contained in the binary .mo file. */
-struct string_desc
-{
- /* Length of addressed string, not including the trailing NUL. */
- nls_uint32 length;
- /* Offset of string in file. */
- nls_uint32 offset;
-};
-
-/* The following are only used in .mo files with minor revision >= 1. */
-
-/* Descriptor for system dependent string segment. */
-struct sysdep_segment
-{
- /* Length of addressed string, including the trailing NUL. */
- nls_uint32 length;
- /* Offset of string in file. */
- nls_uint32 offset;
-};
-
-/* Descriptor for system dependent string. */
-struct sysdep_string
-{
- /* Offset of static string segments in file. */
- nls_uint32 offset;
- /* Alternating sequence of static and system dependent segments.
- The last segment is a static segment, including the trailing NUL. */
- struct segment_pair
- {
- /* Size of static segment. */
- nls_uint32 segsize;
- /* Reference to system dependent string segment, or ~0 at the end. */
- nls_uint32 sysdepref;
- } segments[1];
-};
-
-/* Marker for the end of the segments[] array. This has the value 0xFFFFFFFF,
- regardless whether 'int' is 16 bit, 32 bit, or 64 bit. */
-#define SEGMENTS_END ((nls_uint32) ~0)
-
-/* @@ begin of epilog @@ */
-
-#endif /* gettext.h */
diff --git a/src/audacious/intl/hash-string.h b/src/audacious/intl/hash-string.h
deleted file mode 100644
index 1c63776..0000000
--- a/src/audacious/intl/hash-string.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Description of GNU message catalog format: string hashing function.
- Copyright (C) 1995, 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* @@ end of prolog @@ */
-
-#ifndef PARAMS
-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
-# define PARAMS(Args) Args
-# else
-# define PARAMS(Args) ()
-# endif
-#endif
-
-/* We assume to have `unsigned long int' value with at least 32 bits. */
-#define HASHWORDBITS 32
-
-
-/* Defines the so called `hashpjw' function by P.J. Weinberger
- [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
- 1986, 1987 Bell Telephone Laboratories, Inc.] */
-static unsigned long int hash_string PARAMS ((const char *__str_param));
-
-static inline unsigned long int
-hash_string (str_param)
- const char *str_param;
-{
- unsigned long int hval, g;
- const char *str = str_param;
-
- /* Compute the hash value for the given string. */
- hval = 0;
- while (*str != '\0')
- {
- hval <<= 4;
- hval += (unsigned long int) *str++;
- g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
- if (g != 0)
- {
- hval ^= g >> (HASHWORDBITS - 8);
- hval ^= g;
- }
- }
- return hval;
-}
diff --git a/src/audacious/intl/intl-compat.c b/src/audacious/intl/intl-compat.c
deleted file mode 100644
index e0a1783..0000000
--- a/src/audacious/intl/intl-compat.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/* intl-compat.c - Stub functions to call gettext functions from GNU gettext
- Library.
- Copyright (C) 1995, 2000-2003 Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "gettextP.h"
-
-/* @@ end of prolog @@ */
-
-/* This file redirects the gettext functions (without prefix) to those
- defined in the included GNU libintl library (with "libintl_" prefix).
- It is compiled into libintl in order to make the AM_GNU_GETTEXT test
- of gettext <= 0.11.2 work with the libintl library >= 0.11.3 which
- has the redirections primarily in the <libintl.h> include file.
- It is also compiled into libgnuintl so that libgnuintl.so can be used
- as LD_PRELOADable library on glibc systems, to provide the extra
- features that the functions in the libc don't have (namely, logging). */
-
-
-#undef gettext
-#undef dgettext
-#undef dcgettext
-#undef ngettext
-#undef dngettext
-#undef dcngettext
-#undef textdomain
-#undef bindtextdomain
-#undef bind_textdomain_codeset
-
-
-/* When building a DLL, we must export some functions. Note that because
- the functions are only defined for binary backward compatibility, we
- don't need to use __declspec(dllimport) in any case. */
-#if defined _MSC_VER && BUILDING_DLL
-# define DLL_EXPORTED __declspec(dllexport)
-#else
-# define DLL_EXPORTED
-#endif
-
-
-DLL_EXPORTED
-char *
-gettext (msgid)
- const char *msgid;
-{
- return libintl_gettext (msgid);
-}
-
-
-DLL_EXPORTED
-char *
-dgettext (domainname, msgid)
- const char *domainname;
- const char *msgid;
-{
- return libintl_dgettext (domainname, msgid);
-}
-
-
-DLL_EXPORTED
-char *
-dcgettext (domainname, msgid, category)
- const char *domainname;
- const char *msgid;
- int category;
-{
- return libintl_dcgettext (domainname, msgid, category);
-}
-
-
-DLL_EXPORTED
-char *
-ngettext (msgid1, msgid2, n)
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
-{
- return libintl_ngettext (msgid1, msgid2, n);
-}
-
-
-DLL_EXPORTED
-char *
-dngettext (domainname, msgid1, msgid2, n)
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
-{
- return libintl_dngettext (domainname, msgid1, msgid2, n);
-}
-
-
-DLL_EXPORTED
-char *
-dcngettext (domainname, msgid1, msgid2, n, category)
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
- int category;
-{
- return libintl_dcngettext (domainname, msgid1, msgid2, n, category);
-}
-
-
-DLL_EXPORTED
-char *
-textdomain (domainname)
- const char *domainname;
-{
- return libintl_textdomain (domainname);
-}
-
-
-DLL_EXPORTED
-char *
-bindtextdomain (domainname, dirname)
- const char *domainname;
- const char *dirname;
-{
- return libintl_bindtextdomain (domainname, dirname);
-}
-
-
-DLL_EXPORTED
-char *
-bind_textdomain_codeset (domainname, codeset)
- const char *domainname;
- const char *codeset;
-{
- return libintl_bind_textdomain_codeset (domainname, codeset);
-}
diff --git a/src/audacious/intl/l10nflist.c b/src/audacious/intl/l10nflist.c
deleted file mode 100644
index d149155..0000000
--- a/src/audacious/intl/l10nflist.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
- Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Tell glibc's <string.h> to provide a prototype for stpcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <string.h>
-
-#if defined _LIBC || defined HAVE_ARGZ_H
-# include <argz.h>
-#endif
-#include <ctype.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-#include "loadinfo.h"
-
-/* On some strange systems still no definition of NULL is found. Sigh! */
-#ifndef NULL
-# if defined __STDC__ && __STDC__
-# define NULL ((void *) 0)
-# else
-# define NULL 0
-# endif
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ANSI C functions. This is required by the standard
- because some ANSI C functions will require linking with this object
- file and the name space must not be polluted. */
-# ifndef stpcpy
-# define stpcpy(dest, src) __stpcpy(dest, src)
-# endif
-#else
-# ifndef HAVE_STPCPY
-static char *stpcpy PARAMS ((char *dest, const char *src));
-# endif
-#endif
-
-/* Pathname support.
- ISSLASH(C) tests whether C is a directory separator character.
- IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not,
- it may be concatenated to a directory pathname.
- */
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS */
-# define ISSLASH(C) ((C) == '/' || (C) == '\\')
-# define HAS_DEVICE(P) \
- ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
- && (P)[1] == ':')
-# define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
-#else
- /* Unix */
-# define ISSLASH(C) ((C) == '/')
-# define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
-#endif
-
-/* Define function which are usually not available. */
-
-#if !defined _LIBC && !defined HAVE___ARGZ_COUNT
-/* Returns the number of strings in ARGZ. */
-static size_t argz_count__ PARAMS ((const char *argz, size_t len));
-
-static size_t
-argz_count__ (argz, len)
- const char *argz;
- size_t len;
-{
- size_t count = 0;
- while (len > 0)
- {
- size_t part_len = strlen (argz);
- argz += part_len + 1;
- len -= part_len + 1;
- count++;
- }
- return count;
-}
-# undef __argz_count
-# define __argz_count(argz, len) argz_count__ (argz, len)
-#else
-# ifdef _LIBC
-# define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
-# endif
-#endif /* !_LIBC && !HAVE___ARGZ_COUNT */
-
-#if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
-/* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
- except the last into the character SEP. */
-static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
-
-static void
-argz_stringify__ (argz, len, sep)
- char *argz;
- size_t len;
- int sep;
-{
- while (len > 0)
- {
- size_t part_len = strlen (argz);
- argz += part_len;
- len -= part_len + 1;
- if (len > 0)
- *argz++ = sep;
- }
-}
-# undef __argz_stringify
-# define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
-#else
-# ifdef _LIBC
-# define __argz_stringify(argz, len, sep) \
- INTUSE(__argz_stringify) (argz, len, sep)
-# endif
-#endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
-
-#if !defined _LIBC && !defined HAVE___ARGZ_NEXT
-static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
- const char *entry));
-
-static char *
-argz_next__ (argz, argz_len, entry)
- char *argz;
- size_t argz_len;
- const char *entry;
-{
- if (entry)
- {
- if (entry < argz + argz_len)
- entry = strchr (entry, '\0') + 1;
-
- return entry >= argz + argz_len ? NULL : (char *) entry;
- }
- else
- if (argz_len > 0)
- return argz;
- else
- return 0;
-}
-# undef __argz_next
-# define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
-#endif /* !_LIBC && !HAVE___ARGZ_NEXT */
-
-
-/* Return number of bits set in X. */
-static int pop PARAMS ((int x));
-
-static inline int
-pop (x)
- int x;
-{
- /* We assume that no more than 16 bits are used. */
- x = ((x & ~0x5555) >> 1) + (x & 0x5555);
- x = ((x & ~0x3333) >> 2) + (x & 0x3333);
- x = ((x >> 4) + x) & 0x0f0f;
- x = ((x >> 8) + x) & 0xff;
-
- return x;
-}
-
-
-struct loaded_l10nfile *
-_nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
- territory, codeset, normalized_codeset, modifier, special,
- sponsor, revision, filename, do_allocate)
- struct loaded_l10nfile **l10nfile_list;
- const char *dirlist;
- size_t dirlist_len;
- int mask;
- const char *language;
- const char *territory;
- const char *codeset;
- const char *normalized_codeset;
- const char *modifier;
- const char *special;
- const char *sponsor;
- const char *revision;
- const char *filename;
- int do_allocate;
-{
- char *abs_filename;
- struct loaded_l10nfile **lastp;
- struct loaded_l10nfile *retval;
- char *cp;
- size_t dirlist_count;
- size_t entries;
- int cnt;
-
- /* If LANGUAGE contains an absolute directory specification, we ignore
- DIRLIST. */
- if (IS_ABSOLUTE_PATH (language))
- dirlist_len = 0;
-
- /* Allocate room for the full file name. */
- abs_filename = (char *) malloc (dirlist_len
- + strlen (language)
- + ((mask & TERRITORY) != 0
- ? strlen (territory) + 1 : 0)
- + ((mask & XPG_CODESET) != 0
- ? strlen (codeset) + 1 : 0)
- + ((mask & XPG_NORM_CODESET) != 0
- ? strlen (normalized_codeset) + 1 : 0)
- + (((mask & XPG_MODIFIER) != 0
- || (mask & CEN_AUDIENCE) != 0)
- ? strlen (modifier) + 1 : 0)
- + ((mask & CEN_SPECIAL) != 0
- ? strlen (special) + 1 : 0)
- + (((mask & CEN_SPONSOR) != 0
- || (mask & CEN_REVISION) != 0)
- ? (1 + ((mask & CEN_SPONSOR) != 0
- ? strlen (sponsor) : 0)
- + ((mask & CEN_REVISION) != 0
- ? strlen (revision) + 1 : 0)) : 0)
- + 1 + strlen (filename) + 1);
-
- if (abs_filename == NULL)
- return NULL;
-
- /* Construct file name. */
- cp = abs_filename;
- if (dirlist_len > 0)
- {
- memcpy (cp, dirlist, dirlist_len);
- __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
- cp += dirlist_len;
- cp[-1] = '/';
- }
-
- cp = stpcpy (cp, language);
-
- if ((mask & TERRITORY) != 0)
- {
- *cp++ = '_';
- cp = stpcpy (cp, territory);
- }
- if ((mask & XPG_CODESET) != 0)
- {
- *cp++ = '.';
- cp = stpcpy (cp, codeset);
- }
- if ((mask & XPG_NORM_CODESET) != 0)
- {
- *cp++ = '.';
- cp = stpcpy (cp, normalized_codeset);
- }
- if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
- {
- /* This component can be part of both syntaces but has different
- leading characters. For CEN we use `+', else `@'. */
- *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
- cp = stpcpy (cp, modifier);
- }
- if ((mask & CEN_SPECIAL) != 0)
- {
- *cp++ = '+';
- cp = stpcpy (cp, special);
- }
- if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
- {
- *cp++ = ',';
- if ((mask & CEN_SPONSOR) != 0)
- cp = stpcpy (cp, sponsor);
- if ((mask & CEN_REVISION) != 0)
- {
- *cp++ = '_';
- cp = stpcpy (cp, revision);
- }
- }
-
- *cp++ = '/';
- stpcpy (cp, filename);
-
- /* Look in list of already loaded domains whether it is already
- available. */
- lastp = l10nfile_list;
- for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
- if (retval->filename != NULL)
- {
- int compare = strcmp (retval->filename, abs_filename);
- if (compare == 0)
- /* We found it! */
- break;
- if (compare < 0)
- {
- /* It's not in the list. */
- retval = NULL;
- break;
- }
-
- lastp = &retval->next;
- }
-
- if (retval != NULL || do_allocate == 0)
- {
- free (abs_filename);
- return retval;
- }
-
- dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
-
- /* Allocate a new loaded_l10nfile. */
- retval =
- (struct loaded_l10nfile *)
- malloc (sizeof (*retval)
- + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
- * sizeof (struct loaded_l10nfile *)));
- if (retval == NULL)
- return NULL;
-
- retval->filename = abs_filename;
-
- /* We set retval->data to NULL here; it is filled in later.
- Setting retval->decided to 1 here means that retval does not
- correspond to a real file (dirlist_count > 1) or is not worth
- looking up (if an unnormalized codeset was specified). */
- retval->decided = (dirlist_count > 1
- || ((mask & XPG_CODESET) != 0
- && (mask & XPG_NORM_CODESET) != 0));
- retval->data = NULL;
-
- retval->next = *lastp;
- *lastp = retval;
-
- entries = 0;
- /* Recurse to fill the inheritance list of RETVAL.
- If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
- entry does not correspond to a real file; retval->filename contains
- colons. In this case we loop across all elements of DIRLIST and
- across all bit patterns dominated by MASK.
- If the DIRLIST is a single directory or entirely redundant (i.e.
- DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
- MASK, excluding MASK itself.
- In either case, we loop down from MASK to 0. This has the effect
- that the extra bits in the locale name are dropped in this order:
- first the modifier, then the territory, then the codeset, then the
- normalized_codeset. */
- for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
- if ((cnt & ~mask) == 0
- && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
- && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
- {
- if (dirlist_count > 1)
- {
- /* Iterate over all elements of the DIRLIST. */
- char *dir = NULL;
-
- while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
- != NULL)
- retval->successor[entries++]
- = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
- cnt, language, territory, codeset,
- normalized_codeset, modifier, special,
- sponsor, revision, filename, 1);
- }
- else
- retval->successor[entries++]
- = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
- cnt, language, territory, codeset,
- normalized_codeset, modifier, special,
- sponsor, revision, filename, 1);
- }
- retval->successor[entries] = NULL;
-
- return retval;
-}
-
-/* Normalize codeset name. There is no standard for the codeset
- names. Normalization allows the user to use any of the common
- names. The return value is dynamically allocated and has to be
- freed by the caller. */
-const char *
-_nl_normalize_codeset (codeset, name_len)
- const char *codeset;
- size_t name_len;
-{
- int len = 0;
- int only_digit = 1;
- char *retval;
- char *wp;
- size_t cnt;
-
- for (cnt = 0; cnt < name_len; ++cnt)
- if (isalnum ((unsigned char) codeset[cnt]))
- {
- ++len;
-
- if (isalpha ((unsigned char) codeset[cnt]))
- only_digit = 0;
- }
-
- retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
-
- if (retval != NULL)
- {
- if (only_digit)
- wp = stpcpy (retval, "iso");
- else
- wp = retval;
-
- for (cnt = 0; cnt < name_len; ++cnt)
- if (isalpha ((unsigned char) codeset[cnt]))
- *wp++ = tolower ((unsigned char) codeset[cnt]);
- else if (isdigit ((unsigned char) codeset[cnt]))
- *wp++ = codeset[cnt];
-
- *wp = '\0';
- }
-
- return (const char *) retval;
-}
-
-
-/* @@ begin of epilog @@ */
-
-/* We don't want libintl.a to depend on any other library. So we
- avoid the non-standard function stpcpy. In GNU C Library this
- function is available, though. Also allow the symbol HAVE_STPCPY
- to be defined. */
-#if !_LIBC && !HAVE_STPCPY
-static char *
-stpcpy (dest, src)
- char *dest;
- const char *src;
-{
- while ((*dest++ = *src++) != '\0')
- /* Do nothing. */ ;
- return dest - 1;
-}
-#endif
diff --git a/src/audacious/intl/libgnuintl.h b/src/audacious/intl/libgnuintl.h
deleted file mode 100644
index 5290bc0..0000000
--- a/src/audacious/intl/libgnuintl.h
+++ /dev/null
@@ -1,309 +0,0 @@
-/* Message catalogs for internationalization.
- Copyright (C) 1995-1997, 2000-2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _LIBINTL_H
-#define _LIBINTL_H 1
-
-#include <locale.h>
-
-/* The LC_MESSAGES locale category is the category used by the functions
- gettext() and dgettext(). It is specified in POSIX, but not in ANSI C.
- On systems that don't define it, use an arbitrary value instead.
- On Solaris, <locale.h> defines __LOCALE_H (or _LOCALE_H in Solaris 2.5)
- then includes <libintl.h> (i.e. this file!) and then only defines
- LC_MESSAGES. To avoid a redefinition warning, don't define LC_MESSAGES
- in this case. */
-#if !defined LC_MESSAGES && !(defined __LOCALE_H || (defined _LOCALE_H && defined __sun))
-# define LC_MESSAGES 1729
-#endif
-
-/* We define an additional symbol to signal that we use the GNU
- implementation of gettext. */
-#define __USE_GNU_GETTEXT 1
-
-/* Provide information about the supported file formats. Returns the
- maximum minor revision number supported for a given major revision. */
-#define __GNU_GETTEXT_SUPPORTED_REVISION(major) \
- ((major) == 0 ? 1 : -1)
-
-/* Resolve a platform specific conflict on DJGPP. GNU gettext takes
- precedence over _conio_gettext. */
-#ifdef __DJGPP__
-# undef gettext
-#endif
-
-/* Use _INTL_PARAMS, not PARAMS, in order to avoid clashes with identifiers
- used by programs. Similarly, test __PROTOTYPES, not PROTOTYPES. */
-#ifndef _INTL_PARAMS
-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
-# define _INTL_PARAMS(args) args
-# else
-# define _INTL_PARAMS(args) ()
-# endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* We redirect the functions to those prefixed with "libintl_". This is
- necessary, because some systems define gettext/textdomain/... in the C
- library (namely, Solaris 2.4 and newer, and GNU libc 2.0 and newer).
- If we used the unprefixed names, there would be cases where the
- definition in the C library would override the one in the libintl.so
- shared library. Recall that on ELF systems, the symbols are looked
- up in the following order:
- 1. in the executable,
- 2. in the shared libraries specified on the link command line, in order,
- 3. in the dependencies of the shared libraries specified on the link
- command line,
- 4. in the dlopen()ed shared libraries, in the order in which they were
- dlopen()ed.
- The definition in the C library would override the one in libintl.so if
- either
- * -lc is given on the link command line and -lintl isn't, or
- * -lc is given on the link command line before -lintl, or
- * libintl.so is a dependency of a dlopen()ed shared library but not
- linked to the executable at link time.
- Since Solaris gettext() behaves differently than GNU gettext(), this
- would be unacceptable.
-
- The redirection happens by default through macros in C, so that &gettext
- is independent of the compilation unit, but through inline functions in
- C++, in order not to interfere with the name mangling of class fields or
- class methods called 'gettext'. */
-
-/* The user can define _INTL_REDIRECT_INLINE or _INTL_REDIRECT_MACROS.
- If he doesn't, we choose the method. A third possible method is
- _INTL_REDIRECT_ASM, supported only by GCC. */
-#if !(defined _INTL_REDIRECT_INLINE || defined _INTL_REDIRECT_MACROS)
-# if __GNUC__ >= 2 && !defined __APPLE_CC__ && (defined __STDC__ || defined __cplusplus)
-# define _INTL_REDIRECT_ASM
-# else
-# ifdef __cplusplus
-# define _INTL_REDIRECT_INLINE
-# else
-# define _INTL_REDIRECT_MACROS
-# endif
-# endif
-#endif
-/* Auxiliary macros. */
-#ifdef _INTL_REDIRECT_ASM
-# define _INTL_ASM(cname) __asm__ (_INTL_ASMNAME (__USER_LABEL_PREFIX__, #cname))
-# define _INTL_ASMNAME(prefix,cnamestring) _INTL_STRINGIFY (prefix) cnamestring
-# define _INTL_STRINGIFY(prefix) #prefix
-#else
-# define _INTL_ASM(cname)
-#endif
-
-/* Look up MSGID in the current default message catalog for the current
- LC_MESSAGES locale. If not found, returns MSGID itself (the default
- text). */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_gettext (const char *__msgid);
-static inline char *gettext (const char *__msgid)
-{
- return libintl_gettext (__msgid);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define gettext libintl_gettext
-#endif
-extern char *gettext _INTL_PARAMS ((const char *__msgid))
- _INTL_ASM (libintl_gettext);
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog for the current
- LC_MESSAGES locale. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_dgettext (const char *__domainname, const char *__msgid);
-static inline char *dgettext (const char *__domainname, const char *__msgid)
-{
- return libintl_dgettext (__domainname, __msgid);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define dgettext libintl_dgettext
-#endif
-extern char *dgettext _INTL_PARAMS ((const char *__domainname,
- const char *__msgid))
- _INTL_ASM (libintl_dgettext);
-#endif
-
-/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
- locale. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_dcgettext (const char *__domainname, const char *__msgid,
- int __category);
-static inline char *dcgettext (const char *__domainname, const char *__msgid,
- int __category)
-{
- return libintl_dcgettext (__domainname, __msgid, __category);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define dcgettext libintl_dcgettext
-#endif
-extern char *dcgettext _INTL_PARAMS ((const char *__domainname,
- const char *__msgid,
- int __category))
- _INTL_ASM (libintl_dcgettext);
-#endif
-
-
-/* Similar to `gettext' but select the plural form corresponding to the
- number N. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_ngettext (const char *__msgid1, const char *__msgid2,
- unsigned long int __n);
-static inline char *ngettext (const char *__msgid1, const char *__msgid2,
- unsigned long int __n)
-{
- return libintl_ngettext (__msgid1, __msgid2, __n);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define ngettext libintl_ngettext
-#endif
-extern char *ngettext _INTL_PARAMS ((const char *__msgid1,
- const char *__msgid2,
- unsigned long int __n))
- _INTL_ASM (libintl_ngettext);
-#endif
-
-/* Similar to `dgettext' but select the plural form corresponding to the
- number N. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_dngettext (const char *__domainname, const char *__msgid1,
- const char *__msgid2, unsigned long int __n);
-static inline char *dngettext (const char *__domainname, const char *__msgid1,
- const char *__msgid2, unsigned long int __n)
-{
- return libintl_dngettext (__domainname, __msgid1, __msgid2, __n);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define dngettext libintl_dngettext
-#endif
-extern char *dngettext _INTL_PARAMS ((const char *__domainname,
- const char *__msgid1,
- const char *__msgid2,
- unsigned long int __n))
- _INTL_ASM (libintl_dngettext);
-#endif
-
-/* Similar to `dcgettext' but select the plural form corresponding to the
- number N. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_dcngettext (const char *__domainname,
- const char *__msgid1, const char *__msgid2,
- unsigned long int __n, int __category);
-static inline char *dcngettext (const char *__domainname,
- const char *__msgid1, const char *__msgid2,
- unsigned long int __n, int __category)
-{
- return libintl_dcngettext (__domainname, __msgid1, __msgid2, __n, __category);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define dcngettext libintl_dcngettext
-#endif
-extern char *dcngettext _INTL_PARAMS ((const char *__domainname,
- const char *__msgid1,
- const char *__msgid2,
- unsigned long int __n,
- int __category))
- _INTL_ASM (libintl_dcngettext);
-#endif
-
-
-/* Set the current default message catalog to DOMAINNAME.
- If DOMAINNAME is null, return the current default.
- If DOMAINNAME is "", reset to the default of "messages". */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_textdomain (const char *__domainname);
-static inline char *textdomain (const char *__domainname)
-{
- return libintl_textdomain (__domainname);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define textdomain libintl_textdomain
-#endif
-extern char *textdomain _INTL_PARAMS ((const char *__domainname))
- _INTL_ASM (libintl_textdomain);
-#endif
-
-/* Specify that the DOMAINNAME message catalog will be found
- in DIRNAME rather than in the system locale data base. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_bindtextdomain (const char *__domainname,
- const char *__dirname);
-static inline char *bindtextdomain (const char *__domainname,
- const char *__dirname)
-{
- return libintl_bindtextdomain (__domainname, __dirname);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define bindtextdomain libintl_bindtextdomain
-#endif
-extern char *bindtextdomain _INTL_PARAMS ((const char *__domainname,
- const char *__dirname))
- _INTL_ASM (libintl_bindtextdomain);
-#endif
-
-/* Specify the character encoding in which the messages from the
- DOMAINNAME message catalog will be returned. */
-#ifdef _INTL_REDIRECT_INLINE
-extern char *libintl_bind_textdomain_codeset (const char *__domainname,
- const char *__codeset);
-static inline char *bind_textdomain_codeset (const char *__domainname,
- const char *__codeset)
-{
- return libintl_bind_textdomain_codeset (__domainname, __codeset);
-}
-#else
-#ifdef _INTL_REDIRECT_MACROS
-# define bind_textdomain_codeset libintl_bind_textdomain_codeset
-#endif
-extern char *bind_textdomain_codeset _INTL_PARAMS ((const char *__domainname,
- const char *__codeset))
- _INTL_ASM (libintl_bind_textdomain_codeset);
-#endif
-
-
-/* Support for relocatable packages. */
-
-/* Sets the original and the current installation prefix of the package.
- Relocation simply replaces a pathname starting with the original prefix
- by the corresponding pathname with the current prefix instead. Both
- prefixes should be directory names without trailing slash (i.e. use ""
- instead of "/"). */
-#define libintl_set_relocation_prefix libintl_set_relocation_prefix
-extern void
- libintl_set_relocation_prefix _INTL_PARAMS ((const char *orig_prefix,
- const char *curr_prefix));
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* libintl.h */
diff --git a/src/audacious/intl/loadinfo.h b/src/audacious/intl/loadinfo.h
deleted file mode 100644
index 8fdd670..0000000
--- a/src/audacious/intl/loadinfo.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* Copyright (C) 1996-1999, 2000-2002 Free Software Foundation, Inc.
- This file is part of the GNU C Library.
- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _LOADINFO_H
-#define _LOADINFO_H 1
-
-/* Declarations of locale dependent catalog lookup functions.
- Implemented in
-
- localealias.c Possibly replace a locale name by another.
- explodename.c Split a locale name into its various fields.
- l10nflist.c Generate a list of filenames of possible message catalogs.
- finddomain.c Find and open the relevant message catalogs.
-
- The main function _nl_find_domain() in finddomain.c is declared
- in gettextP.h.
- */
-
-#ifndef PARAMS
-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
-# define PARAMS(args) args
-# else
-# define PARAMS(args) ()
-# endif
-#endif
-
-#ifndef internal_function
-# define internal_function
-#endif
-
-/* Tell the compiler when a conditional or integer expression is
- almost always true or almost always false. */
-#ifndef HAVE_BUILTIN_EXPECT
-# define __builtin_expect(expr, val) (expr)
-#endif
-
-/* Separator in PATH like lists of pathnames. */
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS */
-# define PATH_SEPARATOR ';'
-#else
- /* Unix */
-# define PATH_SEPARATOR ':'
-#endif
-
-/* Encoding of locale name parts. */
-#define CEN_REVISION 1
-#define CEN_SPONSOR 2
-#define CEN_SPECIAL 4
-#define XPG_NORM_CODESET 8
-#define XPG_CODESET 16
-#define TERRITORY 32
-#define CEN_AUDIENCE 64
-#define XPG_MODIFIER 128
-
-#define CEN_SPECIFIC (CEN_REVISION|CEN_SPONSOR|CEN_SPECIAL|CEN_AUDIENCE)
-#define XPG_SPECIFIC (XPG_CODESET|XPG_NORM_CODESET|XPG_MODIFIER)
-
-
-struct loaded_l10nfile
-{
- const char *filename;
- int decided;
-
- const void *data;
-
- struct loaded_l10nfile *next;
- struct loaded_l10nfile *successor[1];
-};
-
-
-/* Normalize codeset name. There is no standard for the codeset
- names. Normalization allows the user to use any of the common
- names. The return value is dynamically allocated and has to be
- freed by the caller. */
-extern const char *_nl_normalize_codeset PARAMS ((const char *codeset,
- size_t name_len));
-
-/* Lookup a locale dependent file.
- *L10NFILE_LIST denotes a pool of lookup results of locale dependent
- files of the same kind, sorted in decreasing order of ->filename.
- DIRLIST and DIRLIST_LEN are an argz list of directories in which to
- look, containing at least one directory (i.e. DIRLIST_LEN > 0).
- MASK, LANGUAGE, TERRITORY, CODESET, NORMALIZED_CODESET, MODIFIER,
- SPECIAL, SPONSOR, REVISION are the pieces of the locale name, as
- produced by _nl_explode_name(). FILENAME is the filename suffix.
- The return value is the lookup result, either found in *L10NFILE_LIST,
- or - if DO_ALLOCATE is nonzero - freshly allocated, or possibly NULL.
- If the return value is non-NULL, it is added to *L10NFILE_LIST, and
- its ->next field denotes the chaining inside *L10NFILE_LIST, and
- furthermore its ->successor[] field contains a list of other lookup
- results from which this lookup result inherits. */
-extern struct loaded_l10nfile *
-_nl_make_l10nflist PARAMS ((struct loaded_l10nfile **l10nfile_list,
- const char *dirlist, size_t dirlist_len, int mask,
- const char *language, const char *territory,
- const char *codeset,
- const char *normalized_codeset,
- const char *modifier, const char *special,
- const char *sponsor, const char *revision,
- const char *filename, int do_allocate));
-
-/* Lookup the real locale name for a locale alias NAME, or NULL if
- NAME is not a locale alias (but possibly a real locale name).
- The return value is statically allocated and must not be freed. */
-extern const char *_nl_expand_alias PARAMS ((const char *name));
-
-/* Split a locale name NAME into its pieces: language, modifier,
- territory, codeset, special, sponsor, revision.
- NAME gets destructively modified: NUL bytes are inserted here and
- there. *LANGUAGE gets assigned NAME. Each of *MODIFIER, *TERRITORY,
- *CODESET, *SPECIAL, *SPONSOR, *REVISION gets assigned either a
- pointer into the old NAME string, or NULL. *NORMALIZED_CODESET
- gets assigned the expanded *CODESET, if it is different from *CODESET;
- this one is dynamically allocated and has to be freed by the caller.
- The return value is a bitmask, where each bit corresponds to one
- filled-in value:
- XPG_MODIFIER, CEN_AUDIENCE for *MODIFIER,
- TERRITORY for *TERRITORY,
- XPG_CODESET for *CODESET,
- XPG_NORM_CODESET for *NORMALIZED_CODESET,
- CEN_SPECIAL for *SPECIAL,
- CEN_SPONSOR for *SPONSOR,
- CEN_REVISION for *REVISION.
- */
-extern int _nl_explode_name PARAMS ((char *name, const char **language,
- const char **modifier,
- const char **territory,
- const char **codeset,
- const char **normalized_codeset,
- const char **special,
- const char **sponsor,
- const char **revision));
-
-/* Split a locale name NAME into a leading language part and all the
- rest. Return a pointer to the first character after the language,
- i.e. to the first byte of the rest. */
-extern char *_nl_find_language PARAMS ((const char *name));
-
-#endif /* loadinfo.h */
diff --git a/src/audacious/intl/loadmsgcat.c b/src/audacious/intl/loadmsgcat.c
deleted file mode 100644
index 78c7cad..0000000
--- a/src/audacious/intl/loadmsgcat.c
+++ /dev/null
@@ -1,1322 +0,0 @@
-/* Load needed message catalogs.
- Copyright (C) 1995-1999, 2000-2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Tell glibc's <string.h> to provide a prototype for mempcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#ifdef __GNUC__
-# undef alloca
-# define alloca __builtin_alloca
-# define HAVE_ALLOCA 1
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#if defined HAVE_UNISTD_H || defined _LIBC
-# include <unistd.h>
-#endif
-
-#ifdef _LIBC
-# include <langinfo.h>
-# include <locale.h>
-#endif
-
-#if (defined HAVE_MMAP && defined HAVE_MUNMAP && !defined DISALLOW_MMAP) \
- || (defined _LIBC && defined _POSIX_MAPPED_FILES)
-# include <sys/mman.h>
-# undef HAVE_MMAP
-# define HAVE_MMAP 1
-#else
-# undef HAVE_MMAP
-#endif
-
-#if defined HAVE_STDINT_H_WITH_UINTMAX || defined _LIBC
-# include <stdint.h>
-#endif
-#if defined HAVE_INTTYPES_H || defined _LIBC
-# include <inttypes.h>
-#endif
-
-#include "gmo.h"
-#include "gettextP.h"
-#include "hash-string.h"
-#include "plural-exp.h"
-
-#ifdef _LIBC
-# include "../locale/localeinfo.h"
-#endif
-
-/* Provide fallback values for macros that ought to be defined in <inttypes.h>.
- Note that our fallback values need not be literal strings, because we don't
- use them with preprocessor string concatenation. */
-#if !defined PRId8 || PRI_MACROS_BROKEN
-# undef PRId8
-# define PRId8 "d"
-#endif
-#if !defined PRIi8 || PRI_MACROS_BROKEN
-# undef PRIi8
-# define PRIi8 "i"
-#endif
-#if !defined PRIo8 || PRI_MACROS_BROKEN
-# undef PRIo8
-# define PRIo8 "o"
-#endif
-#if !defined PRIu8 || PRI_MACROS_BROKEN
-# undef PRIu8
-# define PRIu8 "u"
-#endif
-#if !defined PRIx8 || PRI_MACROS_BROKEN
-# undef PRIx8
-# define PRIx8 "x"
-#endif
-#if !defined PRIX8 || PRI_MACROS_BROKEN
-# undef PRIX8
-# define PRIX8 "X"
-#endif
-#if !defined PRId16 || PRI_MACROS_BROKEN
-# undef PRId16
-# define PRId16 "d"
-#endif
-#if !defined PRIi16 || PRI_MACROS_BROKEN
-# undef PRIi16
-# define PRIi16 "i"
-#endif
-#if !defined PRIo16 || PRI_MACROS_BROKEN
-# undef PRIo16
-# define PRIo16 "o"
-#endif
-#if !defined PRIu16 || PRI_MACROS_BROKEN
-# undef PRIu16
-# define PRIu16 "u"
-#endif
-#if !defined PRIx16 || PRI_MACROS_BROKEN
-# undef PRIx16
-# define PRIx16 "x"
-#endif
-#if !defined PRIX16 || PRI_MACROS_BROKEN
-# undef PRIX16
-# define PRIX16 "X"
-#endif
-#if !defined PRId32 || PRI_MACROS_BROKEN
-# undef PRId32
-# define PRId32 "d"
-#endif
-#if !defined PRIi32 || PRI_MACROS_BROKEN
-# undef PRIi32
-# define PRIi32 "i"
-#endif
-#if !defined PRIo32 || PRI_MACROS_BROKEN
-# undef PRIo32
-# define PRIo32 "o"
-#endif
-#if !defined PRIu32 || PRI_MACROS_BROKEN
-# undef PRIu32
-# define PRIu32 "u"
-#endif
-#if !defined PRIx32 || PRI_MACROS_BROKEN
-# undef PRIx32
-# define PRIx32 "x"
-#endif
-#if !defined PRIX32 || PRI_MACROS_BROKEN
-# undef PRIX32
-# define PRIX32 "X"
-#endif
-#if !defined PRId64 || PRI_MACROS_BROKEN
-# undef PRId64
-# define PRId64 (sizeof (long) == 8 ? "ld" : "lld")
-#endif
-#if !defined PRIi64 || PRI_MACROS_BROKEN
-# undef PRIi64
-# define PRIi64 (sizeof (long) == 8 ? "li" : "lli")
-#endif
-#if !defined PRIo64 || PRI_MACROS_BROKEN
-# undef PRIo64
-# define PRIo64 (sizeof (long) == 8 ? "lo" : "llo")
-#endif
-#if !defined PRIu64 || PRI_MACROS_BROKEN
-# undef PRIu64
-# define PRIu64 (sizeof (long) == 8 ? "lu" : "llu")
-#endif
-#if !defined PRIx64 || PRI_MACROS_BROKEN
-# undef PRIx64
-# define PRIx64 (sizeof (long) == 8 ? "lx" : "llx")
-#endif
-#if !defined PRIX64 || PRI_MACROS_BROKEN
-# undef PRIX64
-# define PRIX64 (sizeof (long) == 8 ? "lX" : "llX")
-#endif
-#if !defined PRIdLEAST8 || PRI_MACROS_BROKEN
-# undef PRIdLEAST8
-# define PRIdLEAST8 "d"
-#endif
-#if !defined PRIiLEAST8 || PRI_MACROS_BROKEN
-# undef PRIiLEAST8
-# define PRIiLEAST8 "i"
-#endif
-#if !defined PRIoLEAST8 || PRI_MACROS_BROKEN
-# undef PRIoLEAST8
-# define PRIoLEAST8 "o"
-#endif
-#if !defined PRIuLEAST8 || PRI_MACROS_BROKEN
-# undef PRIuLEAST8
-# define PRIuLEAST8 "u"
-#endif
-#if !defined PRIxLEAST8 || PRI_MACROS_BROKEN
-# undef PRIxLEAST8
-# define PRIxLEAST8 "x"
-#endif
-#if !defined PRIXLEAST8 || PRI_MACROS_BROKEN
-# undef PRIXLEAST8
-# define PRIXLEAST8 "X"
-#endif
-#if !defined PRIdLEAST16 || PRI_MACROS_BROKEN
-# undef PRIdLEAST16
-# define PRIdLEAST16 "d"
-#endif
-#if !defined PRIiLEAST16 || PRI_MACROS_BROKEN
-# undef PRIiLEAST16
-# define PRIiLEAST16 "i"
-#endif
-#if !defined PRIoLEAST16 || PRI_MACROS_BROKEN
-# undef PRIoLEAST16
-# define PRIoLEAST16 "o"
-#endif
-#if !defined PRIuLEAST16 || PRI_MACROS_BROKEN
-# undef PRIuLEAST16
-# define PRIuLEAST16 "u"
-#endif
-#if !defined PRIxLEAST16 || PRI_MACROS_BROKEN
-# undef PRIxLEAST16
-# define PRIxLEAST16 "x"
-#endif
-#if !defined PRIXLEAST16 || PRI_MACROS_BROKEN
-# undef PRIXLEAST16
-# define PRIXLEAST16 "X"
-#endif
-#if !defined PRIdLEAST32 || PRI_MACROS_BROKEN
-# undef PRIdLEAST32
-# define PRIdLEAST32 "d"
-#endif
-#if !defined PRIiLEAST32 || PRI_MACROS_BROKEN
-# undef PRIiLEAST32
-# define PRIiLEAST32 "i"
-#endif
-#if !defined PRIoLEAST32 || PRI_MACROS_BROKEN
-# undef PRIoLEAST32
-# define PRIoLEAST32 "o"
-#endif
-#if !defined PRIuLEAST32 || PRI_MACROS_BROKEN
-# undef PRIuLEAST32
-# define PRIuLEAST32 "u"
-#endif
-#if !defined PRIxLEAST32 || PRI_MACROS_BROKEN
-# undef PRIxLEAST32
-# define PRIxLEAST32 "x"
-#endif
-#if !defined PRIXLEAST32 || PRI_MACROS_BROKEN
-# undef PRIXLEAST32
-# define PRIXLEAST32 "X"
-#endif
-#if !defined PRIdLEAST64 || PRI_MACROS_BROKEN
-# undef PRIdLEAST64
-# define PRIdLEAST64 PRId64
-#endif
-#if !defined PRIiLEAST64 || PRI_MACROS_BROKEN
-# undef PRIiLEAST64
-# define PRIiLEAST64 PRIi64
-#endif
-#if !defined PRIoLEAST64 || PRI_MACROS_BROKEN
-# undef PRIoLEAST64
-# define PRIoLEAST64 PRIo64
-#endif
-#if !defined PRIuLEAST64 || PRI_MACROS_BROKEN
-# undef PRIuLEAST64
-# define PRIuLEAST64 PRIu64
-#endif
-#if !defined PRIxLEAST64 || PRI_MACROS_BROKEN
-# undef PRIxLEAST64
-# define PRIxLEAST64 PRIx64
-#endif
-#if !defined PRIXLEAST64 || PRI_MACROS_BROKEN
-# undef PRIXLEAST64
-# define PRIXLEAST64 PRIX64
-#endif
-#if !defined PRIdFAST8 || PRI_MACROS_BROKEN
-# undef PRIdFAST8
-# define PRIdFAST8 "d"
-#endif
-#if !defined PRIiFAST8 || PRI_MACROS_BROKEN
-# undef PRIiFAST8
-# define PRIiFAST8 "i"
-#endif
-#if !defined PRIoFAST8 || PRI_MACROS_BROKEN
-# undef PRIoFAST8
-# define PRIoFAST8 "o"
-#endif
-#if !defined PRIuFAST8 || PRI_MACROS_BROKEN
-# undef PRIuFAST8
-# define PRIuFAST8 "u"
-#endif
-#if !defined PRIxFAST8 || PRI_MACROS_BROKEN
-# undef PRIxFAST8
-# define PRIxFAST8 "x"
-#endif
-#if !defined PRIXFAST8 || PRI_MACROS_BROKEN
-# undef PRIXFAST8
-# define PRIXFAST8 "X"
-#endif
-#if !defined PRIdFAST16 || PRI_MACROS_BROKEN
-# undef PRIdFAST16
-# define PRIdFAST16 "d"
-#endif
-#if !defined PRIiFAST16 || PRI_MACROS_BROKEN
-# undef PRIiFAST16
-# define PRIiFAST16 "i"
-#endif
-#if !defined PRIoFAST16 || PRI_MACROS_BROKEN
-# undef PRIoFAST16
-# define PRIoFAST16 "o"
-#endif
-#if !defined PRIuFAST16 || PRI_MACROS_BROKEN
-# undef PRIuFAST16
-# define PRIuFAST16 "u"
-#endif
-#if !defined PRIxFAST16 || PRI_MACROS_BROKEN
-# undef PRIxFAST16
-# define PRIxFAST16 "x"
-#endif
-#if !defined PRIXFAST16 || PRI_MACROS_BROKEN
-# undef PRIXFAST16
-# define PRIXFAST16 "X"
-#endif
-#if !defined PRIdFAST32 || PRI_MACROS_BROKEN
-# undef PRIdFAST32
-# define PRIdFAST32 "d"
-#endif
-#if !defined PRIiFAST32 || PRI_MACROS_BROKEN
-# undef PRIiFAST32
-# define PRIiFAST32 "i"
-#endif
-#if !defined PRIoFAST32 || PRI_MACROS_BROKEN
-# undef PRIoFAST32
-# define PRIoFAST32 "o"
-#endif
-#if !defined PRIuFAST32 || PRI_MACROS_BROKEN
-# undef PRIuFAST32
-# define PRIuFAST32 "u"
-#endif
-#if !defined PRIxFAST32 || PRI_MACROS_BROKEN
-# undef PRIxFAST32
-# define PRIxFAST32 "x"
-#endif
-#if !defined PRIXFAST32 || PRI_MACROS_BROKEN
-# undef PRIXFAST32
-# define PRIXFAST32 "X"
-#endif
-#if !defined PRIdFAST64 || PRI_MACROS_BROKEN
-# undef PRIdFAST64
-# define PRIdFAST64 PRId64
-#endif
-#if !defined PRIiFAST64 || PRI_MACROS_BROKEN
-# undef PRIiFAST64
-# define PRIiFAST64 PRIi64
-#endif
-#if !defined PRIoFAST64 || PRI_MACROS_BROKEN
-# undef PRIoFAST64
-# define PRIoFAST64 PRIo64
-#endif
-#if !defined PRIuFAST64 || PRI_MACROS_BROKEN
-# undef PRIuFAST64
-# define PRIuFAST64 PRIu64
-#endif
-#if !defined PRIxFAST64 || PRI_MACROS_BROKEN
-# undef PRIxFAST64
-# define PRIxFAST64 PRIx64
-#endif
-#if !defined PRIXFAST64 || PRI_MACROS_BROKEN
-# undef PRIXFAST64
-# define PRIXFAST64 PRIX64
-#endif
-#if !defined PRIdMAX || PRI_MACROS_BROKEN
-# undef PRIdMAX
-# define PRIdMAX (sizeof (uintmax_t) == sizeof (long) ? "ld" : "lld")
-#endif
-#if !defined PRIiMAX || PRI_MACROS_BROKEN
-# undef PRIiMAX
-# define PRIiMAX (sizeof (uintmax_t) == sizeof (long) ? "li" : "lli")
-#endif
-#if !defined PRIoMAX || PRI_MACROS_BROKEN
-# undef PRIoMAX
-# define PRIoMAX (sizeof (uintmax_t) == sizeof (long) ? "lo" : "llo")
-#endif
-#if !defined PRIuMAX || PRI_MACROS_BROKEN
-# undef PRIuMAX
-# define PRIuMAX (sizeof (uintmax_t) == sizeof (long) ? "lu" : "llu")
-#endif
-#if !defined PRIxMAX || PRI_MACROS_BROKEN
-# undef PRIxMAX
-# define PRIxMAX (sizeof (uintmax_t) == sizeof (long) ? "lx" : "llx")
-#endif
-#if !defined PRIXMAX || PRI_MACROS_BROKEN
-# undef PRIXMAX
-# define PRIXMAX (sizeof (uintmax_t) == sizeof (long) ? "lX" : "llX")
-#endif
-#if !defined PRIdPTR || PRI_MACROS_BROKEN
-# undef PRIdPTR
-# define PRIdPTR \
- (sizeof (void *) == sizeof (long) ? "ld" : \
- sizeof (void *) == sizeof (int) ? "d" : \
- "lld")
-#endif
-#if !defined PRIiPTR || PRI_MACROS_BROKEN
-# undef PRIiPTR
-# define PRIiPTR \
- (sizeof (void *) == sizeof (long) ? "li" : \
- sizeof (void *) == sizeof (int) ? "i" : \
- "lli")
-#endif
-#if !defined PRIoPTR || PRI_MACROS_BROKEN
-# undef PRIoPTR
-# define PRIoPTR \
- (sizeof (void *) == sizeof (long) ? "lo" : \
- sizeof (void *) == sizeof (int) ? "o" : \
- "llo")
-#endif
-#if !defined PRIuPTR || PRI_MACROS_BROKEN
-# undef PRIuPTR
-# define PRIuPTR \
- (sizeof (void *) == sizeof (long) ? "lu" : \
- sizeof (void *) == sizeof (int) ? "u" : \
- "llu")
-#endif
-#if !defined PRIxPTR || PRI_MACROS_BROKEN
-# undef PRIxPTR
-# define PRIxPTR \
- (sizeof (void *) == sizeof (long) ? "lx" : \
- sizeof (void *) == sizeof (int) ? "x" : \
- "llx")
-#endif
-#if !defined PRIXPTR || PRI_MACROS_BROKEN
-# undef PRIXPTR
-# define PRIXPTR \
- (sizeof (void *) == sizeof (long) ? "lX" : \
- sizeof (void *) == sizeof (int) ? "X" : \
- "llX")
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ISO C functions. This is required by the standard
- because some ISO C functions will require linking with this object
- file and the name space must not be polluted. */
-# define open __open
-# define close __close
-# define read __read
-# define mmap __mmap
-# define munmap __munmap
-#endif
-
-/* For those losing systems which don't have `alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
-#endif
-
-/* For systems that distinguish between text and binary I/O.
- O_BINARY is usually declared in <fcntl.h>. */
-#if !defined O_BINARY && defined _O_BINARY
- /* For MSC-compatible compilers. */
-# define O_BINARY _O_BINARY
-# define O_TEXT _O_TEXT
-#endif
-#ifdef __BEOS__
- /* BeOS 5 has O_BINARY and O_TEXT, but they have no effect. */
-# undef O_BINARY
-# undef O_TEXT
-#endif
-/* On reasonable systems, binary I/O is the default. */
-#ifndef O_BINARY
-# define O_BINARY 0
-#endif
-
-
-/* Prototypes for local functions. Needed to ensure compiler checking of
- function argument counts despite of K&R C function definition syntax. */
-static const char *get_sysdep_segment_value PARAMS ((const char *name));
-
-
-/* We need a sign, whether a new catalog was loaded, which can be associated
- with all translations. This is important if the translations are
- cached by one of GCC's features. */
-int _nl_msg_cat_cntr;
-
-
-/* Expand a system dependent string segment. Return NULL if unsupported. */
-static const char *
-get_sysdep_segment_value (name)
- const char *name;
-{
- /* Test for an ISO C 99 section 7.8.1 format string directive.
- Syntax:
- P R I { d | i | o | u | x | X }
- { { | LEAST | FAST } { 8 | 16 | 32 | 64 } | MAX | PTR } */
- /* We don't use a table of 14 times 6 'const char *' strings here, because
- data relocations cost startup time. */
- if (name[0] == 'P' && name[1] == 'R' && name[2] == 'I')
- {
- if (name[3] == 'd' || name[3] == 'i' || name[3] == 'o' || name[3] == 'u'
- || name[3] == 'x' || name[3] == 'X')
- {
- if (name[4] == '8' && name[5] == '\0')
- {
- if (name[3] == 'd')
- return PRId8;
- if (name[3] == 'i')
- return PRIi8;
- if (name[3] == 'o')
- return PRIo8;
- if (name[3] == 'u')
- return PRIu8;
- if (name[3] == 'x')
- return PRIx8;
- if (name[3] == 'X')
- return PRIX8;
- abort ();
- }
- if (name[4] == '1' && name[5] == '6' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId16;
- if (name[3] == 'i')
- return PRIi16;
- if (name[3] == 'o')
- return PRIo16;
- if (name[3] == 'u')
- return PRIu16;
- if (name[3] == 'x')
- return PRIx16;
- if (name[3] == 'X')
- return PRIX16;
- abort ();
- }
- if (name[4] == '3' && name[5] == '2' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId32;
- if (name[3] == 'i')
- return PRIi32;
- if (name[3] == 'o')
- return PRIo32;
- if (name[3] == 'u')
- return PRIu32;
- if (name[3] == 'x')
- return PRIx32;
- if (name[3] == 'X')
- return PRIX32;
- abort ();
- }
- if (name[4] == '6' && name[5] == '4' && name[6] == '\0')
- {
- if (name[3] == 'd')
- return PRId64;
- if (name[3] == 'i')
- return PRIi64;
- if (name[3] == 'o')
- return PRIo64;
- if (name[3] == 'u')
- return PRIu64;
- if (name[3] == 'x')
- return PRIx64;
- if (name[3] == 'X')
- return PRIX64;
- abort ();
- }
- if (name[4] == 'L' && name[5] == 'E' && name[6] == 'A'
- && name[7] == 'S' && name[8] == 'T')
- {
- if (name[9] == '8' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST8;
- if (name[3] == 'i')
- return PRIiLEAST8;
- if (name[3] == 'o')
- return PRIoLEAST8;
- if (name[3] == 'u')
- return PRIuLEAST8;
- if (name[3] == 'x')
- return PRIxLEAST8;
- if (name[3] == 'X')
- return PRIXLEAST8;
- abort ();
- }
- if (name[9] == '1' && name[10] == '6' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST16;
- if (name[3] == 'i')
- return PRIiLEAST16;
- if (name[3] == 'o')
- return PRIoLEAST16;
- if (name[3] == 'u')
- return PRIuLEAST16;
- if (name[3] == 'x')
- return PRIxLEAST16;
- if (name[3] == 'X')
- return PRIXLEAST16;
- abort ();
- }
- if (name[9] == '3' && name[10] == '2' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST32;
- if (name[3] == 'i')
- return PRIiLEAST32;
- if (name[3] == 'o')
- return PRIoLEAST32;
- if (name[3] == 'u')
- return PRIuLEAST32;
- if (name[3] == 'x')
- return PRIxLEAST32;
- if (name[3] == 'X')
- return PRIXLEAST32;
- abort ();
- }
- if (name[9] == '6' && name[10] == '4' && name[11] == '\0')
- {
- if (name[3] == 'd')
- return PRIdLEAST64;
- if (name[3] == 'i')
- return PRIiLEAST64;
- if (name[3] == 'o')
- return PRIoLEAST64;
- if (name[3] == 'u')
- return PRIuLEAST64;
- if (name[3] == 'x')
- return PRIxLEAST64;
- if (name[3] == 'X')
- return PRIXLEAST64;
- abort ();
- }
- }
- if (name[4] == 'F' && name[5] == 'A' && name[6] == 'S'
- && name[7] == 'T')
- {
- if (name[8] == '8' && name[9] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST8;
- if (name[3] == 'i')
- return PRIiFAST8;
- if (name[3] == 'o')
- return PRIoFAST8;
- if (name[3] == 'u')
- return PRIuFAST8;
- if (name[3] == 'x')
- return PRIxFAST8;
- if (name[3] == 'X')
- return PRIXFAST8;
- abort ();
- }
- if (name[8] == '1' && name[9] == '6' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST16;
- if (name[3] == 'i')
- return PRIiFAST16;
- if (name[3] == 'o')
- return PRIoFAST16;
- if (name[3] == 'u')
- return PRIuFAST16;
- if (name[3] == 'x')
- return PRIxFAST16;
- if (name[3] == 'X')
- return PRIXFAST16;
- abort ();
- }
- if (name[8] == '3' && name[9] == '2' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST32;
- if (name[3] == 'i')
- return PRIiFAST32;
- if (name[3] == 'o')
- return PRIoFAST32;
- if (name[3] == 'u')
- return PRIuFAST32;
- if (name[3] == 'x')
- return PRIxFAST32;
- if (name[3] == 'X')
- return PRIXFAST32;
- abort ();
- }
- if (name[8] == '6' && name[9] == '4' && name[10] == '\0')
- {
- if (name[3] == 'd')
- return PRIdFAST64;
- if (name[3] == 'i')
- return PRIiFAST64;
- if (name[3] == 'o')
- return PRIoFAST64;
- if (name[3] == 'u')
- return PRIuFAST64;
- if (name[3] == 'x')
- return PRIxFAST64;
- if (name[3] == 'X')
- return PRIXFAST64;
- abort ();
- }
- }
- if (name[4] == 'M' && name[5] == 'A' && name[6] == 'X'
- && name[7] == '\0')
- {
- if (name[3] == 'd')
- return PRIdMAX;
- if (name[3] == 'i')
- return PRIiMAX;
- if (name[3] == 'o')
- return PRIoMAX;
- if (name[3] == 'u')
- return PRIuMAX;
- if (name[3] == 'x')
- return PRIxMAX;
- if (name[3] == 'X')
- return PRIXMAX;
- abort ();
- }
- if (name[4] == 'P' && name[5] == 'T' && name[6] == 'R'
- && name[7] == '\0')
- {
- if (name[3] == 'd')
- return PRIdPTR;
- if (name[3] == 'i')
- return PRIiPTR;
- if (name[3] == 'o')
- return PRIoPTR;
- if (name[3] == 'u')
- return PRIuPTR;
- if (name[3] == 'x')
- return PRIxPTR;
- if (name[3] == 'X')
- return PRIXPTR;
- abort ();
- }
- }
- }
- /* Other system dependent strings are not valid. */
- return NULL;
-}
-
-/* Initialize the codeset dependent parts of an opened message catalog.
- Return the header entry. */
-const char *
-internal_function
-_nl_init_domain_conv (domain_file, domain, domainbinding)
- struct loaded_l10nfile *domain_file;
- struct loaded_domain *domain;
- struct binding *domainbinding;
-{
- /* Find out about the character set the file is encoded with.
- This can be found (in textual form) in the entry "". If this
- entry does not exist or if this does not contain the `charset='
- information, we will assume the charset matches the one the
- current locale and we don't have to perform any conversion. */
- char *nullentry;
- size_t nullentrylen;
-
- /* Preinitialize fields, to avoid recursion during _nl_find_msg. */
- domain->codeset_cntr =
- (domainbinding != NULL ? domainbinding->codeset_cntr : 0);
-#ifdef _LIBC
- domain->conv = (__gconv_t) -1;
-#else
-# if HAVE_ICONV
- domain->conv = (iconv_t) -1;
-# endif
-#endif
- domain->conv_tab = NULL;
-
- /* Get the header entry. */
- nullentry = _nl_find_msg (domain_file, domainbinding, "", &nullentrylen);
-
- if (nullentry != NULL)
- {
-#if defined _LIBC || HAVE_ICONV
- const char *charsetstr;
-
- charsetstr = strstr (nullentry, "charset=");
- if (charsetstr != NULL)
- {
- size_t len;
- char *charset;
- const char *outcharset;
-
- charsetstr += strlen ("charset=");
- len = strcspn (charsetstr, " \t\n");
-
- charset = (char *) alloca (len + 1);
-# if defined _LIBC || HAVE_MEMPCPY
- *((char *) mempcpy (charset, charsetstr, len)) = '\0';
-# else
- memcpy (charset, charsetstr, len);
- charset[len] = '\0';
-# endif
-
- /* The output charset should normally be determined by the
- locale. But sometimes the locale is not used or not correctly
- set up, so we provide a possibility for the user to override
- this. Moreover, the value specified through
- bind_textdomain_codeset overrides both. */
- if (domainbinding != NULL && domainbinding->codeset != NULL)
- outcharset = domainbinding->codeset;
- else
- {
- outcharset = getenv ("OUTPUT_CHARSET");
- if (outcharset == NULL || outcharset[0] == '\0')
- {
-# ifdef _LIBC
- outcharset = _NL_CURRENT (LC_CTYPE, CODESET);
-# else
-# if HAVE_ICONV
- extern const char *locale_charset PARAMS ((void));
- outcharset = locale_charset ();
-# endif
-# endif
- }
- }
-
-# ifdef _LIBC
- /* We always want to use transliteration. */
- outcharset = norm_add_slashes (outcharset, "TRANSLIT");
- charset = norm_add_slashes (charset, NULL);
- if (__gconv_open (outcharset, charset, &domain->conv,
- GCONV_AVOID_NOCONV)
- != __GCONV_OK)
- domain->conv = (__gconv_t) -1;
-# else
-# if HAVE_ICONV
- /* When using GNU libc >= 2.2 or GNU libiconv >= 1.5,
- we want to use transliteration. */
-# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) || __GLIBC__ > 2 \
- || _LIBICONV_VERSION >= 0x0105
- if (strchr (outcharset, '/') == NULL)
- {
- char *tmp;
-
- len = strlen (outcharset);
- tmp = (char *) alloca (len + 10 + 1);
- memcpy (tmp, outcharset, len);
- memcpy (tmp + len, "//TRANSLIT", 10 + 1);
- outcharset = tmp;
-
- domain->conv = iconv_open (outcharset, charset);
-
- freea (outcharset);
- }
- else
-# endif
- domain->conv = iconv_open (outcharset, charset);
-# endif
-# endif
-
- freea (charset);
- }
-#endif /* _LIBC || HAVE_ICONV */
- }
-
- return nullentry;
-}
-
-/* Frees the codeset dependent parts of an opened message catalog. */
-void
-internal_function
-_nl_free_domain_conv (domain)
- struct loaded_domain *domain;
-{
- if (domain->conv_tab != NULL && domain->conv_tab != (char **) -1)
- free (domain->conv_tab);
-
-#ifdef _LIBC
- if (domain->conv != (__gconv_t) -1)
- __gconv_close (domain->conv);
-#else
-# if HAVE_ICONV
- if (domain->conv != (iconv_t) -1)
- iconv_close (domain->conv);
-# endif
-#endif
-}
-
-/* Load the message catalogs specified by FILENAME. If it is no valid
- message catalog do nothing. */
-void
-internal_function
-_nl_load_domain (domain_file, domainbinding)
- struct loaded_l10nfile *domain_file;
- struct binding *domainbinding;
-{
- int fd;
- size_t size;
-#ifdef _LIBC
- struct stat64 st;
-#else
- struct stat st;
-#endif
- struct mo_file_header *data = (struct mo_file_header *) -1;
- int use_mmap = 0;
- struct loaded_domain *domain;
- int revision;
- const char *nullentry;
-
- domain_file->decided = 1;
- domain_file->data = NULL;
-
- /* Note that it would be useless to store domainbinding in domain_file
- because domainbinding might be == NULL now but != NULL later (after
- a call to bind_textdomain_codeset). */
-
- /* If the record does not represent a valid locale the FILENAME
- might be NULL. This can happen when according to the given
- specification the locale file name is different for XPG and CEN
- syntax. */
- if (domain_file->filename == NULL)
- return;
-
- /* Try to open the addressed file. */
- fd = open (domain_file->filename, O_RDONLY | O_BINARY);
- if (fd == -1)
- return;
-
- /* We must know about the size of the file. */
- if (
-#ifdef _LIBC
- __builtin_expect (fstat64 (fd, &st) != 0, 0)
-#else
- __builtin_expect (fstat (fd, &st) != 0, 0)
-#endif
- || __builtin_expect ((size = (size_t) st.st_size) != st.st_size, 0)
- || __builtin_expect (size < sizeof (struct mo_file_header), 0))
- {
- /* Something went wrong. */
- close (fd);
- return;
- }
-
-#ifdef HAVE_MMAP
- /* Now we are ready to load the file. If mmap() is available we try
- this first. If not available or it failed we try to load it. */
- data = (struct mo_file_header *) mmap (NULL, size, PROT_READ,
- MAP_PRIVATE, fd, 0);
-
- if (__builtin_expect (data != (struct mo_file_header *) -1, 1))
- {
- /* mmap() call was successful. */
- close (fd);
- use_mmap = 1;
- }
-#endif
-
- /* If the data is not yet available (i.e. mmap'ed) we try to load
- it manually. */
- if (data == (struct mo_file_header *) -1)
- {
- size_t to_read;
- char *read_ptr;
-
- data = (struct mo_file_header *) malloc (size);
- if (data == NULL)
- return;
-
- to_read = size;
- read_ptr = (char *) data;
- do
- {
- long int nb = (long int) read (fd, read_ptr, to_read);
- if (nb <= 0)
- {
-#ifdef EINTR
- if (nb == -1 && errno == EINTR)
- continue;
-#endif
- close (fd);
- return;
- }
- read_ptr += nb;
- to_read -= nb;
- }
- while (to_read > 0);
-
- close (fd);
- }
-
- /* Using the magic number we can test whether it really is a message
- catalog file. */
- if (__builtin_expect (data->magic != _MAGIC && data->magic != _MAGIC_SWAPPED,
- 0))
- {
- /* The magic number is wrong: not a message catalog file. */
-#ifdef HAVE_MMAP
- if (use_mmap)
- munmap ((caddr_t) data, size);
- else
-#endif
- free (data);
- return;
- }
-
- domain = (struct loaded_domain *) malloc (sizeof (struct loaded_domain));
- if (domain == NULL)
- return;
- domain_file->data = domain;
-
- domain->data = (char *) data;
- domain->use_mmap = use_mmap;
- domain->mmap_size = size;
- domain->must_swap = data->magic != _MAGIC;
- domain->malloced = NULL;
-
- /* Fill in the information about the available tables. */
- revision = W (domain->must_swap, data->revision);
- /* We support only the major revision 0. */
- switch (revision >> 16)
- {
- case 0:
- domain->nstrings = W (domain->must_swap, data->nstrings);
- domain->orig_tab = (const struct string_desc *)
- ((char *) data + W (domain->must_swap, data->orig_tab_offset));
- domain->trans_tab = (const struct string_desc *)
- ((char *) data + W (domain->must_swap, data->trans_tab_offset));
- domain->hash_size = W (domain->must_swap, data->hash_tab_size);
- domain->hash_tab =
- (domain->hash_size > 2
- ? (const nls_uint32 *)
- ((char *) data + W (domain->must_swap, data->hash_tab_offset))
- : NULL);
- domain->must_swap_hash_tab = domain->must_swap;
-
- /* Now dispatch on the minor revision. */
- switch (revision & 0xffff)
- {
- case 0:
- domain->n_sysdep_strings = 0;
- domain->orig_sysdep_tab = NULL;
- domain->trans_sysdep_tab = NULL;
- break;
- case 1:
- default:
- {
- nls_uint32 n_sysdep_strings;
-
- if (domain->hash_tab == NULL)
- /* This is invalid. These minor revisions need a hash table. */
- goto invalid;
-
- n_sysdep_strings =
- W (domain->must_swap, data->n_sysdep_strings);
- if (n_sysdep_strings > 0)
- {
- nls_uint32 n_sysdep_segments;
- const struct sysdep_segment *sysdep_segments;
- const char **sysdep_segment_values;
- const nls_uint32 *orig_sysdep_tab;
- const nls_uint32 *trans_sysdep_tab;
- size_t memneed;
- char *mem;
- struct sysdep_string_desc *inmem_orig_sysdep_tab;
- struct sysdep_string_desc *inmem_trans_sysdep_tab;
- nls_uint32 *inmem_hash_tab;
- unsigned int i;
-
- /* Get the values of the system dependent segments. */
- n_sysdep_segments =
- W (domain->must_swap, data->n_sysdep_segments);
- sysdep_segments = (const struct sysdep_segment *)
- ((char *) data
- + W (domain->must_swap, data->sysdep_segments_offset));
- sysdep_segment_values =
- alloca (n_sysdep_segments * sizeof (const char *));
- for (i = 0; i < n_sysdep_segments; i++)
- {
- const char *name =
- (char *) data
- + W (domain->must_swap, sysdep_segments[i].offset);
- nls_uint32 namelen =
- W (domain->must_swap, sysdep_segments[i].length);
-
- if (!(namelen > 0 && name[namelen - 1] == '\0'))
- {
- freea (sysdep_segment_values);
- goto invalid;
- }
-
- sysdep_segment_values[i] = get_sysdep_segment_value (name);
- }
-
- orig_sysdep_tab = (const nls_uint32 *)
- ((char *) data
- + W (domain->must_swap, data->orig_sysdep_tab_offset));
- trans_sysdep_tab = (const nls_uint32 *)
- ((char *) data
- + W (domain->must_swap, data->trans_sysdep_tab_offset));
-
- /* Compute the amount of additional memory needed for the
- system dependent strings and the augmented hash table. */
- memneed = 2 * n_sysdep_strings
- * sizeof (struct sysdep_string_desc)
- + domain->hash_size * sizeof (nls_uint32);
- for (i = 0; i < 2 * n_sysdep_strings; i++)
- {
- const struct sysdep_string *sysdep_string =
- (const struct sysdep_string *)
- ((char *) data
- + W (domain->must_swap,
- i < n_sysdep_strings
- ? orig_sysdep_tab[i]
- : trans_sysdep_tab[i - n_sysdep_strings]));
- size_t need = 0;
- const struct segment_pair *p = sysdep_string->segments;
-
- if (W (domain->must_swap, p->sysdepref) != SEGMENTS_END)
- for (p = sysdep_string->segments;; p++)
- {
- nls_uint32 sysdepref;
-
- need += W (domain->must_swap, p->segsize);
-
- sysdepref = W (domain->must_swap, p->sysdepref);
- if (sysdepref == SEGMENTS_END)
- break;
-
- if (sysdepref >= n_sysdep_segments)
- {
- /* Invalid. */
- freea (sysdep_segment_values);
- goto invalid;
- }
-
- need += strlen (sysdep_segment_values[sysdepref]);
- }
-
- memneed += need;
- }
-
- /* Allocate additional memory. */
- mem = (char *) malloc (memneed);
- if (mem == NULL)
- goto invalid;
-
- domain->malloced = mem;
- inmem_orig_sysdep_tab = (struct sysdep_string_desc *) mem;
- mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
- inmem_trans_sysdep_tab = (struct sysdep_string_desc *) mem;
- mem += n_sysdep_strings * sizeof (struct sysdep_string_desc);
- inmem_hash_tab = (nls_uint32 *) mem;
- mem += domain->hash_size * sizeof (nls_uint32);
-
- /* Compute the system dependent strings. */
- for (i = 0; i < 2 * n_sysdep_strings; i++)
- {
- const struct sysdep_string *sysdep_string =
- (const struct sysdep_string *)
- ((char *) data
- + W (domain->must_swap,
- i < n_sysdep_strings
- ? orig_sysdep_tab[i]
- : trans_sysdep_tab[i - n_sysdep_strings]));
- const char *static_segments =
- (char *) data
- + W (domain->must_swap, sysdep_string->offset);
- const struct segment_pair *p = sysdep_string->segments;
-
- /* Concatenate the segments, and fill
- inmem_orig_sysdep_tab[i] (for i < n_sysdep_strings) and
- inmem_trans_sysdep_tab[i-n_sysdep_strings] (for
- i >= n_sysdep_strings). */
-
- if (W (domain->must_swap, p->sysdepref) == SEGMENTS_END)
- {
- /* Only one static segment. */
- inmem_orig_sysdep_tab[i].length =
- W (domain->must_swap, p->segsize);
- inmem_orig_sysdep_tab[i].pointer = static_segments;
- }
- else
- {
- inmem_orig_sysdep_tab[i].pointer = mem;
-
- for (p = sysdep_string->segments;; p++)
- {
- nls_uint32 segsize =
- W (domain->must_swap, p->segsize);
- nls_uint32 sysdepref =
- W (domain->must_swap, p->sysdepref);
- size_t n;
-
- if (segsize > 0)
- {
- memcpy (mem, static_segments, segsize);
- mem += segsize;
- static_segments += segsize;
- }
-
- if (sysdepref == SEGMENTS_END)
- break;
-
- n = strlen (sysdep_segment_values[sysdepref]);
- memcpy (mem, sysdep_segment_values[sysdepref], n);
- mem += n;
- }
-
- inmem_orig_sysdep_tab[i].length =
- mem - inmem_orig_sysdep_tab[i].pointer;
- }
- }
-
- /* Compute the augmented hash table. */
- for (i = 0; i < domain->hash_size; i++)
- inmem_hash_tab[i] =
- W (domain->must_swap_hash_tab, domain->hash_tab[i]);
- for (i = 0; i < n_sysdep_strings; i++)
- {
- const char *msgid = inmem_orig_sysdep_tab[i].pointer;
- nls_uint32 hash_val = hash_string (msgid);
- nls_uint32 idx = hash_val % domain->hash_size;
- nls_uint32 incr = 1 + (hash_val % (domain->hash_size - 2));
-
- for (;;)
- {
- if (inmem_hash_tab[idx] == 0)
- {
- /* Hash table entry is empty. Use it. */
- inmem_hash_tab[idx] = 1 + domain->nstrings + i;
- break;
- }
-
- if (idx >= domain->hash_size - incr)
- idx -= domain->hash_size - incr;
- else
- idx += incr;
- }
- }
-
- freea (sysdep_segment_values);
-
- domain->n_sysdep_strings = n_sysdep_strings;
- domain->orig_sysdep_tab = inmem_orig_sysdep_tab;
- domain->trans_sysdep_tab = inmem_trans_sysdep_tab;
-
- domain->hash_tab = inmem_hash_tab;
- domain->must_swap_hash_tab = 0;
- }
- else
- {
- domain->n_sysdep_strings = 0;
- domain->orig_sysdep_tab = NULL;
- domain->trans_sysdep_tab = NULL;
- }
- }
- break;
- }
- break;
- default:
- /* This is an invalid revision. */
- invalid:
- /* This is an invalid .mo file. */
- if (domain->malloced)
- free (domain->malloced);
-#ifdef HAVE_MMAP
- if (use_mmap)
- munmap ((caddr_t) data, size);
- else
-#endif
- free (data);
- free (domain);
- domain_file->data = NULL;
- return;
- }
-
- /* Now initialize the character set converter from the character set
- the file is encoded with (found in the header entry) to the domain's
- specified character set or the locale's character set. */
- nullentry = _nl_init_domain_conv (domain_file, domain, domainbinding);
-
- /* Also look for a plural specification. */
- EXTRACT_PLURAL_EXPRESSION (nullentry, &domain->plural, &domain->nplurals);
-}
-
-
-#ifdef _LIBC
-void
-internal_function
-_nl_unload_domain (domain)
- struct loaded_domain *domain;
-{
- if (domain->plural != &__gettext_germanic_plural)
- __gettext_free_exp (domain->plural);
-
- _nl_free_domain_conv (domain);
-
- if (domain->malloced)
- free (domain->malloced);
-
-# ifdef _POSIX_MAPPED_FILES
- if (domain->use_mmap)
- munmap ((caddr_t) domain->data, domain->mmap_size);
- else
-# endif /* _POSIX_MAPPED_FILES */
- free ((void *) domain->data);
-
- free (domain);
-}
-#endif
diff --git a/src/audacious/intl/localcharset.c b/src/audacious/intl/localcharset.c
deleted file mode 100644
index 9b91d62..0000000
--- a/src/audacious/intl/localcharset.c
+++ /dev/null
@@ -1,398 +0,0 @@
-/* Determine a canonical name for the current locale's character encoding.
-
- Copyright (C) 2000-2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Written by Bruno Haible <bruno@clisp.org>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-/* Specification. */
-#include "localcharset.h"
-
-#if HAVE_STDDEF_H
-# include <stddef.h>
-#endif
-
-#include <stdio.h>
-#if HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
-#if HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-
-#if defined _WIN32 || defined __WIN32__
-# undef WIN32 /* avoid warning on mingw32 */
-# define WIN32
-#endif
-
-#if defined __EMX__
-/* Assume EMX program runs on OS/2, even if compiled under DOS. */
-# define OS2
-#endif
-
-#if !defined WIN32
-# if HAVE_LANGINFO_CODESET
-# include <langinfo.h>
-# else
-# if HAVE_SETLOCALE
-# include <locale.h>
-# endif
-# endif
-#elif defined WIN32
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-#endif
-#if defined OS2
-# define INCL_DOS
-# include <os2.h>
-#endif
-
-#if ENABLE_RELOCATABLE
-# include "relocatable.h"
-#else
-# define relocate(pathname) (pathname)
-#endif
-
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS */
-# define ISSLASH(C) ((C) == '/' || (C) == '\\')
-#endif
-
-#ifndef DIRECTORY_SEPARATOR
-# define DIRECTORY_SEPARATOR '/'
-#endif
-
-#ifndef ISSLASH
-# define ISSLASH(C) ((C) == DIRECTORY_SEPARATOR)
-#endif
-
-#ifdef HAVE_GETC_UNLOCKED
-# undef getc
-# define getc getc_unlocked
-#endif
-
-/* The following static variable is declared 'volatile' to avoid a
- possible multithread problem in the function get_charset_aliases. If we
- are running in a threaded environment, and if two threads initialize
- 'charset_aliases' simultaneously, both will produce the same value,
- and everything will be ok if the two assignments to 'charset_aliases'
- are atomic. But I don't know what will happen if the two assignments mix. */
-#if __STDC__ != 1
-# define volatile /* empty */
-#endif
-/* Pointer to the contents of the charset.alias file, if it has already been
- read, else NULL. Its format is:
- ALIAS_1 '\0' CANONICAL_1 '\0' ... ALIAS_n '\0' CANONICAL_n '\0' '\0' */
-static const char * volatile charset_aliases;
-
-/* Return a pointer to the contents of the charset.alias file. */
-static const char *
-get_charset_aliases ()
-{
- const char *cp;
-
- cp = charset_aliases;
- if (cp == NULL)
- {
-#if !(defined VMS || defined WIN32)
- FILE *fp;
- const char *dir = relocate (LIBDIR);
- const char *base = "charset.alias";
- char *file_name;
-
- /* Concatenate dir and base into freshly allocated file_name. */
- {
- size_t dir_len = strlen (dir);
- size_t base_len = strlen (base);
- int add_slash = (dir_len > 0 && !ISSLASH (dir[dir_len - 1]));
- file_name = (char *) malloc (dir_len + add_slash + base_len + 1);
- if (file_name != NULL)
- {
- memcpy (file_name, dir, dir_len);
- if (add_slash)
- file_name[dir_len] = DIRECTORY_SEPARATOR;
- memcpy (file_name + dir_len + add_slash, base, base_len + 1);
- }
- }
-
- if (file_name == NULL || (fp = fopen (file_name, "r")) == NULL)
- /* Out of memory or file not found, treat it as empty. */
- cp = "";
- else
- {
- /* Parse the file's contents. */
- int c;
- char buf1[50+1];
- char buf2[50+1];
- char *res_ptr = NULL;
- size_t res_size = 0;
- size_t l1, l2;
-
- for (;;)
- {
- c = getc (fp);
- if (c == EOF)
- break;
- if (c == '\n' || c == ' ' || c == '\t')
- continue;
- if (c == '#')
- {
- /* Skip comment, to end of line. */
- do
- c = getc (fp);
- while (!(c == EOF || c == '\n'));
- if (c == EOF)
- break;
- continue;
- }
- ungetc (c, fp);
- if (fscanf (fp, "%50s %50s", buf1, buf2) < 2)
- break;
- l1 = strlen (buf1);
- l2 = strlen (buf2);
- if (res_size == 0)
- {
- res_size = l1 + 1 + l2 + 1;
- res_ptr = (char *) malloc (res_size + 1);
- }
- else
- {
- res_size += l1 + 1 + l2 + 1;
- res_ptr = (char *) realloc (res_ptr, res_size + 1);
- }
- if (res_ptr == NULL)
- {
- /* Out of memory. */
- res_size = 0;
- break;
- }
- g_strlcpy (res_ptr + res_size - (l2 + 1) - (l1 + 1), buf1, res_size - (l2 + 1));
- g_strlcpy (res_ptr + res_size - (l2 + 1), buf2, res_size - (l1 + 1));
- }
- fclose (fp);
- if (res_size == 0)
- cp = "";
- else
- {
- *(res_ptr + res_size) = '\0';
- cp = res_ptr;
- }
- }
-
- if (file_name != NULL)
- free (file_name);
-
-#else
-
-# if defined VMS
- /* To avoid the troubles of an extra file charset.alias_vms in the
- sources of many GNU packages, simply inline the aliases here. */
- /* The list of encodings is taken from the OpenVMS 7.3-1 documentation
- "Compaq C Run-Time Library Reference Manual for OpenVMS systems"
- section 10.7 "Handling Different Character Sets". */
- cp = "ISO8859-1" "\0" "ISO-8859-1" "\0"
- "ISO8859-2" "\0" "ISO-8859-2" "\0"
- "ISO8859-5" "\0" "ISO-8859-5" "\0"
- "ISO8859-7" "\0" "ISO-8859-7" "\0"
- "ISO8859-8" "\0" "ISO-8859-8" "\0"
- "ISO8859-9" "\0" "ISO-8859-9" "\0"
- /* Japanese */
- "eucJP" "\0" "EUC-JP" "\0"
- "SJIS" "\0" "SHIFT_JIS" "\0"
- "DECKANJI" "\0" "DEC-KANJI" "\0"
- "SDECKANJI" "\0" "EUC-JP" "\0"
- /* Chinese */
- "eucTW" "\0" "EUC-TW" "\0"
- "DECHANYU" "\0" "DEC-HANYU" "\0"
- "DECHANZI" "\0" "GB2312" "\0"
- /* Korean */
- "DECKOREAN" "\0" "EUC-KR" "\0";
-# endif
-
-# if defined WIN32
- /* To avoid the troubles of installing a separate file in the same
- directory as the DLL and of retrieving the DLL's directory at
- runtime, simply inline the aliases here. */
-
- cp = "CP936" "\0" "GBK" "\0"
- "CP1361" "\0" "JOHAB" "\0"
- "CP20127" "\0" "ASCII" "\0"
- "CP20866" "\0" "KOI8-R" "\0"
- "CP21866" "\0" "KOI8-RU" "\0"
- "CP28591" "\0" "ISO-8859-1" "\0"
- "CP28592" "\0" "ISO-8859-2" "\0"
- "CP28593" "\0" "ISO-8859-3" "\0"
- "CP28594" "\0" "ISO-8859-4" "\0"
- "CP28595" "\0" "ISO-8859-5" "\0"
- "CP28596" "\0" "ISO-8859-6" "\0"
- "CP28597" "\0" "ISO-8859-7" "\0"
- "CP28598" "\0" "ISO-8859-8" "\0"
- "CP28599" "\0" "ISO-8859-9" "\0"
- "CP28605" "\0" "ISO-8859-15" "\0";
-# endif
-#endif
-
- charset_aliases = cp;
- }
-
- return cp;
-}
-
-/* Determine the current locale's character encoding, and canonicalize it
- into one of the canonical names listed in config.charset.
- The result must not be freed; it is statically allocated.
- If the canonical name cannot be determined, the result is a non-canonical
- name. */
-
-#ifdef STATIC
-STATIC
-#endif
-const char *
-locale_charset ()
-{
- const char *codeset;
- const char *aliases;
-
-#if !(defined WIN32 || defined OS2)
-
-# if HAVE_LANGINFO_CODESET
-
- /* Most systems support nl_langinfo (CODESET) nowadays. */
- codeset = nl_langinfo (CODESET);
-
-# else
-
- /* On old systems which lack it, use setlocale or getenv. */
- const char *locale = NULL;
-
- /* But most old systems don't have a complete set of locales. Some
- (like SunOS 4 or DJGPP) have only the C locale. Therefore we don't
- use setlocale here; it would return "C" when it doesn't support the
- locale name the user has set. */
-# if HAVE_SETLOCALE && 0
- locale = setlocale (LC_CTYPE, NULL);
-# endif
- if (locale == NULL || locale[0] == '\0')
- {
- locale = getenv ("LC_ALL");
- if (locale == NULL || locale[0] == '\0')
- {
- locale = getenv ("LC_CTYPE");
- if (locale == NULL || locale[0] == '\0')
- locale = getenv ("LANG");
- }
- }
-
- /* On some old systems, one used to set locale = "iso8859_1". On others,
- you set it to "language_COUNTRY.charset". In any case, we resolve it
- through the charset.alias file. */
- codeset = locale;
-
-# endif
-
-#elif defined WIN32
-
- static char buf[2 + 10 + 1];
-
- /* Woe32 has a function returning the locale's codepage as a number. */
- sprintf (buf, "CP%u", GetACP ());
- codeset = buf;
-
-#elif defined OS2
-
- const char *locale;
- static char buf[2 + 10 + 1];
- ULONG cp[3];
- ULONG cplen;
-
- /* Allow user to override the codeset, as set in the operating system,
- with standard language environment variables. */
- locale = getenv ("LC_ALL");
- if (locale == NULL || locale[0] == '\0')
- {
- locale = getenv ("LC_CTYPE");
- if (locale == NULL || locale[0] == '\0')
- locale = getenv ("LANG");
- }
- if (locale != NULL && locale[0] != '\0')
- {
- /* If the locale name contains an encoding after the dot, return it. */
- const char *dot = strchr (locale, '.');
-
- if (dot != NULL)
- {
- const char *modifier;
-
- dot++;
- /* Look for the possible @... trailer and remove it, if any. */
- modifier = strchr (dot, '@');
- if (modifier == NULL)
- return dot;
- if (modifier - dot < sizeof (buf))
- {
- memcpy (buf, dot, modifier - dot);
- buf [modifier - dot] = '\0';
- return buf;
- }
- }
-
- /* Resolve through the charset.alias file. */
- codeset = locale;
- }
- else
- {
- /* OS/2 has a function returning the locale's codepage as a number. */
- if (DosQueryCp (sizeof (cp), cp, &cplen))
- codeset = "";
- else
- {
- sprintf (buf, "CP%u", cp[0]);
- codeset = buf;
- }
- }
-
-#endif
-
- if (codeset == NULL)
- /* The canonical name cannot be determined. */
- codeset = "";
-
- /* Resolve alias. */
- for (aliases = get_charset_aliases ();
- *aliases != '\0';
- aliases += strlen (aliases) + 1, aliases += strlen (aliases) + 1)
- if (strcmp (codeset, aliases) == 0
- || (aliases[0] == '*' && aliases[1] == '\0'))
- {
- codeset = aliases + strlen (aliases) + 1;
- break;
- }
-
- /* Don't return an empty string. GNU libc and GNU libiconv interpret
- the empty string as denoting "the locale's character encoding",
- thus GNU libiconv would call this function a second time. */
- if (codeset[0] == '\0')
- codeset = "ASCII";
-
- return codeset;
-}
diff --git a/src/audacious/intl/localcharset.h b/src/audacious/intl/localcharset.h
deleted file mode 100644
index 129e4a4..0000000
--- a/src/audacious/intl/localcharset.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Determine a canonical name for the current locale's character encoding.
- Copyright (C) 2000-2003 Free Software Foundation, Inc.
- This file is part of the GNU CHARSET Library.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _LOCALCHARSET_H
-#define _LOCALCHARSET_H
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/* Determine the current locale's character encoding, and canonicalize it
- into one of the canonical names listed in config.charset.
- The result must not be freed; it is statically allocated.
- If the canonical name cannot be determined, the result is a non-canonical
- name. */
-extern const char * locale_charset (void);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* _LOCALCHARSET_H */
diff --git a/src/audacious/intl/locale.alias b/src/audacious/intl/locale.alias
deleted file mode 100644
index 213357b..0000000
--- a/src/audacious/intl/locale.alias
+++ /dev/null
@@ -1,78 +0,0 @@
-# Locale name alias data base.
-# Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-# The format of this file is the same as for the corresponding file of
-# the X Window System, which normally can be found in
-# /usr/lib/X11/locale/locale.alias
-# A single line contains two fields: an alias and a substitution value.
-# All entries are case independent.
-
-# Note: This file is far from being complete. If you have a value for
-# your own site which you think might be useful for others too, share
-# it with the rest of us. Send it using the `glibcbug' script to
-# bugs@gnu.org.
-
-# Packages using this file:
-
-bokmal no_NO.ISO-8859-1
-bokmål no_NO.ISO-8859-1
-catalan ca_ES.ISO-8859-1
-croatian hr_HR.ISO-8859-2
-czech cs_CZ.ISO-8859-2
-danish da_DK.ISO-8859-1
-dansk da_DK.ISO-8859-1
-deutsch de_DE.ISO-8859-1
-dutch nl_NL.ISO-8859-1
-eesti et_EE.ISO-8859-1
-estonian et_EE.ISO-8859-1
-finnish fi_FI.ISO-8859-1
-français fr_FR.ISO-8859-1
-french fr_FR.ISO-8859-1
-galego gl_ES.ISO-8859-1
-galician gl_ES.ISO-8859-1
-german de_DE.ISO-8859-1
-greek el_GR.ISO-8859-7
-hebrew he_IL.ISO-8859-8
-hrvatski hr_HR.ISO-8859-2
-hungarian hu_HU.ISO-8859-2
-icelandic is_IS.ISO-8859-1
-italian it_IT.ISO-8859-1
-japanese ja_JP.eucJP
-japanese.euc ja_JP.eucJP
-ja_JP ja_JP.eucJP
-ja_JP.ujis ja_JP.eucJP
-japanese.sjis ja_JP.SJIS
-korean ko_KR.eucKR
-korean.euc ko_KR.eucKR
-ko_KR ko_KR.eucKR
-lithuanian lt_LT.ISO-8859-13
-nb_NO no_NO.ISO-8859-1
-nb_NO.ISO-8859-1 no_NO.ISO-8859-1
-norwegian no_NO.ISO-8859-1
-nynorsk nn_NO.ISO-8859-1
-polish pl_PL.ISO-8859-2
-portuguese pt_PT.ISO-8859-1
-romanian ro_RO.ISO-8859-2
-russian ru_RU.ISO-8859-5
-slovak sk_SK.ISO-8859-2
-slovene sl_SI.ISO-8859-2
-slovenian sl_SI.ISO-8859-2
-spanish es_ES.ISO-8859-1
-swedish sv_SE.ISO-8859-1
-thai th_TH.TIS-620
-turkish tr_TR.ISO-8859-9
diff --git a/src/audacious/intl/localealias.c b/src/audacious/intl/localealias.c
deleted file mode 100644
index 3bc0f2e..0000000
--- a/src/audacious/intl/localealias.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/* Handle aliases for locale names.
- Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Tell glibc's <string.h> to provide a prototype for mempcpy().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#if defined _LIBC || defined HAVE___FSETLOCKING
-# include <stdio_ext.h>
-#endif
-#include <sys/types.h>
-
-#ifdef __GNUC__
-# undef alloca
-# define alloca __builtin_alloca
-# define HAVE_ALLOCA 1
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if defined HAVE_ALLOCA_H || defined _LIBC
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "gettextP.h"
-
-#if ENABLE_RELOCATABLE
-# include "relocatable.h"
-#else
-# define relocate(pathname) (pathname)
-#endif
-
-/* @@ end of prolog @@ */
-
-#ifdef _LIBC
-/* Rename the non ANSI C functions. This is required by the standard
- because some ANSI C functions will require linking with this object
- file and the name space must not be polluted. */
-# define strcasecmp __strcasecmp
-
-# ifndef mempcpy
-# define mempcpy __mempcpy
-# endif
-# define HAVE_MEMPCPY 1
-# define HAVE___FSETLOCKING 1
-
-/* We need locking here since we can be called from different places. */
-# include <bits/libc-lock.h>
-
-__libc_lock_define_initialized (static, lock);
-#endif
-
-#ifndef internal_function
-# define internal_function
-#endif
-
-/* Some optimizations for glibc. */
-#ifdef _LIBC
-# define FEOF(fp) feof_unlocked (fp)
-# define FGETS(buf, n, fp) fgets_unlocked (buf, n, fp)
-#else
-# define FEOF(fp) feof (fp)
-# define FGETS(buf, n, fp) fgets (buf, n, fp)
-#endif
-
-/* For those losing systems which don't have `alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
-#endif
-
-#if defined _LIBC_REENTRANT || defined HAVE_FGETS_UNLOCKED
-# undef fgets
-# define fgets(buf, len, s) fgets_unlocked (buf, len, s)
-#endif
-#if defined _LIBC_REENTRANT || defined HAVE_FEOF_UNLOCKED
-# undef feof
-# define feof(s) feof_unlocked (s)
-#endif
-
-
-struct alias_map
-{
- const char *alias;
- const char *value;
-};
-
-
-#ifndef _LIBC
-# define libc_freeres_ptr(decl) decl
-#endif
-
-libc_freeres_ptr (static char *string_space);
-static size_t string_space_act;
-static size_t string_space_max;
-libc_freeres_ptr (static struct alias_map *map);
-static size_t nmap;
-static size_t maxmap;
-
-
-/* Prototypes for local functions. */
-static size_t read_alias_file PARAMS ((const char *fname, int fname_len))
- internal_function;
-static int extend_alias_table PARAMS ((void));
-static int alias_compare PARAMS ((const struct alias_map *map1,
- const struct alias_map *map2));
-
-
-const char *
-_nl_expand_alias (name)
- const char *name;
-{
- static const char *locale_alias_path;
- struct alias_map *retval;
- const char *result = NULL;
- size_t added;
-
-#ifdef _LIBC
- __libc_lock_lock (lock);
-#endif
-
- if (locale_alias_path == NULL)
- locale_alias_path = LOCALE_ALIAS_PATH;
-
- do
- {
- struct alias_map item;
-
- item.alias = name;
-
- if (nmap > 0)
- retval = (struct alias_map *) bsearch (&item, map, nmap,
- sizeof (struct alias_map),
- (int (*) PARAMS ((const void *,
- const void *))
- ) alias_compare);
- else
- retval = NULL;
-
- /* We really found an alias. Return the value. */
- if (retval != NULL)
- {
- result = retval->value;
- break;
- }
-
- /* Perhaps we can find another alias file. */
- added = 0;
- while (added == 0 && locale_alias_path[0] != '\0')
- {
- const char *start;
-
- while (locale_alias_path[0] == PATH_SEPARATOR)
- ++locale_alias_path;
- start = locale_alias_path;
-
- while (locale_alias_path[0] != '\0'
- && locale_alias_path[0] != PATH_SEPARATOR)
- ++locale_alias_path;
-
- if (start < locale_alias_path)
- added = read_alias_file (start, locale_alias_path - start);
- }
- }
- while (added != 0);
-
-#ifdef _LIBC
- __libc_lock_unlock (lock);
-#endif
-
- return result;
-}
-
-
-static size_t
-internal_function
-read_alias_file (fname, fname_len)
- const char *fname;
- int fname_len;
-{
- FILE *fp;
- char *full_fname;
- size_t added;
- static const char aliasfile[] = "/locale.alias";
-
- full_fname = (char *) alloca (fname_len + sizeof aliasfile);
-#ifdef HAVE_MEMPCPY
- mempcpy (mempcpy (full_fname, fname, fname_len),
- aliasfile, sizeof aliasfile);
-#else
- memcpy (full_fname, fname, fname_len);
- memcpy (&full_fname[fname_len], aliasfile, sizeof aliasfile);
-#endif
-
- fp = fopen (relocate (full_fname), "r");
- freea (full_fname);
- if (fp == NULL)
- return 0;
-
-#ifdef HAVE___FSETLOCKING
- /* No threads present. */
- __fsetlocking (fp, FSETLOCKING_BYCALLER);
-#endif
-
- added = 0;
- while (!FEOF (fp))
- {
- /* It is a reasonable approach to use a fix buffer here because
- a) we are only interested in the first two fields
- b) these fields must be usable as file names and so must not
- be that long
- We avoid a multi-kilobyte buffer here since this would use up
- stack space which we might not have if the program ran out of
- memory. */
- char buf[400];
- char *alias;
- char *value;
- char *cp;
-
- if (FGETS (buf, sizeof buf, fp) == NULL)
- /* EOF reached. */
- break;
-
- cp = buf;
- /* Ignore leading white space. */
- while (isspace ((unsigned char) cp[0]))
- ++cp;
-
- /* A leading '#' signals a comment line. */
- if (cp[0] != '\0' && cp[0] != '#')
- {
- alias = cp++;
- while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
- ++cp;
- /* Terminate alias name. */
- if (cp[0] != '\0')
- *cp++ = '\0';
-
- /* Now look for the beginning of the value. */
- while (isspace ((unsigned char) cp[0]))
- ++cp;
-
- if (cp[0] != '\0')
- {
- size_t alias_len;
- size_t value_len;
-
- value = cp++;
- while (cp[0] != '\0' && !isspace ((unsigned char) cp[0]))
- ++cp;
- /* Terminate value. */
- if (cp[0] == '\n')
- {
- /* This has to be done to make the following test
- for the end of line possible. We are looking for
- the terminating '\n' which do not overwrite here. */
- *cp++ = '\0';
- *cp = '\n';
- }
- else if (cp[0] != '\0')
- *cp++ = '\0';
-
- if (nmap >= maxmap)
- if (__builtin_expect (extend_alias_table (), 0))
- return added;
-
- alias_len = strlen (alias) + 1;
- value_len = strlen (value) + 1;
-
- if (string_space_act + alias_len + value_len > string_space_max)
- {
- /* Increase size of memory pool. */
- size_t new_size = (string_space_max
- + (alias_len + value_len > 1024
- ? alias_len + value_len : 1024));
- char *new_pool = (char *) realloc (string_space, new_size);
- if (new_pool == NULL)
- return added;
-
- if (__builtin_expect (string_space != new_pool, 0))
- {
- size_t i;
-
- for (i = 0; i < nmap; i++)
- {
- map[i].alias += new_pool - string_space;
- map[i].value += new_pool - string_space;
- }
- }
-
- string_space = new_pool;
- string_space_max = new_size;
- }
-
- map[nmap].alias = memcpy (&string_space[string_space_act],
- alias, alias_len);
- string_space_act += alias_len;
-
- map[nmap].value = memcpy (&string_space[string_space_act],
- value, value_len);
- string_space_act += value_len;
-
- ++nmap;
- ++added;
- }
- }
-
- /* Possibly not the whole line fits into the buffer. Ignore
- the rest of the line. */
- while (strchr (buf, '\n') == NULL)
- if (FGETS (buf, sizeof buf, fp) == NULL)
- /* Make sure the inner loop will be left. The outer loop
- will exit at the `feof' test. */
- break;
- }
-
- /* Should we test for ferror()? I think we have to silently ignore
- errors. --drepper */
- fclose (fp);
-
- if (added > 0)
- qsort (map, nmap, sizeof (struct alias_map),
- (int (*) PARAMS ((const void *, const void *))) alias_compare);
-
- return added;
-}
-
-
-static int
-extend_alias_table ()
-{
- size_t new_size;
- struct alias_map *new_map;
-
- new_size = maxmap == 0 ? 100 : 2 * maxmap;
- new_map = (struct alias_map *) realloc (map, (new_size
- * sizeof (struct alias_map)));
- if (new_map == NULL)
- /* Simply don't extend: we don't have any more core. */
- return -1;
-
- map = new_map;
- maxmap = new_size;
- return 0;
-}
-
-
-static int
-alias_compare (map1, map2)
- const struct alias_map *map1;
- const struct alias_map *map2;
-{
-#if defined _LIBC || defined HAVE_STRCASECMP
- return strcasecmp (map1->alias, map2->alias);
-#else
- const unsigned char *p1 = (const unsigned char *) map1->alias;
- const unsigned char *p2 = (const unsigned char *) map2->alias;
- unsigned char c1, c2;
-
- if (p1 == p2)
- return 0;
-
- do
- {
- /* I know this seems to be odd but the tolower() function in
- some systems libc cannot handle nonalpha characters. */
- c1 = isupper (*p1) ? tolower (*p1) : *p1;
- c2 = isupper (*p2) ? tolower (*p2) : *p2;
- if (c1 == '\0')
- break;
- ++p1;
- ++p2;
- }
- while (c1 == c2);
-
- return c1 - c2;
-#endif
-}
diff --git a/src/audacious/intl/localename.c b/src/audacious/intl/localename.c
deleted file mode 100644
index f03e656..0000000
--- a/src/audacious/intl/localename.c
+++ /dev/null
@@ -1,772 +0,0 @@
-/* Determine the current selected locale.
- Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Written by Ulrich Drepper <drepper@gnu.org>, 1995. */
-/* Win32 code written by Tor Lillqvist <tml@iki.fi>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <locale.h>
-
-#if defined _WIN32 || defined __WIN32__
-# undef WIN32 /* avoid warning on mingw32 */
-# define WIN32
-#endif
-
-#ifdef WIN32
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-/* Mingw headers don't have latest language and sublanguage codes. */
-# ifndef LANG_AFRIKAANS
-# define LANG_AFRIKAANS 0x36
-# endif
-# ifndef LANG_ALBANIAN
-# define LANG_ALBANIAN 0x1c
-# endif
-# ifndef LANG_ARABIC
-# define LANG_ARABIC 0x01
-# endif
-# ifndef LANG_ARMENIAN
-# define LANG_ARMENIAN 0x2b
-# endif
-# ifndef LANG_ASSAMESE
-# define LANG_ASSAMESE 0x4d
-# endif
-# ifndef LANG_AZERI
-# define LANG_AZERI 0x2c
-# endif
-# ifndef LANG_BASQUE
-# define LANG_BASQUE 0x2d
-# endif
-# ifndef LANG_BELARUSIAN
-# define LANG_BELARUSIAN 0x23
-# endif
-# ifndef LANG_BENGALI
-# define LANG_BENGALI 0x45
-# endif
-# ifndef LANG_CATALAN
-# define LANG_CATALAN 0x03
-# endif
-# ifndef LANG_DIVEHI
-# define LANG_DIVEHI 0x65
-# endif
-# ifndef LANG_ESTONIAN
-# define LANG_ESTONIAN 0x25
-# endif
-# ifndef LANG_FAEROESE
-# define LANG_FAEROESE 0x38
-# endif
-# ifndef LANG_FARSI
-# define LANG_FARSI 0x29
-# endif
-# ifndef LANG_GALICIAN
-# define LANG_GALICIAN 0x56
-# endif
-# ifndef LANG_GEORGIAN
-# define LANG_GEORGIAN 0x37
-# endif
-# ifndef LANG_GUJARATI
-# define LANG_GUJARATI 0x47
-# endif
-# ifndef LANG_HEBREW
-# define LANG_HEBREW 0x0d
-# endif
-# ifndef LANG_HINDI
-# define LANG_HINDI 0x39
-# endif
-# ifndef LANG_INDONESIAN
-# define LANG_INDONESIAN 0x21
-# endif
-# ifndef LANG_KANNADA
-# define LANG_KANNADA 0x4b
-# endif
-# ifndef LANG_KASHMIRI
-# define LANG_KASHMIRI 0x60
-# endif
-# ifndef LANG_KAZAK
-# define LANG_KAZAK 0x3f
-# endif
-# ifndef LANG_KONKANI
-# define LANG_KONKANI 0x57
-# endif
-# ifndef LANG_KYRGYZ
-# define LANG_KYRGYZ 0x40
-# endif
-# ifndef LANG_LATVIAN
-# define LANG_LATVIAN 0x26
-# endif
-# ifndef LANG_LITHUANIAN
-# define LANG_LITHUANIAN 0x27
-# endif
-# ifndef LANG_MACEDONIAN
-# define LANG_MACEDONIAN 0x2f
-# endif
-# ifndef LANG_MALAY
-# define LANG_MALAY 0x3e
-# endif
-# ifndef LANG_MALAYALAM
-# define LANG_MALAYALAM 0x4c
-# endif
-# ifndef LANG_MANIPURI
-# define LANG_MANIPURI 0x58
-# endif
-# ifndef LANG_MARATHI
-# define LANG_MARATHI 0x4e
-# endif
-# ifndef LANG_MONGOLIAN
-# define LANG_MONGOLIAN 0x50
-# endif
-# ifndef LANG_NEPALI
-# define LANG_NEPALI 0x61
-# endif
-# ifndef LANG_ORIYA
-# define LANG_ORIYA 0x48
-# endif
-# ifndef LANG_PUNJABI
-# define LANG_PUNJABI 0x46
-# endif
-# ifndef LANG_SANSKRIT
-# define LANG_SANSKRIT 0x4f
-# endif
-# ifndef LANG_SERBIAN
-# define LANG_SERBIAN 0x1a
-# endif
-# ifndef LANG_SINDHI
-# define LANG_SINDHI 0x59
-# endif
-# ifndef LANG_SLOVAK
-# define LANG_SLOVAK 0x1b
-# endif
-# ifndef LANG_SORBIAN
-# define LANG_SORBIAN 0x2e
-# endif
-# ifndef LANG_SWAHILI
-# define LANG_SWAHILI 0x41
-# endif
-# ifndef LANG_SYRIAC
-# define LANG_SYRIAC 0x5a
-# endif
-# ifndef LANG_TAMIL
-# define LANG_TAMIL 0x49
-# endif
-# ifndef LANG_TATAR
-# define LANG_TATAR 0x44
-# endif
-# ifndef LANG_TELUGU
-# define LANG_TELUGU 0x4a
-# endif
-# ifndef LANG_THAI
-# define LANG_THAI 0x1e
-# endif
-# ifndef LANG_UKRAINIAN
-# define LANG_UKRAINIAN 0x22
-# endif
-# ifndef LANG_URDU
-# define LANG_URDU 0x20
-# endif
-# ifndef LANG_UZBEK
-# define LANG_UZBEK 0x43
-# endif
-# ifndef LANG_VIETNAMESE
-# define LANG_VIETNAMESE 0x2a
-# endif
-# ifndef SUBLANG_ARABIC_SAUDI_ARABIA
-# define SUBLANG_ARABIC_SAUDI_ARABIA 0x01
-# endif
-# ifndef SUBLANG_ARABIC_IRAQ
-# define SUBLANG_ARABIC_IRAQ 0x02
-# endif
-# ifndef SUBLANG_ARABIC_EGYPT
-# define SUBLANG_ARABIC_EGYPT 0x03
-# endif
-# ifndef SUBLANG_ARABIC_LIBYA
-# define SUBLANG_ARABIC_LIBYA 0x04
-# endif
-# ifndef SUBLANG_ARABIC_ALGERIA
-# define SUBLANG_ARABIC_ALGERIA 0x05
-# endif
-# ifndef SUBLANG_ARABIC_MOROCCO
-# define SUBLANG_ARABIC_MOROCCO 0x06
-# endif
-# ifndef SUBLANG_ARABIC_TUNISIA
-# define SUBLANG_ARABIC_TUNISIA 0x07
-# endif
-# ifndef SUBLANG_ARABIC_OMAN
-# define SUBLANG_ARABIC_OMAN 0x08
-# endif
-# ifndef SUBLANG_ARABIC_YEMEN
-# define SUBLANG_ARABIC_YEMEN 0x09
-# endif
-# ifndef SUBLANG_ARABIC_SYRIA
-# define SUBLANG_ARABIC_SYRIA 0x0a
-# endif
-# ifndef SUBLANG_ARABIC_JORDAN
-# define SUBLANG_ARABIC_JORDAN 0x0b
-# endif
-# ifndef SUBLANG_ARABIC_LEBANON
-# define SUBLANG_ARABIC_LEBANON 0x0c
-# endif
-# ifndef SUBLANG_ARABIC_KUWAIT
-# define SUBLANG_ARABIC_KUWAIT 0x0d
-# endif
-# ifndef SUBLANG_ARABIC_UAE
-# define SUBLANG_ARABIC_UAE 0x0e
-# endif
-# ifndef SUBLANG_ARABIC_BAHRAIN
-# define SUBLANG_ARABIC_BAHRAIN 0x0f
-# endif
-# ifndef SUBLANG_ARABIC_QATAR
-# define SUBLANG_ARABIC_QATAR 0x10
-# endif
-# ifndef SUBLANG_AZERI_LATIN
-# define SUBLANG_AZERI_LATIN 0x01
-# endif
-# ifndef SUBLANG_AZERI_CYRILLIC
-# define SUBLANG_AZERI_CYRILLIC 0x02
-# endif
-# ifndef SUBLANG_CHINESE_MACAU
-# define SUBLANG_CHINESE_MACAU 0x05
-# endif
-# ifndef SUBLANG_ENGLISH_SOUTH_AFRICA
-# define SUBLANG_ENGLISH_SOUTH_AFRICA 0x07
-# endif
-# ifndef SUBLANG_ENGLISH_JAMAICA
-# define SUBLANG_ENGLISH_JAMAICA 0x08
-# endif
-# ifndef SUBLANG_ENGLISH_CARIBBEAN
-# define SUBLANG_ENGLISH_CARIBBEAN 0x09
-# endif
-# ifndef SUBLANG_ENGLISH_BELIZE
-# define SUBLANG_ENGLISH_BELIZE 0x0a
-# endif
-# ifndef SUBLANG_ENGLISH_TRINIDAD
-# define SUBLANG_ENGLISH_TRINIDAD 0x0b
-# endif
-# ifndef SUBLANG_ENGLISH_ZIMBABWE
-# define SUBLANG_ENGLISH_ZIMBABWE 0x0c
-# endif
-# ifndef SUBLANG_ENGLISH_PHILIPPINES
-# define SUBLANG_ENGLISH_PHILIPPINES 0x0d
-# endif
-# ifndef SUBLANG_FRENCH_LUXEMBOURG
-# define SUBLANG_FRENCH_LUXEMBOURG 0x05
-# endif
-# ifndef SUBLANG_FRENCH_MONACO
-# define SUBLANG_FRENCH_MONACO 0x06
-# endif
-# ifndef SUBLANG_GERMAN_LUXEMBOURG
-# define SUBLANG_GERMAN_LUXEMBOURG 0x04
-# endif
-# ifndef SUBLANG_GERMAN_LIECHTENSTEIN
-# define SUBLANG_GERMAN_LIECHTENSTEIN 0x05
-# endif
-# ifndef SUBLANG_KASHMIRI_INDIA
-# define SUBLANG_KASHMIRI_INDIA 0x02
-# endif
-# ifndef SUBLANG_MALAY_MALAYSIA
-# define SUBLANG_MALAY_MALAYSIA 0x01
-# endif
-# ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
-# define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
-# endif
-# ifndef SUBLANG_NEPALI_INDIA
-# define SUBLANG_NEPALI_INDIA 0x02
-# endif
-# ifndef SUBLANG_SERBIAN_LATIN
-# define SUBLANG_SERBIAN_LATIN 0x02
-# endif
-# ifndef SUBLANG_SERBIAN_CYRILLIC
-# define SUBLANG_SERBIAN_CYRILLIC 0x03
-# endif
-# ifndef SUBLANG_SPANISH_GUATEMALA
-# define SUBLANG_SPANISH_GUATEMALA 0x04
-# endif
-# ifndef SUBLANG_SPANISH_COSTA_RICA
-# define SUBLANG_SPANISH_COSTA_RICA 0x05
-# endif
-# ifndef SUBLANG_SPANISH_PANAMA
-# define SUBLANG_SPANISH_PANAMA 0x06
-# endif
-# ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC
-# define SUBLANG_SPANISH_DOMINICAN_REPUBLIC 0x07
-# endif
-# ifndef SUBLANG_SPANISH_VENEZUELA
-# define SUBLANG_SPANISH_VENEZUELA 0x08
-# endif
-# ifndef SUBLANG_SPANISH_COLOMBIA
-# define SUBLANG_SPANISH_COLOMBIA 0x09
-# endif
-# ifndef SUBLANG_SPANISH_PERU
-# define SUBLANG_SPANISH_PERU 0x0a
-# endif
-# ifndef SUBLANG_SPANISH_ARGENTINA
-# define SUBLANG_SPANISH_ARGENTINA 0x0b
-# endif
-# ifndef SUBLANG_SPANISH_ECUADOR
-# define SUBLANG_SPANISH_ECUADOR 0x0c
-# endif
-# ifndef SUBLANG_SPANISH_CHILE
-# define SUBLANG_SPANISH_CHILE 0x0d
-# endif
-# ifndef SUBLANG_SPANISH_URUGUAY
-# define SUBLANG_SPANISH_URUGUAY 0x0e
-# endif
-# ifndef SUBLANG_SPANISH_PARAGUAY
-# define SUBLANG_SPANISH_PARAGUAY 0x0f
-# endif
-# ifndef SUBLANG_SPANISH_BOLIVIA
-# define SUBLANG_SPANISH_BOLIVIA 0x10
-# endif
-# ifndef SUBLANG_SPANISH_EL_SALVADOR
-# define SUBLANG_SPANISH_EL_SALVADOR 0x11
-# endif
-# ifndef SUBLANG_SPANISH_HONDURAS
-# define SUBLANG_SPANISH_HONDURAS 0x12
-# endif
-# ifndef SUBLANG_SPANISH_NICARAGUA
-# define SUBLANG_SPANISH_NICARAGUA 0x13
-# endif
-# ifndef SUBLANG_SPANISH_PUERTO_RICO
-# define SUBLANG_SPANISH_PUERTO_RICO 0x14
-# endif
-# ifndef SUBLANG_SWEDISH_FINLAND
-# define SUBLANG_SWEDISH_FINLAND 0x02
-# endif
-# ifndef SUBLANG_URDU_PAKISTAN
-# define SUBLANG_URDU_PAKISTAN 0x01
-# endif
-# ifndef SUBLANG_URDU_INDIA
-# define SUBLANG_URDU_INDIA 0x02
-# endif
-# ifndef SUBLANG_UZBEK_LATIN
-# define SUBLANG_UZBEK_LATIN 0x01
-# endif
-# ifndef SUBLANG_UZBEK_CYRILLIC
-# define SUBLANG_UZBEK_CYRILLIC 0x02
-# endif
-#endif
-
-/* XPG3 defines the result of 'setlocale (category, NULL)' as:
- "Directs 'setlocale()' to query 'category' and return the current
- setting of 'local'."
- However it does not specify the exact format. Neither do SUSV2 and
- ISO C 99. So we can use this feature only on selected systems (e.g.
- those using GNU C Library). */
-#if defined _LIBC || (defined __GNU_LIBRARY__ && __GNU_LIBRARY__ >= 2)
-# define HAVE_LOCALE_NULL
-#endif
-
-/* Determine the current locale's name, and canonicalize it into XPG syntax
- language[_territory[.codeset]][@modifier]
- The codeset part in the result is not reliable; the locale_charset()
- should be used for codeset information instead.
- The result must not be freed; it is statically allocated. */
-
-const char *
-_nl_locale_name (category, categoryname)
- int category;
- const char *categoryname;
-{
- const char *retval;
-
-#ifndef WIN32
-
- /* Use the POSIX methods of looking to 'LC_ALL', 'LC_xxx', and 'LANG'.
- On some systems this can be done by the 'setlocale' function itself. */
-# if defined HAVE_SETLOCALE && defined HAVE_LC_MESSAGES && defined HAVE_LOCALE_NULL
- retval = setlocale (category, NULL);
-# else
- /* Setting of LC_ALL overwrites all other. */
- retval = getenv ("LC_ALL");
- if (retval == NULL || retval[0] == '\0')
- {
- /* Next comes the name of the desired category. */
- retval = getenv (categoryname);
- if (retval == NULL || retval[0] == '\0')
- {
- /* Last possibility is the LANG environment variable. */
- retval = getenv ("LANG");
- if (retval == NULL || retval[0] == '\0')
- /* We use C as the default domain. POSIX says this is
- implementation defined. */
- retval = "C";
- }
- }
-# endif
-
- return retval;
-
-#else /* WIN32 */
-
- /* Return an XPG style locale name language[_territory][@modifier].
- Don't even bother determining the codeset; it's not useful in this
- context, because message catalogs are not specific to a single
- codeset. */
-
- LCID lcid;
- LANGID langid;
- int primary, sub;
-
- /* Let the user override the system settings through environment
- variables, as on POSIX systems. */
- retval = getenv ("LC_ALL");
- if (retval != NULL && retval[0] != '\0')
- return retval;
- retval = getenv (categoryname);
- if (retval != NULL && retval[0] != '\0')
- return retval;
- retval = getenv ("LANG");
- if (retval != NULL && retval[0] != '\0')
- return retval;
-
- /* Use native Win32 API locale ID. */
- lcid = GetThreadLocale ();
-
- /* Strip off the sorting rules, keep only the language part. */
- langid = LANGIDFROMLCID (lcid);
-
- /* Split into language and territory part. */
- primary = PRIMARYLANGID (langid);
- sub = SUBLANGID (langid);
-
- /* Dispatch on language.
- See also http://www.unicode.org/unicode/onlinedat/languages.html .
- For details about languages, see http://www.ethnologue.com/ . */
- switch (primary)
- {
- case LANG_AFRIKAANS: return "af_ZA";
- case LANG_ALBANIAN: return "sq_AL";
- case 0x5e: /* AMHARIC */ return "am_ET";
- case LANG_ARABIC:
- switch (sub)
- {
- case SUBLANG_ARABIC_SAUDI_ARABIA: return "ar_SA";
- case SUBLANG_ARABIC_IRAQ: return "ar_IQ";
- case SUBLANG_ARABIC_EGYPT: return "ar_EG";
- case SUBLANG_ARABIC_LIBYA: return "ar_LY";
- case SUBLANG_ARABIC_ALGERIA: return "ar_DZ";
- case SUBLANG_ARABIC_MOROCCO: return "ar_MA";
- case SUBLANG_ARABIC_TUNISIA: return "ar_TN";
- case SUBLANG_ARABIC_OMAN: return "ar_OM";
- case SUBLANG_ARABIC_YEMEN: return "ar_YE";
- case SUBLANG_ARABIC_SYRIA: return "ar_SY";
- case SUBLANG_ARABIC_JORDAN: return "ar_JO";
- case SUBLANG_ARABIC_LEBANON: return "ar_LB";
- case SUBLANG_ARABIC_KUWAIT: return "ar_KW";
- case SUBLANG_ARABIC_UAE: return "ar_AE";
- case SUBLANG_ARABIC_BAHRAIN: return "ar_BH";
- case SUBLANG_ARABIC_QATAR: return "ar_QA";
- }
- return "ar";
- case LANG_ARMENIAN: return "hy_AM";
- case LANG_ASSAMESE: return "as_IN";
- case LANG_AZERI:
- switch (sub)
- {
- /* FIXME: Adjust this when Azerbaijani locales appear on Unix. */
- case SUBLANG_AZERI_LATIN: return "az_AZ@latin";
- case SUBLANG_AZERI_CYRILLIC: return "az_AZ@cyrillic";
- }
- return "az";
- case LANG_BASQUE:
- return "eu"; /* Ambiguous: could be "eu_ES" or "eu_FR". */
- case LANG_BELARUSIAN: return "be_BY";
- case LANG_BENGALI: return "bn_IN";
- case LANG_BULGARIAN: return "bg_BG";
- case 0x55: /* BURMESE */ return "my_MM";
- case 0x53: /* CAMBODIAN */ return "km_KH";
- case LANG_CATALAN: return "ca_ES";
- case 0x5c: /* CHEROKEE */ return "chr_US";
- case LANG_CHINESE:
- switch (sub)
- {
- case SUBLANG_CHINESE_TRADITIONAL: return "zh_TW";
- case SUBLANG_CHINESE_SIMPLIFIED: return "zh_CN";
- case SUBLANG_CHINESE_HONGKONG: return "zh_HK";
- case SUBLANG_CHINESE_SINGAPORE: return "zh_SG";
- case SUBLANG_CHINESE_MACAU: return "zh_MO";
- }
- return "zh";
- case LANG_CROATIAN: /* LANG_CROATIAN == LANG_SERBIAN
- * What used to be called Serbo-Croatian
- * should really now be two separate
- * languages because of political reasons.
- * (Says tml, who knows nothing about Serbian
- * or Croatian.)
- * (I can feel those flames coming already.)
- */
- switch (sub)
- {
- case SUBLANG_DEFAULT: return "hr_HR";
- case SUBLANG_SERBIAN_LATIN: return "sr_YU";
- case SUBLANG_SERBIAN_CYRILLIC: return "sr_YU@cyrillic";
- }
- return "hr";
- case LANG_CZECH: return "cs_CZ";
- case LANG_DANISH: return "da_DK";
- case LANG_DIVEHI: return "div_MV";
- case LANG_DUTCH:
- switch (sub)
- {
- case SUBLANG_DUTCH: return "nl_NL";
- case SUBLANG_DUTCH_BELGIAN: /* FLEMISH, VLAAMS */ return "nl_BE";
- }
- return "nl";
- case 0x66: /* EDO */ return "bin_NG";
- case LANG_ENGLISH:
- switch (sub)
- {
- /* SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. Heh. I thought
- * English was the language spoken in England.
- * Oh well.
- */
- case SUBLANG_ENGLISH_US: return "en_US";
- case SUBLANG_ENGLISH_UK: return "en_GB";
- case SUBLANG_ENGLISH_AUS: return "en_AU";
- case SUBLANG_ENGLISH_CAN: return "en_CA";
- case SUBLANG_ENGLISH_NZ: return "en_NZ";
- case SUBLANG_ENGLISH_EIRE: return "en_IE";
- case SUBLANG_ENGLISH_SOUTH_AFRICA: return "en_ZA";
- case SUBLANG_ENGLISH_JAMAICA: return "en_JM";
- case SUBLANG_ENGLISH_CARIBBEAN: return "en_GD"; /* Grenada? */
- case SUBLANG_ENGLISH_BELIZE: return "en_BZ";
- case SUBLANG_ENGLISH_TRINIDAD: return "en_TT";
- case SUBLANG_ENGLISH_ZIMBABWE: return "en_ZW";
- case SUBLANG_ENGLISH_PHILIPPINES: return "en_PH";
- }
- return "en";
- case LANG_ESTONIAN: return "et_EE";
- case LANG_FAEROESE: return "fo_FO";
- case LANG_FARSI: return "fa_IR";
- case LANG_FINNISH: return "fi_FI";
- case LANG_FRENCH:
- switch (sub)
- {
- case SUBLANG_FRENCH: return "fr_FR";
- case SUBLANG_FRENCH_BELGIAN: /* WALLOON */ return "fr_BE";
- case SUBLANG_FRENCH_CANADIAN: return "fr_CA";
- case SUBLANG_FRENCH_SWISS: return "fr_CH";
- case SUBLANG_FRENCH_LUXEMBOURG: return "fr_LU";
- case SUBLANG_FRENCH_MONACO: return "fr_MC";
- }
- return "fr";
- case 0x62: /* FRISIAN */ return "fy_NL";
- case 0x67: /* FULFULDE */ return "ful_NG";
- case 0x3c: /* GAELIC */
- switch (sub)
- {
- case 0x01: /* SCOTTISH */ return "gd_GB";
- case 0x02: /* IRISH */ return "ga_IE";
- }
- return "C";
- case LANG_GALICIAN: return "gl_ES";
- case LANG_GEORGIAN: return "ka_GE";
- case LANG_GERMAN:
- switch (sub)
- {
- case SUBLANG_GERMAN: return "de_DE";
- case SUBLANG_GERMAN_SWISS: return "de_CH";
- case SUBLANG_GERMAN_AUSTRIAN: return "de_AT";
- case SUBLANG_GERMAN_LUXEMBOURG: return "de_LU";
- case SUBLANG_GERMAN_LIECHTENSTEIN: return "de_LI";
- }
- return "de";
- case LANG_GREEK: return "el_GR";
- case 0x74: /* GUARANI */ return "gn_PY";
- case LANG_GUJARATI: return "gu_IN";
- case 0x68: /* HAUSA */ return "ha_NG";
- case 0x75: /* HAWAIIAN */
- /* FIXME: Do they mean Hawaiian ("haw_US", 1000 speakers)
- or Hawaii Creole English ("cpe_US", 600000 speakers)? */
- return "cpe_US";
- case LANG_HEBREW: return "he_IL";
- case LANG_HINDI: return "hi_IN";
- case LANG_HUNGARIAN: return "hu_HU";
- case 0x69: /* IBIBIO */ return "nic_NG";
- case LANG_ICELANDIC: return "is_IS";
- case 0x70: /* IGBO */ return "ibo_NG";
- case LANG_INDONESIAN: return "id_ID";
- case 0x5d: /* INUKTITUT */ return "iu_CA";
- case LANG_ITALIAN:
- switch (sub)
- {
- case SUBLANG_ITALIAN: return "it_IT";
- case SUBLANG_ITALIAN_SWISS: return "it_CH";
- }
- return "it";
- case LANG_JAPANESE: return "ja_JP";
- case LANG_KANNADA: return "kn_IN";
- case 0x71: /* KANURI */ return "kau_NG";
- case LANG_KASHMIRI:
- switch (sub)
- {
- case SUBLANG_DEFAULT: return "ks_PK";
- case SUBLANG_KASHMIRI_INDIA: return "ks_IN";
- }
- return "ks";
- case LANG_KAZAK: return "kk_KZ";
- case LANG_KONKANI:
- /* FIXME: Adjust this when such locales appear on Unix. */
- return "kok_IN";
- case LANG_KOREAN: return "ko_KR";
- case LANG_KYRGYZ: return "ky_KG";
- case 0x54: /* LAO */ return "lo_LA";
- case 0x76: /* LATIN */ return "la_VA";
- case LANG_LATVIAN: return "lv_LV";
- case LANG_LITHUANIAN: return "lt_LT";
- case LANG_MACEDONIAN: return "mk_MK";
- case LANG_MALAY:
- switch (sub)
- {
- case SUBLANG_MALAY_MALAYSIA: return "ms_MY";
- case SUBLANG_MALAY_BRUNEI_DARUSSALAM: return "ms_BN";
- }
- return "ms";
- case LANG_MALAYALAM: return "ml_IN";
- case 0x3a: /* MALTESE */ return "mt_MT";
- case LANG_MANIPURI:
- /* FIXME: Adjust this when such locales appear on Unix. */
- return "mni_IN";
- case LANG_MARATHI: return "mr_IN";
- case LANG_MONGOLIAN:
- return "mn"; /* Ambiguous: could be "mn_CN" or "mn_MN". */
- case LANG_NEPALI:
- switch (sub)
- {
- case SUBLANG_DEFAULT: return "ne_NP";
- case SUBLANG_NEPALI_INDIA: return "ne_IN";
- }
- return "ne";
- case LANG_NORWEGIAN:
- switch (sub)
- {
- case SUBLANG_NORWEGIAN_BOKMAL: return "no_NO";
- case SUBLANG_NORWEGIAN_NYNORSK: return "nn_NO";
- }
- return "no";
- case LANG_ORIYA: return "or_IN";
- case 0x72: /* OROMO */ return "om_ET";
- case 0x79: /* PAPIAMENTU */ return "pap_AN";
- case 0x63: /* PASHTO */
- return "ps"; /* Ambiguous: could be "ps_PK" or "ps_AF". */
- case LANG_POLISH: return "pl_PL";
- case LANG_PORTUGUESE:
- switch (sub)
- {
- case SUBLANG_PORTUGUESE: return "pt_PT";
- /* Hmm. SUBLANG_PORTUGUESE_BRAZILIAN == SUBLANG_DEFAULT.
- Same phenomenon as SUBLANG_ENGLISH_US == SUBLANG_DEFAULT. */
- case SUBLANG_PORTUGUESE_BRAZILIAN: return "pt_BR";
- }
- return "pt";
- case LANG_PUNJABI: return "pa_IN";
- case 0x17: /* RHAETO-ROMANCE */ return "rm_CH";
- case LANG_ROMANIAN: return "ro_RO";
- case LANG_RUSSIAN:
- return "ru"; /* Ambiguous: could be "ru_RU" or "ru_UA". */
- case 0x3b: /* SAMI */ return "se_NO";
- case LANG_SANSKRIT: return "sa_IN";
- case LANG_SINDHI: return "sd";
- case 0x5b: /* SINHALESE */ return "si_LK";
- case LANG_SLOVAK: return "sk_SK";
- case LANG_SLOVENIAN: return "sl_SI";
- case 0x77: /* SOMALI */ return "so_SO";
- case LANG_SORBIAN:
- /* FIXME: Adjust this when such locales appear on Unix. */
- return "wen_DE";
- case LANG_SPANISH:
- switch (sub)
- {
- case SUBLANG_SPANISH: return "es_ES";
- case SUBLANG_SPANISH_MEXICAN: return "es_MX";
- case SUBLANG_SPANISH_MODERN:
- return "es_ES@modern"; /* not seen on Unix */
- case SUBLANG_SPANISH_GUATEMALA: return "es_GT";
- case SUBLANG_SPANISH_COSTA_RICA: return "es_CR";
- case SUBLANG_SPANISH_PANAMA: return "es_PA";
- case SUBLANG_SPANISH_DOMINICAN_REPUBLIC: return "es_DO";
- case SUBLANG_SPANISH_VENEZUELA: return "es_VE";
- case SUBLANG_SPANISH_COLOMBIA: return "es_CO";
- case SUBLANG_SPANISH_PERU: return "es_PE";
- case SUBLANG_SPANISH_ARGENTINA: return "es_AR";
- case SUBLANG_SPANISH_ECUADOR: return "es_EC";
- case SUBLANG_SPANISH_CHILE: return "es_CL";
- case SUBLANG_SPANISH_URUGUAY: return "es_UY";
- case SUBLANG_SPANISH_PARAGUAY: return "es_PY";
- case SUBLANG_SPANISH_BOLIVIA: return "es_BO";
- case SUBLANG_SPANISH_EL_SALVADOR: return "es_SV";
- case SUBLANG_SPANISH_HONDURAS: return "es_HN";
- case SUBLANG_SPANISH_NICARAGUA: return "es_NI";
- case SUBLANG_SPANISH_PUERTO_RICO: return "es_PR";
- }
- return "es";
- case 0x30: /* SUTU */ return "bnt_TZ";
- case LANG_SWAHILI: return "sw_KE";
- case LANG_SWEDISH:
- switch (sub)
- {
- case SUBLANG_DEFAULT: return "sv_SE";
- case SUBLANG_SWEDISH_FINLAND: return "sv_FI";
- }
- return "sv";
- case LANG_SYRIAC: return "syr_TR"; /* An extinct language. */
- case 0x64: /* TAGALOG */ return "tl_PH";
- case 0x28: /* TAJIK */ return "tg_TJ";
- case 0x5f: /* TAMAZIGHT */ return "ber_MA";
- case LANG_TAMIL:
- return "ta"; /* Ambiguous: could be "ta_IN" or "ta_LK" or "ta_SG". */
- case LANG_TATAR: return "tt_RU";
- case LANG_TELUGU: return "te_IN";
- case LANG_THAI: return "th_TH";
- case 0x51: /* TIBETAN */ return "bo_CN";
- case 0x73: /* TIGRINYA */ return "ti_ET";
- case 0x31: /* TSONGA */ return "ts_ZA";
- case LANG_TURKISH: return "tr_TR";
- case 0x42: /* TURKMEN */ return "tk_TM";
- case LANG_UKRAINIAN: return "uk_UA";
- case LANG_URDU:
- switch (sub)
- {
- case SUBLANG_URDU_PAKISTAN: return "ur_PK";
- case SUBLANG_URDU_INDIA: return "ur_IN";
- }
- return "ur";
- case LANG_UZBEK:
- switch (sub)
- {
- /* FIXME: Adjust this when Uzbek locales appear on Unix. */
- case SUBLANG_UZBEK_LATIN: return "uz_UZ@latin";
- case SUBLANG_UZBEK_CYRILLIC: return "uz_UZ@cyrillic";
- }
- return "uz";
- case 0x33: /* VENDA */ return "ven_ZA";
- case LANG_VIETNAMESE: return "vi_VN";
- case 0x52: /* WELSH */ return "cy_GB";
- case 0x34: /* XHOSA */ return "xh_ZA";
- case 0x78: /* YI */ return "sit_CN";
- case 0x3d: /* YIDDISH */ return "yi_IL";
- case 0x6a: /* YORUBA */ return "yo_NG";
- case 0x35: /* ZULU */ return "zu_ZA";
- default: return "C";
- }
-
-#endif
-}
diff --git a/src/audacious/intl/log.c b/src/audacious/intl/log.c
deleted file mode 100644
index 9067401..0000000
--- a/src/audacious/intl/log.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/* Log file output.
- Copyright (C) 2003 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* Written by Bruno Haible <bruno@clisp.org>. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* Print an ASCII string with quotes and escape sequences where needed. */
-static void
-print_escaped (stream, str)
- FILE *stream;
- const char *str;
-{
- putc ('"', stream);
- for (; *str != '\0'; str++)
- if (*str == '\n')
- {
- fputs ("\\n\"", stream);
- if (str[1] == '\0')
- return;
- fputs ("\n\"", stream);
- }
- else
- {
- if (*str == '"' || *str == '\\')
- putc ('\\', stream);
- putc (*str, stream);
- }
- putc ('"', stream);
-}
-
-/* Add to the log file an entry denoting a failed translation. */
-void
-_nl_log_untranslated (logfilename, domainname, msgid1, msgid2, plural)
- const char *logfilename;
- const char *domainname;
- const char *msgid1;
- const char *msgid2;
- int plural;
-{
- static char *last_logfilename = NULL;
- static FILE *last_logfile = NULL;
- FILE *logfile;
-
- /* Can we reuse the last opened logfile? */
- if (last_logfilename == NULL || strcmp (logfilename, last_logfilename) != 0)
- {
- /* Close the last used logfile. */
- if (last_logfilename != NULL)
- {
- if (last_logfile != NULL)
- {
- fclose (last_logfile);
- last_logfile = NULL;
- }
- free (last_logfilename);
- last_logfilename = NULL;
- }
- /* Open the logfile. */
- last_logfilename = (char *) malloc (strlen (logfilename) + 1);
- if (last_logfilename == NULL)
- return;
- g_strlcpy (last_logfilename, logfilename, strlen(logfilename) + 1);
- last_logfile = fopen (logfilename, "a");
- if (last_logfile == NULL)
- return;
- }
- logfile = last_logfile;
-
- fprintf (logfile, "domain ");
- print_escaped (logfile, domainname);
- fprintf (logfile, "\nmsgid ");
- print_escaped (logfile, msgid1);
- if (plural)
- {
- fprintf (logfile, "\nmsgid_plural ");
- print_escaped (logfile, msgid2);
- fprintf (logfile, "\nmsgstr[0] \"\"\n");
- }
- else
- fprintf (logfile, "\nmsgstr \"\"\n");
- putc ('\n', logfile);
-}
diff --git a/src/audacious/intl/ngettext.c b/src/audacious/intl/ngettext.c
deleted file mode 100644
index 92bebce..0000000
--- a/src/audacious/intl/ngettext.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Implementation of ngettext(3) function.
- Copyright (C) 1995, 1997, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef _LIBC
-# define __need_NULL
-# include <stddef.h>
-#else
-# include <stdlib.h> /* Just for NULL. */
-#endif
-
-#include "gettextP.h"
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-
-#include <locale.h>
-
-/* @@ end of prolog @@ */
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define NGETTEXT __ngettext
-# define DCNGETTEXT __dcngettext
-#else
-# define NGETTEXT libintl_ngettext
-# define DCNGETTEXT libintl_dcngettext
-#endif
-
-/* Look up MSGID in the current default message catalog for the current
- LC_MESSAGES locale. If not found, returns MSGID itself (the default
- text). */
-char *
-NGETTEXT (msgid1, msgid2, n)
- const char *msgid1;
- const char *msgid2;
- unsigned long int n;
-{
- return DCNGETTEXT (NULL, msgid1, msgid2, n, LC_MESSAGES);
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__ngettext, ngettext);
-#endif
diff --git a/src/audacious/intl/os2compat.c b/src/audacious/intl/os2compat.c
deleted file mode 100644
index 32423e2..0000000
--- a/src/audacious/intl/os2compat.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/* OS/2 compatibility functions.
- Copyright (C) 2001-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#define OS2_AWARE
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-
-/* A version of getenv() that works from DLLs */
-extern unsigned long DosScanEnv (const unsigned char *pszName, unsigned char **ppszValue);
-
-char *
-_nl_getenv (const char *name)
-{
- unsigned char *value;
- if (DosScanEnv (name, &value))
- return NULL;
- else
- return value;
-}
-
-/* A fixed size buffer. */
-char libintl_nl_default_dirname[MAXPATHLEN+1];
-
-char *_nlos2_libdir = NULL;
-char *_nlos2_localealiaspath = NULL;
-char *_nlos2_localedir = NULL;
-
-static __attribute__((constructor)) void
-nlos2_initialize ()
-{
- char *root = getenv ("UNIXROOT");
- char *gnulocaledir = getenv ("GNULOCALEDIR");
-
- _nlos2_libdir = gnulocaledir;
- if (!_nlos2_libdir)
- {
- if (root)
- {
- size_t sl = strlen (root);
- _nlos2_libdir = (char *) malloc (sl + strlen (LIBDIR) + 1);
- memcpy (_nlos2_libdir, root, sl);
- memcpy (_nlos2_libdir + sl, LIBDIR, strlen (LIBDIR) + 1);
- }
- else
- _nlos2_libdir = LIBDIR;
- }
-
- _nlos2_localealiaspath = gnulocaledir;
- if (!_nlos2_localealiaspath)
- {
- if (root)
- {
- size_t sl = strlen (root);
- _nlos2_localealiaspath = (char *) malloc (sl + strlen (LOCALE_ALIAS_PATH) + 1);
- memcpy (_nlos2_localealiaspath, root, sl);
- memcpy (_nlos2_localealiaspath + sl, LOCALE_ALIAS_PATH, strlen (LOCALE_ALIAS_PATH) + 1);
- }
- else
- _nlos2_localealiaspath = LOCALE_ALIAS_PATH;
- }
-
- _nlos2_localedir = gnulocaledir;
- if (!_nlos2_localedir)
- {
- if (root)
- {
- size_t sl = strlen (root);
- _nlos2_localedir = (char *) malloc (sl + strlen (LOCALEDIR) + 1);
- memcpy (_nlos2_localedir, root, sl);
- memcpy (_nlos2_localedir + sl, LOCALEDIR, strlen (LOCALEDIR) + 1);
- }
- else
- _nlos2_localedir = LOCALEDIR;
- }
-
- if (strlen (_nlos2_localedir) <= MAXPATHLEN)
- g_strlcpy (libintl_nl_default_dirname, _nlos2_localedir, MAXPATHLEN + 1);
-}
diff --git a/src/audacious/intl/os2compat.h b/src/audacious/intl/os2compat.h
deleted file mode 100644
index a18d582..0000000
--- a/src/audacious/intl/os2compat.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* OS/2 compatibility defines.
- This file is intended to be included from config.h
- Copyright (C) 2001-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* When included from os2compat.h we need all the original definitions */
-#ifndef OS2_AWARE
-
-#undef LIBDIR
-#define LIBDIR _nlos2_libdir
-extern char *_nlos2_libdir;
-
-#undef LOCALEDIR
-#define LOCALEDIR _nlos2_localedir
-extern char *_nlos2_localedir;
-
-#undef LOCALE_ALIAS_PATH
-#define LOCALE_ALIAS_PATH _nlos2_localealiaspath
-extern char *_nlos2_localealiaspath;
-
-#endif
-
-#undef HAVE_STRCASECMP
-#define HAVE_STRCASECMP 1
-#define strcasecmp stricmp
-#define strncasecmp strnicmp
-
-/* We have our own getenv() which works even if library is compiled as DLL */
-#define getenv _nl_getenv
-
-/* Older versions of gettext used -1 as the value of LC_MESSAGES */
-#define LC_MESSAGES_COMPAT (-1)
diff --git a/src/audacious/intl/osdep.c b/src/audacious/intl/osdep.c
deleted file mode 100644
index d2d8575..0000000
--- a/src/audacious/intl/osdep.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/* OS dependent parts of libintl.
- Copyright (C) 2001-2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#if defined __EMX__
-# include "os2compat.c"
-#else
-/* Avoid AIX compiler warning. */
-typedef int dummy;
-#endif
diff --git a/src/audacious/intl/plural-exp.c b/src/audacious/intl/plural-exp.c
deleted file mode 100644
index 0660896..0000000
--- a/src/audacious/intl/plural-exp.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/* Expression parsing for plural form selection.
- Copyright (C) 2000, 2001 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "plural-exp.h"
-
-#if (defined __GNUC__ && !defined __APPLE_CC__) \
- || (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L)
-
-/* These structs are the constant expression for the germanic plural
- form determination. It represents the expression "n != 1". */
-static const struct expression plvar =
-{
- .nargs = 0,
- .operation = var,
-};
-static const struct expression plone =
-{
- .nargs = 0,
- .operation = num,
- .val =
- {
- .num = 1
- }
-};
-struct expression GERMANIC_PLURAL =
-{
- .nargs = 2,
- .operation = not_equal,
- .val =
- {
- .args =
- {
- [0] = (struct expression *) &plvar,
- [1] = (struct expression *) &plone
- }
- }
-};
-
-# define INIT_GERMANIC_PLURAL()
-
-#else
-
-/* For compilers without support for ISO C 99 struct/union initializers:
- Initialization at run-time. */
-
-static struct expression plvar;
-static struct expression plone;
-struct expression GERMANIC_PLURAL;
-
-static void
-init_germanic_plural ()
-{
- if (plone.val.num == 0)
- {
- plvar.nargs = 0;
- plvar.operation = var;
-
- plone.nargs = 0;
- plone.operation = num;
- plone.val.num = 1;
-
- GERMANIC_PLURAL.nargs = 2;
- GERMANIC_PLURAL.operation = not_equal;
- GERMANIC_PLURAL.val.args[0] = &plvar;
- GERMANIC_PLURAL.val.args[1] = &plone;
- }
-}
-
-# define INIT_GERMANIC_PLURAL() init_germanic_plural ()
-
-#endif
-
-void
-internal_function
-EXTRACT_PLURAL_EXPRESSION (nullentry, pluralp, npluralsp)
- const char *nullentry;
- struct expression **pluralp;
- unsigned long int *npluralsp;
-{
- if (nullentry != NULL)
- {
- const char *plural;
- const char *nplurals;
-
- plural = strstr (nullentry, "plural=");
- nplurals = strstr (nullentry, "nplurals=");
- if (plural == NULL || nplurals == NULL)
- goto no_plural;
- else
- {
- char *endp;
- unsigned long int n;
- struct parse_args args;
-
- /* First get the number. */
- nplurals += 9;
- while (*nplurals != '\0' && isspace ((unsigned char) *nplurals))
- ++nplurals;
- if (!(*nplurals >= '0' && *nplurals <= '9'))
- goto no_plural;
-#if defined HAVE_STRTOUL || defined _LIBC
- n = strtoul (nplurals, &endp, 10);
-#else
- for (endp = nplurals, n = 0; *endp >= '0' && *endp <= '9'; endp++)
- n = n * 10 + (*endp - '0');
-#endif
- if (nplurals == endp)
- goto no_plural;
- *npluralsp = n;
-
- /* Due to the restrictions bison imposes onto the interface of the
- scanner function we have to put the input string and the result
- passed up from the parser into the same structure which address
- is passed down to the parser. */
- plural += 7;
- args.cp = plural;
- if (PLURAL_PARSE (&args) != 0)
- goto no_plural;
- *pluralp = args.res;
- }
- }
- else
- {
- /* By default we are using the Germanic form: singular form only
- for `one', the plural form otherwise. Yes, this is also what
- English is using since English is a Germanic language. */
- no_plural:
- INIT_GERMANIC_PLURAL ();
- *pluralp = &GERMANIC_PLURAL;
- *npluralsp = 2;
- }
-}
diff --git a/src/audacious/intl/plural-exp.h b/src/audacious/intl/plural-exp.h
deleted file mode 100644
index d096f32..0000000
--- a/src/audacious/intl/plural-exp.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/* Expression parsing and evaluation for plural form selection.
- Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _PLURAL_EXP_H
-#define _PLURAL_EXP_H
-
-#ifndef PARAMS
-# if __STDC__ || defined __GNUC__ || defined __SUNPRO_C || defined __cplusplus || __PROTOTYPES
-# define PARAMS(args) args
-# else
-# define PARAMS(args) ()
-# endif
-#endif
-
-#ifndef internal_function
-# define internal_function
-#endif
-
-#ifndef attribute_hidden
-# define attribute_hidden
-#endif
-
-
-/* This is the representation of the expressions to determine the
- plural form. */
-struct expression
-{
- int nargs; /* Number of arguments. */
- enum operator
- {
- /* Without arguments: */
- var, /* The variable "n". */
- num, /* Decimal number. */
- /* Unary operators: */
- lnot, /* Logical NOT. */
- /* Binary operators: */
- mult, /* Multiplication. */
- divide, /* Division. */
- module, /* Modulo operation. */
- plus, /* Addition. */
- minus, /* Subtraction. */
- less_than, /* Comparison. */
- greater_than, /* Comparison. */
- less_or_equal, /* Comparison. */
- greater_or_equal, /* Comparison. */
- equal, /* Comparison for equality. */
- not_equal, /* Comparison for inequality. */
- land, /* Logical AND. */
- lor, /* Logical OR. */
- /* Ternary operators: */
- qmop /* Question mark operator. */
- } operation;
- union
- {
- unsigned long int num; /* Number value for `num'. */
- struct expression *args[3]; /* Up to three arguments. */
- } val;
-};
-
-/* This is the data structure to pass information to the parser and get
- the result in a thread-safe way. */
-struct parse_args
-{
- const char *cp;
- struct expression *res;
-};
-
-
-/* Names for the libintl functions are a problem. This source code is used
- 1. in the GNU C Library library,
- 2. in the GNU libintl library,
- 3. in the GNU gettext tools.
- The function names in each situation must be different, to allow for
- binary incompatible changes in 'struct expression'. Furthermore,
- 1. in the GNU C Library library, the names have a __ prefix,
- 2.+3. in the GNU libintl library and in the GNU gettext tools, the names
- must follow ANSI C and not start with __.
- So we have to distinguish the three cases. */
-#ifdef _LIBC
-# define FREE_EXPRESSION __gettext_free_exp
-# define PLURAL_PARSE __gettextparse
-# define GERMANIC_PLURAL __gettext_germanic_plural
-# define EXTRACT_PLURAL_EXPRESSION __gettext_extract_plural
-#elif defined (IN_LIBINTL)
-# define FREE_EXPRESSION libintl_gettext_free_exp
-# define PLURAL_PARSE libintl_gettextparse
-# define GERMANIC_PLURAL libintl_gettext_germanic_plural
-# define EXTRACT_PLURAL_EXPRESSION libintl_gettext_extract_plural
-#else
-# define FREE_EXPRESSION free_plural_expression
-# define PLURAL_PARSE parse_plural_expression
-# define GERMANIC_PLURAL germanic_plural
-# define EXTRACT_PLURAL_EXPRESSION extract_plural_expression
-#endif
-
-extern void FREE_EXPRESSION PARAMS ((struct expression *exp))
- internal_function;
-extern int PLURAL_PARSE PARAMS ((void *arg));
-extern struct expression GERMANIC_PLURAL attribute_hidden;
-extern void EXTRACT_PLURAL_EXPRESSION PARAMS ((const char *nullentry,
- struct expression **pluralp,
- unsigned long int *npluralsp))
- internal_function;
-
-#if !defined (_LIBC) && !defined (IN_LIBINTL)
-extern unsigned long int plural_eval PARAMS ((struct expression *pexp,
- unsigned long int n));
-#endif
-
-#endif /* _PLURAL_EXP_H */
diff --git a/src/audacious/intl/plural.c b/src/audacious/intl/plural.c
deleted file mode 100644
index d42bfb4..0000000
--- a/src/audacious/intl/plural.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/* A Bison parser, made from plural.y
- by GNU bison 1.35. */
-
-#define YYBISON 1 /* Identify Bison output. */
-
-#define yyparse __gettextparse
-#define yylex __gettextlex
-#define yyerror __gettexterror
-#define yylval __gettextlval
-#define yychar __gettextchar
-#define yydebug __gettextdebug
-#define yynerrs __gettextnerrs
-# define EQUOP2 257
-# define CMPOP2 258
-# define ADDOP2 259
-# define MULOP2 260
-# define NUMBER 261
-
-#line 1 "plural.y"
-
-/* Expression parsing for plural form selection.
- Copyright (C) 2000, 2001 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* The bison generated parser uses alloca. AIX 3 forces us to put this
- declaration at the beginning of the file. The declaration in bison's
- skeleton file comes too late. This must come before <config.h>
- because <config.h> may include arbitrary system headers. */
-#if defined _AIX && !defined __GNUC__
- #pragma alloca
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stddef.h>
-#include <stdlib.h>
-#include "plural-exp.h"
-
-/* The main function generated by the parser is called __gettextparse,
- but we want it to be called PLURAL_PARSE. */
-#ifndef _LIBC
-# define __gettextparse PLURAL_PARSE
-#endif
-
-#define YYLEX_PARAM &((struct parse_args *) arg)->cp
-#define YYPARSE_PARAM arg
-
-#line 49 "plural.y"
-#ifndef YYSTYPE
-typedef union {
- unsigned long int num;
- enum operator op;
- struct expression *exp;
-} yystype;
-# define YYSTYPE yystype
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-#line 55 "plural.y"
-
-/* Prototypes for local functions. */
-static struct expression *new_exp PARAMS ((int nargs, enum operator op,
- struct expression * const *args));
-static inline struct expression *new_exp_0 PARAMS ((enum operator op));
-static inline struct expression *new_exp_1 PARAMS ((enum operator op,
- struct expression *right));
-static struct expression *new_exp_2 PARAMS ((enum operator op,
- struct expression *left,
- struct expression *right));
-static inline struct expression *new_exp_3 PARAMS ((enum operator op,
- struct expression *bexp,
- struct expression *tbranch,
- struct expression *fbranch));
-static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
-static void yyerror PARAMS ((const char *str));
-
-/* Allocation of expressions. */
-
-static struct expression *
-new_exp (nargs, op, args)
- int nargs;
- enum operator op;
- struct expression * const *args;
-{
- int i;
- struct expression *newp;
-
- /* If any of the argument could not be malloc'ed, just return NULL. */
- for (i = nargs - 1; i >= 0; i--)
- if (args[i] == NULL)
- goto fail;
-
- /* Allocate a new expression. */
- newp = (struct expression *) malloc (sizeof (*newp));
- if (newp != NULL)
- {
- newp->nargs = nargs;
- newp->operation = op;
- for (i = nargs - 1; i >= 0; i--)
- newp->val.args[i] = args[i];
- return newp;
- }
-
- fail:
- for (i = nargs - 1; i >= 0; i--)
- FREE_EXPRESSION (args[i]);
-
- return NULL;
-}
-
-static inline struct expression *
-new_exp_0 (op)
- enum operator op;
-{
- return new_exp (0, op, NULL);
-}
-
-static inline struct expression *
-new_exp_1 (op, right)
- enum operator op;
- struct expression *right;
-{
- struct expression *args[1];
-
- args[0] = right;
- return new_exp (1, op, args);
-}
-
-static struct expression *
-new_exp_2 (op, left, right)
- enum operator op;
- struct expression *left;
- struct expression *right;
-{
- struct expression *args[2];
-
- args[0] = left;
- args[1] = right;
- return new_exp (2, op, args);
-}
-
-static inline struct expression *
-new_exp_3 (op, bexp, tbranch, fbranch)
- enum operator op;
- struct expression *bexp;
- struct expression *tbranch;
- struct expression *fbranch;
-{
- struct expression *args[3];
-
- args[0] = bexp;
- args[1] = tbranch;
- args[2] = fbranch;
- return new_exp (3, op, args);
-}
-
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-
-
-#define YYFINAL 27
-#define YYFLAG -32768
-#define YYNTBASE 16
-
-/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
-#define YYTRANSLATE(x) ((unsigned)(x) <= 261 ? yytranslate[x] : 18)
-
-/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
-static const char yytranslate[] =
-{
- 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 10, 2, 2, 2, 2, 5, 2,
- 14, 15, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 12, 2,
- 2, 2, 2, 3, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 13, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 4, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 1, 6, 7, 8,
- 9, 11
-};
-
-#if YYDEBUG
-static const short yyprhs[] =
-{
- 0, 0, 2, 8, 12, 16, 20, 24, 28, 32,
- 35, 37, 39
-};
-static const short yyrhs[] =
-{
- 17, 0, 17, 3, 17, 12, 17, 0, 17, 4,
- 17, 0, 17, 5, 17, 0, 17, 6, 17, 0,
- 17, 7, 17, 0, 17, 8, 17, 0, 17, 9,
- 17, 0, 10, 17, 0, 13, 0, 11, 0, 14,
- 17, 15, 0
-};
-
-#endif
-
-#if YYDEBUG
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const short yyrline[] =
-{
- 0, 174, 182, 186, 190, 194, 198, 202, 206, 210,
- 214, 218, 223
-};
-#endif
-
-
-#if (YYDEBUG) || defined YYERROR_VERBOSE
-
-/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
-static const char *const yytname[] =
-{
- "$", "error", "$undefined.", "'?'", "'|'", "'&'", "EQUOP2", "CMPOP2",
- "ADDOP2", "MULOP2", "'!'", "NUMBER", "':'", "'n'", "'('", "')'",
- "start", "exp", 0
-};
-#endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const short yyr1[] =
-{
- 0, 16, 17, 17, 17, 17, 17, 17, 17, 17,
- 17, 17, 17
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const short yyr2[] =
-{
- 0, 1, 5, 3, 3, 3, 3, 3, 3, 2,
- 1, 1, 3
-};
-
-/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
- doesn't specify something else to do. Zero means the default is an
- error. */
-static const short yydefact[] =
-{
- 0, 0, 11, 10, 0, 1, 9, 0, 0, 0,
- 0, 0, 0, 0, 0, 12, 0, 3, 4, 5,
- 6, 7, 8, 0, 2, 0, 0, 0
-};
-
-static const short yydefgoto[] =
-{
- 25, 5
-};
-
-static const short yypact[] =
-{
- -9, -9,-32768,-32768, -9, 34,-32768, 11, -9, -9,
- -9, -9, -9, -9, -9,-32768, 24, 39, 43, 16,
- 26, -3,-32768, -9, 34, 21, 53,-32768
-};
-
-static const short yypgoto[] =
-{
- -32768, -1
-};
-
-
-#define YYLAST 53
-
-
-static const short yytable[] =
-{
- 6, 1, 2, 7, 3, 4, 14, 16, 17, 18,
- 19, 20, 21, 22, 8, 9, 10, 11, 12, 13,
- 14, 26, 24, 12, 13, 14, 15, 8, 9, 10,
- 11, 12, 13, 14, 13, 14, 23, 8, 9, 10,
- 11, 12, 13, 14, 10, 11, 12, 13, 14, 11,
- 12, 13, 14, 27
-};
-
-static const short yycheck[] =
-{
- 1, 10, 11, 4, 13, 14, 9, 8, 9, 10,
- 11, 12, 13, 14, 3, 4, 5, 6, 7, 8,
- 9, 0, 23, 7, 8, 9, 15, 3, 4, 5,
- 6, 7, 8, 9, 8, 9, 12, 3, 4, 5,
- 6, 7, 8, 9, 5, 6, 7, 8, 9, 6,
- 7, 8, 9, 0
-};
-#define YYPURE 1
-
-/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
-#line 3 "/usr/local/share/bison/bison.simple"
-
-/* Skeleton output parser for bison,
-
- Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
- Foundation, Inc.
-
- 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, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
-
-/* As a special exception, when this file is copied by Bison into a
- Bison output file, you may use that output file without restriction.
- This special exception was added by the Free Software Foundation
- in version 1.24 of Bison. */
-
-/* This is the parser code that is written into each bison parser when
- the %semantic_parser declaration is not specified in the grammar.
- It was written by Richard Stallman by simplifying the hairy parser
- used when %semantic_parser is specified. */
-
-/* All symbols defined below should begin with yy or YY, to avoid
- infringing on user name space. This should be done even for local
- variables, as they might otherwise be expanded by user macros.
- There are some unavoidable exceptions within include files to
- define necessary library symbols; they are noted "INFRINGES ON
- USER NAME SPACE" below. */
-
-#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
-
-/* The parser invokes alloca or malloc; define the necessary symbols. */
-
-# if YYSTACK_USE_ALLOCA
-# define YYSTACK_ALLOC alloca
-# else
-# ifndef YYSTACK_USE_ALLOCA
-# if defined (alloca) || defined (_ALLOCA_H)
-# define YYSTACK_ALLOC alloca
-# else
-# ifdef __GNUC__
-# define YYSTACK_ALLOC __builtin_alloca
-# endif
-# endif
-# endif
-# endif
-
-# ifdef YYSTACK_ALLOC
- /* Pacify GCC's `empty if-body' warning. */
-# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
-# else
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-# define YYSTACK_ALLOC malloc
-# define YYSTACK_FREE free
-# endif
-#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
-
-
-#if (! defined (yyoverflow) \
- && (! defined (__cplusplus) \
- || (YYLTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member. */
-union yyalloc
-{
- short yyss;
- YYSTYPE yyvs;
-# if YYLSP_NEEDED
- YYLTYPE yyls;
-# endif
-};
-
-/* The size of the maximum gap between one aligned stack and the next. */
-# define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
- N elements. */
-# if YYLSP_NEEDED
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \
- + 2 * YYSTACK_GAP_MAX)
-# else
-# define YYSTACK_BYTES(N) \
- ((N) * (sizeof (short) + sizeof (YYSTYPE)) \
- + YYSTACK_GAP_MAX)
-# endif
-
-/* Copy COUNT objects from FROM to TO. The source and destination do
- not overlap. */
-# ifndef YYCOPY
-# if 1 < __GNUC__
-# define YYCOPY(To, From, Count) \
- __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-# else
-# define YYCOPY(To, From, Count) \
- do \
- { \
- register YYSIZE_T yyi; \
- for (yyi = 0; yyi < (Count); yyi++) \
- (To)[yyi] = (From)[yyi]; \
- } \
- while (0)
-# endif
-# endif
-
-/* Relocate STACK from its old location to the new one. The
- local variables YYSIZE and YYSTACKSIZE give the old and new number of
- elements in the stack, and YYPTR gives the new location of the
- stack. Advance YYPTR to a properly aligned location for the next
- stack. */
-# define YYSTACK_RELOCATE(Stack) \
- do \
- { \
- YYSIZE_T yynewbytes; \
- YYCOPY (&yyptr->Stack, Stack, yysize); \
- Stack = &yyptr->Stack; \
- yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAX; \
- yyptr += yynewbytes / sizeof (*yyptr); \
- } \
- while (0)
-
-#endif
-
-
-#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
-# define YYSIZE_T __SIZE_TYPE__
-#endif
-#if ! defined (YYSIZE_T) && defined (size_t)
-# define YYSIZE_T size_t
-#endif
-#if ! defined (YYSIZE_T)
-# if defined (__STDC__) || defined (__cplusplus)
-# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-# define YYSIZE_T size_t
-# endif
-#endif
-#if ! defined (YYSIZE_T)
-# define YYSIZE_T unsigned int
-#endif
-
-#define yyerrok (yyerrstatus = 0)
-#define yyclearin (yychar = YYEMPTY)
-#define YYEMPTY -2
-#define YYEOF 0
-#define YYACCEPT goto yyacceptlab
-#define YYABORT goto yyabortlab
-#define YYERROR goto yyerrlab1
-/* Like YYERROR except do call yyerror. This remains here temporarily
- to ease the transition to the new meaning of YYERROR, for GCC.
- Once GCC version 2 has supplanted version 1, this can go. */
-#define YYFAIL goto yyerrlab
-#define YYRECOVERING() (!!yyerrstatus)
-#define YYBACKUP(Token, Value) \
-do \
- if (yychar == YYEMPTY && yylen == 1) \
- { \
- yychar = (Token); \
- yylval = (Value); \
- yychar1 = YYTRANSLATE (yychar); \
- YYPOPSTACK; \
- goto yybackup; \
- } \
- else \
- { \
- yyerror ("syntax error: cannot back up"); \
- YYERROR; \
- } \
-while (0)
-
-#define YYTERROR 1
-#define YYERRCODE 256
-
-
-/* YYLLOC_DEFAULT -- Compute the default location (before the actions
- are run).
-
- When YYLLOC_DEFAULT is run, CURRENT is set the location of the
- first token. By default, to implement support for ranges, extend
- its range to the last symbol. */
-
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N) \
- Current.last_line = Rhs[N].last_line; \
- Current.last_column = Rhs[N].last_column;
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments. */
-
-#if YYPURE
-# if YYLSP_NEEDED
-# ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, &yylloc, YYLEX_PARAM)
-# else
-# define YYLEX yylex (&yylval, &yylloc)
-# endif
-# else /* !YYLSP_NEEDED */
-# ifdef YYLEX_PARAM
-# define YYLEX yylex (&yylval, YYLEX_PARAM)
-# else
-# define YYLEX yylex (&yylval)
-# endif
-# endif /* !YYLSP_NEEDED */
-#else /* !YYPURE */
-# define YYLEX yylex ()
-#endif /* !YYPURE */
-
-
-/* Enable debugging if requested. */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-# define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args) \
-do { \
- if (yydebug) \
- YYFPRINTF Args; \
-} while (0)
-/* Nonzero means print parse trace. It is left uninitialized so that
- multiple parsers can coexist. */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-#endif /* !YYDEBUG */
-
-/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
- if the built-in stack extension method is used).
-
- Do not make this value too large; the results are undefined if
- SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
- evaluated with infinite-precision integer arithmetic. */
-
-#if YYMAXDEPTH == 0
-# undef YYMAXDEPTH
-#endif
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-#ifdef YYERROR_VERBOSE
-
-# ifndef yystrlen
-# if defined (__GLIBC__) && defined (_STRING_H)
-# define yystrlen strlen
-# else
-/* Return the length of YYSTR. */
-static YYSIZE_T
-# if defined (__STDC__) || defined (__cplusplus)
-yystrlen (const char *yystr)
-# else
-yystrlen (yystr)
- const char *yystr;
-# endif
-{
- register const char *yys = yystr;
-
- while (*yys++ != '\0')
- continue;
-
- return yys - yystr - 1;
-}
-# endif
-# endif
-
-# ifndef yystpcpy
-# if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
-# define yystpcpy stpcpy
-# else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
- YYDEST. */
-static char *
-# if defined (__STDC__) || defined (__cplusplus)
-yystpcpy (char *yydest, const char *yysrc)
-# else
-yystpcpy (yydest, yysrc)
- char *yydest;
- const char *yysrc;
-# endif
-{
- register char *yyd = yydest;
- register const char *yys = yysrc;
-
- while ((*yyd++ = *yys++) != '\0')
- continue;
-
- return yyd - 1;
-}
-# endif
-# endif
-#endif
-
-#line 315 "/usr/local/share/bison/bison.simple"
-
-
-/* The user can define YYPARSE_PARAM as the name of an argument to be passed
- into yyparse. The argument should have type void *.
- It should actually point to an object.
- Grammar actions can access the variable by casting it
- to the proper pointer type. */
-
-#ifdef YYPARSE_PARAM
-# if defined (__STDC__) || defined (__cplusplus)
-# define YYPARSE_PARAM_ARG void *YYPARSE_PARAM
-# define YYPARSE_PARAM_DECL
-# else
-# define YYPARSE_PARAM_ARG YYPARSE_PARAM
-# define YYPARSE_PARAM_DECL void *YYPARSE_PARAM;
-# endif
-#else /* !YYPARSE_PARAM */
-# define YYPARSE_PARAM_ARG
-# define YYPARSE_PARAM_DECL
-#endif /* !YYPARSE_PARAM */
-
-/* Prevent warning if -Wstrict-prototypes. */
-#ifdef __GNUC__
-# ifdef YYPARSE_PARAM
-int yyparse (void *);
-# else
-int yyparse (void);
-# endif
-#endif
-
-/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
- variables are global, or local to YYPARSE. */
-
-#define YY_DECL_NON_LSP_VARIABLES \
-/* The lookahead symbol. */ \
-int yychar; \
- \
-/* The semantic value of the lookahead symbol. */ \
-YYSTYPE yylval; \
- \
-/* Number of parse errors so far. */ \
-int yynerrs;
-
-#if YYLSP_NEEDED
-# define YY_DECL_VARIABLES \
-YY_DECL_NON_LSP_VARIABLES \
- \
-/* Location data for the lookahead symbol. */ \
-YYLTYPE yylloc;
-#else
-# define YY_DECL_VARIABLES \
-YY_DECL_NON_LSP_VARIABLES
-#endif
-
-
-/* If nonreentrant, generate the variables here. */
-
-#if !YYPURE
-YY_DECL_VARIABLES
-#endif /* !YYPURE */
-
-int
-yyparse (YYPARSE_PARAM_ARG)
- YYPARSE_PARAM_DECL
-{
- /* If reentrant, generate the variables here. */
-#if YYPURE
- YY_DECL_VARIABLES
-#endif /* !YYPURE */
-
- register int yystate;
- register int yyn;
- int yyresult;
- /* Number of tokens to shift before error messages enabled. */
- int yyerrstatus;
- /* Lookahead token as an internal (translated) token number. */
- int yychar1 = 0;
-
- /* Three stacks and their tools:
- `yyss': related to states,
- `yyvs': related to semantic values,
- `yyls': related to locations.
-
- Refer to the stacks thru separate pointers, to allow yyoverflow
- to reallocate them elsewhere. */
-
- /* The state stack. */
- short yyssa[YYINITDEPTH];
- short *yyss = yyssa;
- register short *yyssp;
-
- /* The semantic value stack. */
- YYSTYPE yyvsa[YYINITDEPTH];
- YYSTYPE *yyvs = yyvsa;
- register YYSTYPE *yyvsp;
-
-#if YYLSP_NEEDED
- /* The location stack. */
- YYLTYPE yylsa[YYINITDEPTH];
- YYLTYPE *yyls = yylsa;
- YYLTYPE *yylsp;
-#endif
-
-#if YYLSP_NEEDED
-# define YYPOPSTACK (yyvsp--, yyssp--, yylsp--)
-#else
-# define YYPOPSTACK (yyvsp--, yyssp--)
-#endif
-
- YYSIZE_T yystacksize = YYINITDEPTH;
-
-
- /* The variables used to return semantic value and location from the
- action routines. */
- YYSTYPE yyval;
-#if YYLSP_NEEDED
- YYLTYPE yyloc;
-#endif
-
- /* When reducing, the number of symbols on the RHS of the reduced
- rule. */
- int yylen;
-
- YYDPRINTF ((stderr, "Starting parse\n"));
-
- yystate = 0;
- yyerrstatus = 0;
- yynerrs = 0;
- yychar = YYEMPTY; /* Cause a token to be read. */
-
- /* Initialize stack pointers.
- Waste one element of value and location stack
- so that they stay on the same level as the state stack.
- The wasted elements are never initialized. */
-
- yyssp = yyss;
- yyvsp = yyvs;
-#if YYLSP_NEEDED
- yylsp = yyls;
-#endif
- goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate. |
-`------------------------------------------------------------*/
- yynewstate:
- /* In all cases, when you get here, the value and location stacks
- have just been pushed. so pushing a state here evens the stacks.
- */
- yyssp++;
-
- yysetstate:
- *yyssp = yystate;
-
- if (yyssp >= yyss + yystacksize - 1)
- {
- /* Get the current used size of the three stacks, in elements. */
- YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
- {
- /* Give user a chance to reallocate the stack. Use copies of
- these so that the &'s don't force the real ones into
- memory. */
- YYSTYPE *yyvs1 = yyvs;
- short *yyss1 = yyss;
-
- /* Each stack pointer address is followed by the size of the
- data in use in that stack, in bytes. */
-# if YYLSP_NEEDED
- YYLTYPE *yyls1 = yyls;
- /* This used to be a conditional around just the two extra args,
- but that might be undefined if yyoverflow is a macro. */
- yyoverflow ("parser stack overflow",
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yyls1, yysize * sizeof (*yylsp),
- &yystacksize);
- yyls = yyls1;
-# else
- yyoverflow ("parser stack overflow",
- &yyss1, yysize * sizeof (*yyssp),
- &yyvs1, yysize * sizeof (*yyvsp),
- &yystacksize);
-# endif
- yyss = yyss1;
- yyvs = yyvs1;
- }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
- goto yyoverflowlab;
-# else
- /* Extend the stack our own way. */
- if (yystacksize >= YYMAXDEPTH)
- goto yyoverflowlab;
- yystacksize *= 2;
- if (yystacksize > YYMAXDEPTH)
- yystacksize = YYMAXDEPTH;
-
- {
- short *yyss1 = yyss;
- union yyalloc *yyptr =
- (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
- if (! yyptr)
- goto yyoverflowlab;
- YYSTACK_RELOCATE (yyss);
- YYSTACK_RELOCATE (yyvs);
-# if YYLSP_NEEDED
- YYSTACK_RELOCATE (yyls);
-# endif
-# undef YYSTACK_RELOCATE
- if (yyss1 != yyssa)
- YYSTACK_FREE (yyss1);
- }
-# endif
-#endif /* no yyoverflow */
-
- yyssp = yyss + yysize - 1;
- yyvsp = yyvs + yysize - 1;
-#if YYLSP_NEEDED
- yylsp = yyls + yysize - 1;
-#endif
-
- YYDPRINTF ((stderr, "Stack size increased to %lu\n",
- (unsigned long int) yystacksize));
-
- if (yyssp >= yyss + yystacksize - 1)
- YYABORT;
- }
-
- YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
- goto yybackup;
-
-
-/*-----------.
-| yybackup. |
-`-----------*/
-yybackup:
-
-/* Do appropriate processing given the current state. */
-/* Read a lookahead token if we need one and don't already have one. */
-/* yyresume: */
-
- /* First try to decide what to do without reference to lookahead token. */
-
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yydefault;
-
- /* Not known => get a lookahead token if don't already have one. */
-
- /* yychar is either YYEMPTY or YYEOF
- or a valid token in external form. */
-
- if (yychar == YYEMPTY)
- {
- YYDPRINTF ((stderr, "Reading a token: "));
- yychar = YYLEX;
- }
-
- /* Convert token to internal form (in yychar1) for indexing tables with */
-
- if (yychar <= 0) /* This means end of input. */
- {
- yychar1 = 0;
- yychar = YYEOF; /* Don't call YYLEX any more */
-
- YYDPRINTF ((stderr, "Now at end of input.\n"));
- }
- else
- {
- yychar1 = YYTRANSLATE (yychar);
-
-#if YYDEBUG
- /* We have to keep this `#if YYDEBUG', since we use variables
- which are defined only if `YYDEBUG' is set. */
- if (yydebug)
- {
- YYFPRINTF (stderr, "Next token is %d (%s",
- yychar, yytname[yychar1]);
- /* Give the individual parser a way to print the precise
- meaning of a token, for further debugging info. */
-# ifdef YYPRINT
- YYPRINT (stderr, yychar, yylval);
-# endif
- YYFPRINTF (stderr, ")\n");
- }
-#endif
- }
-
- yyn += yychar1;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
- goto yydefault;
-
- yyn = yytable[yyn];
-
- /* yyn is what to do for this token type in this state.
- Negative => reduce, -yyn is rule number.
- Positive => shift, yyn is new state.
- New state is final state => don't bother to shift,
- just return success.
- 0, or most negative number => error. */
-
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrlab;
- yyn = -yyn;
- goto yyreduce;
- }
- else if (yyn == 0)
- goto yyerrlab;
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- /* Shift the lookahead token. */
- YYDPRINTF ((stderr, "Shifting token %d (%s), ",
- yychar, yytname[yychar1]));
-
- /* Discard the token being shifted unless it is eof. */
- if (yychar != YYEOF)
- yychar = YYEMPTY;
-
- *++yyvsp = yylval;
-#if YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
-
- /* Count tokens shifted since error; after three, turn off error
- status. */
- if (yyerrstatus)
- yyerrstatus--;
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state. |
-`-----------------------------------------------------------*/
-yydefault:
- yyn = yydefact[yystate];
- if (yyn == 0)
- goto yyerrlab;
- goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction. |
-`-----------------------------*/
-yyreduce:
- /* yyn is the number of a rule to reduce with. */
- yylen = yyr2[yyn];
-
- /* If YYLEN is nonzero, implement the default value of the action:
- `$$ = $1'.
-
- Otherwise, the following line sets YYVAL to the semantic value of
- the lookahead token. This behavior is undocumented and Bison
- users should not rely upon it. Assigning to YYVAL
- unconditionally makes the parser a bit smaller, and it avoids a
- GCC warning that YYVAL may be used uninitialized. */
- yyval = yyvsp[1-yylen];
-
-#if YYLSP_NEEDED
- /* Similarly for the default location. Let the user run additional
- commands if for instance locations are ranges. */
- yyloc = yylsp[1-yylen];
- YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
-#endif
-
-#if YYDEBUG
- /* We have to keep this `#if YYDEBUG', since we use variables which
- are defined only if `YYDEBUG' is set. */
- if (yydebug)
- {
- int yyi;
-
- YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
- yyn, yyrline[yyn]);
-
- /* Print the symbols being reduced, and their result. */
- for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
- YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
- YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
- }
-#endif
-
- switch (yyn) {
-
-case 1:
-#line 175 "plural.y"
-{
- if (yyvsp[0].exp == NULL)
- YYABORT;
- ((struct parse_args *) arg)->res = yyvsp[0].exp;
- }
- break;
-case 2:
-#line 183 "plural.y"
-{
- yyval.exp = new_exp_3 (qmop, yyvsp[-4].exp, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 3:
-#line 187 "plural.y"
-{
- yyval.exp = new_exp_2 (lor, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 4:
-#line 191 "plural.y"
-{
- yyval.exp = new_exp_2 (land, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 5:
-#line 195 "plural.y"
-{
- yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 6:
-#line 199 "plural.y"
-{
- yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 7:
-#line 203 "plural.y"
-{
- yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 8:
-#line 207 "plural.y"
-{
- yyval.exp = new_exp_2 (yyvsp[-1].op, yyvsp[-2].exp, yyvsp[0].exp);
- }
- break;
-case 9:
-#line 211 "plural.y"
-{
- yyval.exp = new_exp_1 (lnot, yyvsp[0].exp);
- }
- break;
-case 10:
-#line 215 "plural.y"
-{
- yyval.exp = new_exp_0 (var);
- }
- break;
-case 11:
-#line 219 "plural.y"
-{
- if ((yyval.exp = new_exp_0 (num)) != NULL)
- yyval.exp->val.num = yyvsp[0].num;
- }
- break;
-case 12:
-#line 224 "plural.y"
-{
- yyval.exp = yyvsp[-1].exp;
- }
- break;
-}
-
-#line 705 "/usr/local/share/bison/bison.simple"
-
-
- yyvsp -= yylen;
- yyssp -= yylen;
-#if YYLSP_NEEDED
- yylsp -= yylen;
-#endif
-
-#if YYDEBUG
- if (yydebug)
- {
- short *yyssp1 = yyss - 1;
- YYFPRINTF (stderr, "state stack now");
- while (yyssp1 != yyssp)
- YYFPRINTF (stderr, " %d", *++yyssp1);
- YYFPRINTF (stderr, "\n");
- }
-#endif
-
- *++yyvsp = yyval;
-#if YYLSP_NEEDED
- *++yylsp = yyloc;
-#endif
-
- /* Now `shift' the result of the reduction. Determine what state
- that goes to, based on the state we popped back to and the rule
- number reduced by. */
-
- yyn = yyr1[yyn];
-
- yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
- if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
- yystate = yytable[yystate];
- else
- yystate = yydefgoto[yyn - YYNTBASE];
-
- goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
- /* If not already recovering from an error, report this error. */
- if (!yyerrstatus)
- {
- ++yynerrs;
-
-#ifdef YYERROR_VERBOSE
- yyn = yypact[yystate];
-
- if (yyn > YYFLAG && yyn < YYLAST)
- {
- YYSIZE_T yysize = 0;
- char *yymsg;
- int yyx, yycount;
-
- yycount = 0;
- /* Start YYX at -YYN if negative to avoid negative indexes in
- YYCHECK. */
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
- if (yycheck[yyx + yyn] == yyx)
- yysize += yystrlen (yytname[yyx]) + 15, yycount++;
- yysize += yystrlen ("parse error, unexpected ") + 1;
- yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
- yymsg = (char *) YYSTACK_ALLOC (yysize);
- if (yymsg != 0)
- {
- char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
- yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
-
- if (yycount < 5)
- {
- yycount = 0;
- for (yyx = yyn < 0 ? -yyn : 0;
- yyx < (int) (sizeof (yytname) / sizeof (char *));
- yyx++)
- if (yycheck[yyx + yyn] == yyx)
- {
- const char *yyq = ! yycount ? ", expecting " : " or ";
- yyp = yystpcpy (yyp, yyq);
- yyp = yystpcpy (yyp, yytname[yyx]);
- yycount++;
- }
- }
- yyerror (yymsg);
- YYSTACK_FREE (yymsg);
- }
- else
- yyerror ("parse error; also virtual memory exhausted");
- }
- else
-#endif /* defined (YYERROR_VERBOSE) */
- yyerror ("parse error");
- }
- goto yyerrlab1;
-
-
-/*--------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action |
-`--------------------------------------------------*/
-yyerrlab1:
- if (yyerrstatus == 3)
- {
- /* If just tried and failed to reuse lookahead token after an
- error, discard it. */
-
- /* return failure if at end of input */
- if (yychar == YYEOF)
- YYABORT;
- YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
- yychar, yytname[yychar1]));
- yychar = YYEMPTY;
- }
-
- /* Else will try to reuse lookahead token after shifting the error
- token. */
-
- yyerrstatus = 3; /* Each real token shifted decrements this */
-
- goto yyerrhandle;
-
-
-/*-------------------------------------------------------------------.
-| yyerrdefault -- current state does not do anything special for the |
-| error token. |
-`-------------------------------------------------------------------*/
-yyerrdefault:
-#if 0
- /* This is wrong; only states that explicitly want error tokens
- should shift them. */
-
- /* If its default is to accept any token, ok. Otherwise pop it. */
- yyn = yydefact[yystate];
- if (yyn)
- goto yydefault;
-#endif
-
-
-/*---------------------------------------------------------------.
-| yyerrpop -- pop the current state because it cannot handle the |
-| error token |
-`---------------------------------------------------------------*/
-yyerrpop:
- if (yyssp == yyss)
- YYABORT;
- yyvsp--;
- yystate = *--yyssp;
-#if YYLSP_NEEDED
- yylsp--;
-#endif
-
-#if YYDEBUG
- if (yydebug)
- {
- short *yyssp1 = yyss - 1;
- YYFPRINTF (stderr, "Error: state stack now");
- while (yyssp1 != yyssp)
- YYFPRINTF (stderr, " %d", *++yyssp1);
- YYFPRINTF (stderr, "\n");
- }
-#endif
-
-/*--------------.
-| yyerrhandle. |
-`--------------*/
-yyerrhandle:
- yyn = yypact[yystate];
- if (yyn == YYFLAG)
- goto yyerrdefault;
-
- yyn += YYTERROR;
- if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
- goto yyerrdefault;
-
- yyn = yytable[yyn];
- if (yyn < 0)
- {
- if (yyn == YYFLAG)
- goto yyerrpop;
- yyn = -yyn;
- goto yyreduce;
- }
- else if (yyn == 0)
- goto yyerrpop;
-
- if (yyn == YYFINAL)
- YYACCEPT;
-
- YYDPRINTF ((stderr, "Shifting error token, "));
-
- *++yyvsp = yylval;
-#if YYLSP_NEEDED
- *++yylsp = yylloc;
-#endif
-
- yystate = yyn;
- goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here. |
-`-------------------------------------*/
-yyacceptlab:
- yyresult = 0;
- goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here. |
-`-----------------------------------*/
-yyabortlab:
- yyresult = 1;
- goto yyreturn;
-
-/*---------------------------------------------.
-| yyoverflowab -- parser overflow comes here. |
-`---------------------------------------------*/
-yyoverflowlab:
- yyerror ("parser stack overflow");
- yyresult = 2;
- /* Fall through. */
-
-yyreturn:
-#ifndef yyoverflow
- if (yyss != yyssa)
- YYSTACK_FREE (yyss);
-#endif
- return yyresult;
-}
-#line 229 "plural.y"
-
-
-void
-internal_function
-FREE_EXPRESSION (exp)
- struct expression *exp;
-{
- if (exp == NULL)
- return;
-
- /* Handle the recursive case. */
- switch (exp->nargs)
- {
- case 3:
- FREE_EXPRESSION (exp->val.args[2]);
- /* FALLTHROUGH */
- case 2:
- FREE_EXPRESSION (exp->val.args[1]);
- /* FALLTHROUGH */
- case 1:
- FREE_EXPRESSION (exp->val.args[0]);
- /* FALLTHROUGH */
- default:
- break;
- }
-
- free (exp);
-}
-
-
-static int
-yylex (lval, pexp)
- YYSTYPE *lval;
- const char **pexp;
-{
- const char *exp = *pexp;
- int result;
-
- while (1)
- {
- if (exp[0] == '\0')
- {
- *pexp = exp;
- return YYEOF;
- }
-
- if (exp[0] != ' ' && exp[0] != '\t')
- break;
-
- ++exp;
- }
-
- result = *exp++;
- switch (result)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- unsigned long int n = result - '0';
- while (exp[0] >= '0' && exp[0] <= '9')
- {
- n *= 10;
- n += exp[0] - '0';
- ++exp;
- }
- lval->num = n;
- result = NUMBER;
- }
- break;
-
- case '=':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = equal;
- result = EQUOP2;
- }
- else
- result = YYERRCODE;
- break;
-
- case '!':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = not_equal;
- result = EQUOP2;
- }
- break;
-
- case '&':
- case '|':
- if (exp[0] == result)
- ++exp;
- else
- result = YYERRCODE;
- break;
-
- case '<':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = less_or_equal;
- }
- else
- lval->op = less_than;
- result = CMPOP2;
- break;
-
- case '>':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = greater_or_equal;
- }
- else
- lval->op = greater_than;
- result = CMPOP2;
- break;
-
- case '*':
- lval->op = mult;
- result = MULOP2;
- break;
-
- case '/':
- lval->op = divide;
- result = MULOP2;
- break;
-
- case '%':
- lval->op = module;
- result = MULOP2;
- break;
-
- case '+':
- lval->op = plus;
- result = ADDOP2;
- break;
-
- case '-':
- lval->op = minus;
- result = ADDOP2;
- break;
-
- case 'n':
- case '?':
- case ':':
- case '(':
- case ')':
- /* Nothing, just return the character. */
- break;
-
- case ';':
- case '\n':
- case '\0':
- /* Be safe and let the user call this function again. */
- --exp;
- result = YYEOF;
- break;
-
- default:
- result = YYERRCODE;
-#if YYDEBUG != 0
- --exp;
-#endif
- break;
- }
-
- *pexp = exp;
-
- return result;
-}
-
-
-static void
-yyerror (str)
- const char *str;
-{
- /* Do nothing. We don't print error messages here. */
-}
diff --git a/src/audacious/intl/plural.y b/src/audacious/intl/plural.y
deleted file mode 100644
index 75a1c01..0000000
--- a/src/audacious/intl/plural.y
+++ /dev/null
@@ -1,409 +0,0 @@
-%{
-/* Expression parsing for plural form selection.
- Copyright (C) 2000, 2001 Free Software Foundation, Inc.
- Written by Ulrich Drepper <drepper@cygnus.com>, 2000.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-/* The bison generated parser uses alloca. AIX 3 forces us to put this
- declaration at the beginning of the file. The declaration in bison's
- skeleton file comes too late. This must come before <config.h>
- because <config.h> may include arbitrary system headers. */
-#if defined _AIX && !defined __GNUC__
- #pragma alloca
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stddef.h>
-#include <stdlib.h>
-#include "plural-exp.h"
-
-/* The main function generated by the parser is called __gettextparse,
- but we want it to be called PLURAL_PARSE. */
-#ifndef _LIBC
-# define __gettextparse PLURAL_PARSE
-#endif
-
-#define YYLEX_PARAM &((struct parse_args *) arg)->cp
-#define YYPARSE_PARAM arg
-%}
-%pure_parser
-%expect 7
-
-%union {
- unsigned long int num;
- enum operator op;
- struct expression *exp;
-}
-
-%{
-/* Prototypes for local functions. */
-static struct expression *new_exp PARAMS ((int nargs, enum operator op,
- struct expression * const *args));
-static inline struct expression *new_exp_0 PARAMS ((enum operator op));
-static inline struct expression *new_exp_1 PARAMS ((enum operator op,
- struct expression *right));
-static struct expression *new_exp_2 PARAMS ((enum operator op,
- struct expression *left,
- struct expression *right));
-static inline struct expression *new_exp_3 PARAMS ((enum operator op,
- struct expression *bexp,
- struct expression *tbranch,
- struct expression *fbranch));
-static int yylex PARAMS ((YYSTYPE *lval, const char **pexp));
-static void yyerror PARAMS ((const char *str));
-
-/* Allocation of expressions. */
-
-static struct expression *
-new_exp (nargs, op, args)
- int nargs;
- enum operator op;
- struct expression * const *args;
-{
- int i;
- struct expression *newp;
-
- /* If any of the argument could not be malloc'ed, just return NULL. */
- for (i = nargs - 1; i >= 0; i--)
- if (args[i] == NULL)
- goto fail;
-
- /* Allocate a new expression. */
- newp = (struct expression *) malloc (sizeof (*newp));
- if (newp != NULL)
- {
- newp->nargs = nargs;
- newp->operation = op;
- for (i = nargs - 1; i >= 0; i--)
- newp->val.args[i] = args[i];
- return newp;
- }
-
- fail:
- for (i = nargs - 1; i >= 0; i--)
- FREE_EXPRESSION (args[i]);
-
- return NULL;
-}
-
-static inline struct expression *
-new_exp_0 (op)
- enum operator op;
-{
- return new_exp (0, op, NULL);
-}
-
-static inline struct expression *
-new_exp_1 (op, right)
- enum operator op;
- struct expression *right;
-{
- struct expression *args[1];
-
- args[0] = right;
- return new_exp (1, op, args);
-}
-
-static struct expression *
-new_exp_2 (op, left, right)
- enum operator op;
- struct expression *left;
- struct expression *right;
-{
- struct expression *args[2];
-
- args[0] = left;
- args[1] = right;
- return new_exp (2, op, args);
-}
-
-static inline struct expression *
-new_exp_3 (op, bexp, tbranch, fbranch)
- enum operator op;
- struct expression *bexp;
- struct expression *tbranch;
- struct expression *fbranch;
-{
- struct expression *args[3];
-
- args[0] = bexp;
- args[1] = tbranch;
- args[2] = fbranch;
- return new_exp (3, op, args);
-}
-
-%}
-
-/* This declares that all operators have the same associativity and the
- precedence order as in C. See [Harbison, Steele: C, A Reference Manual].
- There is no unary minus and no bitwise operators.
- Operators with the same syntactic behaviour have been merged into a single
- token, to save space in the array generated by bison. */
-%right '?' /* ? */
-%left '|' /* || */
-%left '&' /* && */
-%left EQUOP2 /* == != */
-%left CMPOP2 /* < > <= >= */
-%left ADDOP2 /* + - */
-%left MULOP2 /* * / % */
-%right '!' /* ! */
-
-%token <op> EQUOP2 CMPOP2 ADDOP2 MULOP2
-%token <num> NUMBER
-%type <exp> exp
-
-%%
-
-start: exp
- {
- if ($1 == NULL)
- YYABORT;
- ((struct parse_args *) arg)->res = $1;
- }
- ;
-
-exp: exp '?' exp ':' exp
- {
- $$ = new_exp_3 (qmop, $1, $3, $5);
- }
- | exp '|' exp
- {
- $$ = new_exp_2 (lor, $1, $3);
- }
- | exp '&' exp
- {
- $$ = new_exp_2 (land, $1, $3);
- }
- | exp EQUOP2 exp
- {
- $$ = new_exp_2 ($2, $1, $3);
- }
- | exp CMPOP2 exp
- {
- $$ = new_exp_2 ($2, $1, $3);
- }
- | exp ADDOP2 exp
- {
- $$ = new_exp_2 ($2, $1, $3);
- }
- | exp MULOP2 exp
- {
- $$ = new_exp_2 ($2, $1, $3);
- }
- | '!' exp
- {
- $$ = new_exp_1 (lnot, $2);
- }
- | 'n'
- {
- $$ = new_exp_0 (var);
- }
- | NUMBER
- {
- if (($$ = new_exp_0 (num)) != NULL)
- $$->val.num = $1;
- }
- | '(' exp ')'
- {
- $$ = $2;
- }
- ;
-
-%%
-
-void
-internal_function
-FREE_EXPRESSION (exp)
- struct expression *exp;
-{
- if (exp == NULL)
- return;
-
- /* Handle the recursive case. */
- switch (exp->nargs)
- {
- case 3:
- FREE_EXPRESSION (exp->val.args[2]);
- /* FALLTHROUGH */
- case 2:
- FREE_EXPRESSION (exp->val.args[1]);
- /* FALLTHROUGH */
- case 1:
- FREE_EXPRESSION (exp->val.args[0]);
- /* FALLTHROUGH */
- default:
- break;
- }
-
- free (exp);
-}
-
-
-static int
-yylex (lval, pexp)
- YYSTYPE *lval;
- const char **pexp;
-{
- const char *exp = *pexp;
- int result;
-
- while (1)
- {
- if (exp[0] == '\0')
- {
- *pexp = exp;
- return YYEOF;
- }
-
- if (exp[0] != ' ' && exp[0] != '\t')
- break;
-
- ++exp;
- }
-
- result = *exp++;
- switch (result)
- {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- {
- unsigned long int n = result - '0';
- while (exp[0] >= '0' && exp[0] <= '9')
- {
- n *= 10;
- n += exp[0] - '0';
- ++exp;
- }
- lval->num = n;
- result = NUMBER;
- }
- break;
-
- case '=':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = equal;
- result = EQUOP2;
- }
- else
- result = YYERRCODE;
- break;
-
- case '!':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = not_equal;
- result = EQUOP2;
- }
- break;
-
- case '&':
- case '|':
- if (exp[0] == result)
- ++exp;
- else
- result = YYERRCODE;
- break;
-
- case '<':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = less_or_equal;
- }
- else
- lval->op = less_than;
- result = CMPOP2;
- break;
-
- case '>':
- if (exp[0] == '=')
- {
- ++exp;
- lval->op = greater_or_equal;
- }
- else
- lval->op = greater_than;
- result = CMPOP2;
- break;
-
- case '*':
- lval->op = mult;
- result = MULOP2;
- break;
-
- case '/':
- lval->op = divide;
- result = MULOP2;
- break;
-
- case '%':
- lval->op = module;
- result = MULOP2;
- break;
-
- case '+':
- lval->op = plus;
- result = ADDOP2;
- break;
-
- case '-':
- lval->op = minus;
- result = ADDOP2;
- break;
-
- case 'n':
- case '?':
- case ':':
- case '(':
- case ')':
- /* Nothing, just return the character. */
- break;
-
- case ';':
- case '\n':
- case '\0':
- /* Be safe and let the user call this function again. */
- --exp;
- result = YYEOF;
- break;
-
- default:
- result = YYERRCODE;
-#if YYDEBUG != 0
- --exp;
-#endif
- break;
- }
-
- *pexp = exp;
-
- return result;
-}
-
-
-static void
-yyerror (str)
- const char *str;
-{
- /* Do nothing. We don't print error messages here. */
-}
diff --git a/src/audacious/intl/ref-add.sin b/src/audacious/intl/ref-add.sin
deleted file mode 100644
index 3678c28..0000000
--- a/src/audacious/intl/ref-add.sin
+++ /dev/null
@@ -1,31 +0,0 @@
-# Add this package to a list of references stored in a text file.
-#
-# Copyright (C) 2000 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-#
-# Written by Bruno Haible <haible@clisp.cons.org>.
-#
-/^# Packages using this file: / {
- s/# Packages using this file://
- ta
- :a
- s/ @PACKAGE@ / @PACKAGE@ /
- tb
- s/ $/ @PACKAGE@ /
- :b
- s/^/# Packages using this file:/
-}
diff --git a/src/audacious/intl/ref-del.sin b/src/audacious/intl/ref-del.sin
deleted file mode 100644
index 0c12d8e..0000000
--- a/src/audacious/intl/ref-del.sin
+++ /dev/null
@@ -1,26 +0,0 @@
-# Remove this package from a list of references stored in a text file.
-#
-# Copyright (C) 2000 Free Software Foundation, Inc.
-#
-# This program is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Library General Public License as published
-# by the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Library General Public License for more details.
-#
-# You should have received a copy of the GNU Library General Public
-# License along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-#
-# Written by Bruno Haible <haible@clisp.cons.org>.
-#
-/^# Packages using this file: / {
- s/# Packages using this file://
- s/ @PACKAGE@ / /
- s/^/# Packages using this file:/
-}
diff --git a/src/audacious/intl/relocatable.c b/src/audacious/intl/relocatable.c
deleted file mode 100644
index ef522c4..0000000
--- a/src/audacious/intl/relocatable.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/* Provide relocatable packages.
- Copyright (C) 2003 Free Software Foundation, Inc.
- Written by Bruno Haible <bruno@clisp.org>, 2003.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-
-/* Tell glibc's <stdio.h> to provide a prototype for getline().
- This must come before <config.h> because <config.h> may include
- <features.h>, and once <features.h> has been included, it's too late. */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-/* Specification. */
-#include "relocatable.h"
-
-#if ENABLE_RELOCATABLE
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef NO_XMALLOC
-# define xmalloc malloc
-#else
-# include "xmalloc.h"
-#endif
-
-#if DEPENDS_ON_LIBCHARSET
-# include <libcharset.h>
-#endif
-#if DEPENDS_ON_LIBICONV && HAVE_ICONV
-# include <iconv.h>
-#endif
-#if DEPENDS_ON_LIBINTL && ENABLE_NLS
-# include <libintl.h>
-#endif
-
-/* Faked cheap 'bool'. */
-#undef bool
-#undef false
-#undef true
-#define bool int
-#define false 0
-#define true 1
-
-/* Pathname support.
- ISSLASH(C) tests whether C is a directory separator character.
- IS_PATH_WITH_DIR(P) tests whether P contains a directory specification.
- */
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS */
-# define ISSLASH(C) ((C) == '/' || (C) == '\\')
-# define HAS_DEVICE(P) \
- ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
- && (P)[1] == ':')
-# define IS_PATH_WITH_DIR(P) \
- (strchr (P, '/') != NULL || strchr (P, '\\') != NULL || HAS_DEVICE (P))
-# define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE (P) ? 2 : 0)
-#else
- /* Unix */
-# define ISSLASH(C) ((C) == '/')
-# define IS_PATH_WITH_DIR(P) (strchr (P, '/') != NULL)
-# define FILESYSTEM_PREFIX_LEN(P) 0
-#endif
-
-/* Original installation prefix. */
-static char *orig_prefix;
-static size_t orig_prefix_len;
-/* Current installation prefix. */
-static char *curr_prefix;
-static size_t curr_prefix_len;
-/* These prefixes do not end in a slash. Anything that will be concatenated
- to them must start with a slash. */
-
-/* Sets the original and the current installation prefix of this module.
- Relocation simply replaces a pathname starting with the original prefix
- by the corresponding pathname with the current prefix instead. Both
- prefixes should be directory names without trailing slash (i.e. use ""
- instead of "/"). */
-static void
-set_this_relocation_prefix (const char *orig_prefix_arg,
- const char *curr_prefix_arg)
-{
- if (orig_prefix_arg != NULL && curr_prefix_arg != NULL
- /* Optimization: if orig_prefix and curr_prefix are equal, the
- relocation is a nop. */
- && strcmp (orig_prefix_arg, curr_prefix_arg) != 0)
- {
- /* Duplicate the argument strings. */
- char *memory;
-
- orig_prefix_len = strlen (orig_prefix_arg);
- curr_prefix_len = strlen (curr_prefix_arg);
- memory = (char *) xmalloc (orig_prefix_len + 1 + curr_prefix_len + 1);
-#ifdef NO_XMALLOC
- if (memory != NULL)
-#endif
- {
- memcpy (memory, orig_prefix_arg, orig_prefix_len + 1);
- orig_prefix = memory;
- memory += orig_prefix_len + 1;
- memcpy (memory, curr_prefix_arg, curr_prefix_len + 1);
- curr_prefix = memory;
- return;
- }
- }
- orig_prefix = NULL;
- curr_prefix = NULL;
- /* Don't worry about wasted memory here - this function is usually only
- called once. */
-}
-
-/* Sets the original and the current installation prefix of the package.
- Relocation simply replaces a pathname starting with the original prefix
- by the corresponding pathname with the current prefix instead. Both
- prefixes should be directory names without trailing slash (i.e. use ""
- instead of "/"). */
-void
-set_relocation_prefix (const char *orig_prefix_arg, const char *curr_prefix_arg)
-{
- set_this_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
-
- /* Now notify all dependent libraries. */
-#if DEPENDS_ON_LIBCHARSET
- libcharset_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
-#endif
-#if DEPENDS_ON_LIBICONV && HAVE_ICONV && _LIBICONV_VERSION >= 0x0109
- libiconv_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
-#endif
-#if DEPENDS_ON_LIBINTL && ENABLE_NLS && defined libintl_set_relocation_prefix
- libintl_set_relocation_prefix (orig_prefix_arg, curr_prefix_arg);
-#endif
-}
-
-/* Convenience function:
- Computes the current installation prefix, based on the original
- installation prefix, the original installation directory of a particular
- file, and the current pathname of this file. Returns NULL upon failure. */
-#ifdef IN_LIBRARY
-#define compute_curr_prefix local_compute_curr_prefix
-static
-#endif
-const char *
-compute_curr_prefix (const char *orig_installprefix,
- const char *orig_installdir,
- const char *curr_pathname)
-{
- const char *curr_installdir;
- const char *rel_installdir;
-
- if (curr_pathname == NULL)
- return NULL;
-
- /* Determine the relative installation directory, relative to the prefix.
- This is simply the difference between orig_installprefix and
- orig_installdir. */
- if (strncmp (orig_installprefix, orig_installdir, strlen (orig_installprefix))
- != 0)
- /* Shouldn't happen - nothing should be installed outside $(prefix). */
- return NULL;
- rel_installdir = orig_installdir + strlen (orig_installprefix);
-
- /* Determine the current installation directory. */
- {
- const char *p_base = curr_pathname + FILESYSTEM_PREFIX_LEN (curr_pathname);
- const char *p = curr_pathname + strlen (curr_pathname);
- char *q;
-
- while (p > p_base)
- {
- p--;
- if (ISSLASH (*p))
- break;
- }
-
- q = (char *) xmalloc (p - curr_pathname + 1);
-#ifdef NO_XMALLOC
- if (q == NULL)
- return NULL;
-#endif
- memcpy (q, curr_pathname, p - curr_pathname);
- q[p - curr_pathname] = '\0';
- curr_installdir = q;
- }
-
- /* Compute the current installation prefix by removing the trailing
- rel_installdir from it. */
- {
- const char *rp = rel_installdir + strlen (rel_installdir);
- const char *cp = curr_installdir + strlen (curr_installdir);
- const char *cp_base =
- curr_installdir + FILESYSTEM_PREFIX_LEN (curr_installdir);
-
- while (rp > rel_installdir && cp > cp_base)
- {
- bool same = false;
- const char *rpi = rp;
- const char *cpi = cp;
-
- while (rpi > rel_installdir && cpi > cp_base)
- {
- rpi--;
- cpi--;
- if (ISSLASH (*rpi) || ISSLASH (*cpi))
- {
- if (ISSLASH (*rpi) && ISSLASH (*cpi))
- same = true;
- break;
- }
-#if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
- /* Win32, OS/2, DOS - case insignificant filesystem */
- if ((*rpi >= 'a' && *rpi <= 'z' ? *rpi - 'a' + 'A' : *rpi)
- != (*cpi >= 'a' && *cpi <= 'z' ? *cpi - 'a' + 'A' : *cpi))
- break;
-#else
- if (*rpi != *cpi)
- break;
-#endif
- }
- if (!same)
- break;
- /* The last pathname component was the same. opi and cpi now point
- to the slash before it. */
- rp = rpi;
- cp = cpi;
- }
-
- if (rp > rel_installdir)
- /* Unexpected: The curr_installdir does not end with rel_installdir. */
- return NULL;
-
- {
- size_t curr_prefix_len = cp - curr_installdir;
- char *curr_prefix;
-
- curr_prefix = (char *) xmalloc (curr_prefix_len + 1);
-#ifdef NO_XMALLOC
- if (curr_prefix == NULL)
- return NULL;
-#endif
- memcpy (curr_prefix, curr_installdir, curr_prefix_len);
- curr_prefix[curr_prefix_len] = '\0';
-
- return curr_prefix;
- }
- }
-}
-
-#if defined PIC && defined INSTALLDIR
-
-/* Full pathname of shared library, or NULL. */
-static char *shared_library_fullname;
-
-#if defined _WIN32 || defined __WIN32__
-
-/* Determine the full pathname of the shared library when it is loaded. */
-
-BOOL WINAPI
-DllMain (HINSTANCE module_handle, DWORD event, LPVOID reserved)
-{
- (void) reserved;
-
- if (event == DLL_PROCESS_ATTACH)
- {
- /* The DLL is being loaded into an application's address range. */
- static char location[MAX_PATH];
-
- if (!GetModuleFileName (module_handle, location, sizeof (location)))
- /* Shouldn't happen. */
- return FALSE;
-
- if (!IS_PATH_WITH_DIR (location))
- /* Shouldn't happen. */
- return FALSE;
-
- shared_library_fullname = strdup (location);
- }
-
- return TRUE;
-}
-
-#else /* Unix */
-
-static void
-find_shared_library_fullname ()
-{
-#ifdef __linux__
- FILE *fp;
-
- /* Open the current process' maps file. It describes one VMA per line. */
- fp = fopen ("/proc/self/maps", "r");
- if (fp)
- {
- unsigned long address = (unsigned long) &find_shared_library_fullname;
- for (;;)
- {
- unsigned long start, end;
- int c;
-
- if (fscanf (fp, "%lx-%lx", &start, &end) != 2)
- break;
- if (address >= start && address <= end - 1)
- {
- /* Found it. Now see if this line contains a filename. */
- while (c = getc (fp), c != EOF && c != '\n' && c != '/')
- continue;
- if (c == '/')
- {
- size_t size;
- int len;
-
- ungetc (c, fp);
- shared_library_fullname = NULL; size = 0;
- len = getline (&shared_library_fullname, &size, fp);
- if (len >= 0)
- {
- /* Success: filled shared_library_fullname. */
- if (len > 0 && shared_library_fullname[len - 1] == '\n')
- shared_library_fullname[len - 1] = '\0';
- }
- }
- break;
- }
- while (c = getc (fp), c != EOF && c != '\n')
- continue;
- }
- fclose (fp);
- }
-#endif
-}
-
-#endif /* WIN32 / Unix */
-
-/* Return the full pathname of the current shared library.
- Return NULL if unknown.
- Guaranteed to work only on Linux and Woe32. */
-static char *
-get_shared_library_fullname ()
-{
-#if !(defined _WIN32 || defined __WIN32__)
- static bool tried_find_shared_library_fullname;
- if (!tried_find_shared_library_fullname)
- {
- find_shared_library_fullname ();
- tried_find_shared_library_fullname = true;
- }
-#endif
- return shared_library_fullname;
-}
-
-#endif /* PIC */
-
-/* Returns the pathname, relocated according to the current installation
- directory. */
-const char *
-relocate (const char *pathname)
-{
-#if defined PIC && defined INSTALLDIR
- static int initialized;
-
- /* Initialization code for a shared library. */
- if (!initialized)
- {
- /* At this point, orig_prefix and curr_prefix likely have already been
- set through the main program's set_program_name_and_installdir
- function. This is sufficient in the case that the library has
- initially been installed in the same orig_prefix. But we can do
- better, to also cover the cases that 1. it has been installed
- in a different prefix before being moved to orig_prefix and (later)
- to curr_prefix, 2. unlike the program, it has not moved away from
- orig_prefix. */
- const char *orig_installprefix = INSTALLPREFIX;
- const char *orig_installdir = INSTALLDIR;
- const char *curr_prefix_better;
-
- curr_prefix_better =
- compute_curr_prefix (orig_installprefix, orig_installdir,
- get_shared_library_fullname ());
- if (curr_prefix_better == NULL)
- curr_prefix_better = curr_prefix;
-
- set_relocation_prefix (orig_installprefix, curr_prefix_better);
-
- initialized = 1;
- }
-#endif
-
- /* Note: It is not necessary to perform case insensitive comparison here,
- even for DOS-like filesystems, because the pathname argument was
- typically created from the same Makefile variable as orig_prefix came
- from. */
- if (orig_prefix != NULL && curr_prefix != NULL
- && strncmp (pathname, orig_prefix, orig_prefix_len) == 0)
- {
- if (pathname[orig_prefix_len] == '\0')
- /* pathname equals orig_prefix. */
- return curr_prefix;
- if (ISSLASH (pathname[orig_prefix_len]))
- {
- /* pathname starts with orig_prefix. */
- const char *pathname_tail = &pathname[orig_prefix_len];
- char *result =
- (char *) xmalloc (curr_prefix_len + strlen (pathname_tail) + 1);
-
-#ifdef NO_XMALLOC
- if (result != NULL)
-#endif
- {
- memcpy (result, curr_prefix, curr_prefix_len);
- g_strlcpy (result + curr_prefix_len, pathname_tail, strlen(pathname_tail) + 1);
- return result;
- }
- }
- }
- /* Nothing to relocate. */
- return pathname;
-}
-
-#endif
diff --git a/src/audacious/intl/relocatable.h b/src/audacious/intl/relocatable.h
deleted file mode 100644
index 9ce6362..0000000
--- a/src/audacious/intl/relocatable.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* Provide relocatable packages.
- Copyright (C) 2003 Free Software Foundation, Inc.
- Written by Bruno Haible <bruno@clisp.org>, 2003.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifndef _RELOCATABLE_H
-#define _RELOCATABLE_H
-
-/* This can be enabled through the configure --enable-relocatable option. */
-#if ENABLE_RELOCATABLE
-
-/* When building a DLL, we must export some functions. Note that because
- this is a private .h file, we don't need to use __declspec(dllimport)
- in any case. */
-#if defined _MSC_VER && BUILDING_DLL
-# define RELOCATABLE_DLL_EXPORTED __declspec(dllexport)
-#else
-# define RELOCATABLE_DLL_EXPORTED
-#endif
-
-/* Sets the original and the current installation prefix of the package.
- Relocation simply replaces a pathname starting with the original prefix
- by the corresponding pathname with the current prefix instead. Both
- prefixes should be directory names without trailing slash (i.e. use ""
- instead of "/"). */
-extern RELOCATABLE_DLL_EXPORTED void
- set_relocation_prefix (const char *orig_prefix,
- const char *curr_prefix);
-
-/* Returns the pathname, relocated according to the current installation
- directory. */
-extern const char * relocate (const char *pathname);
-
-/* Memory management: relocate() leaks memory, because it has to construct
- a fresh pathname. If this is a problem because your program calls
- relocate() frequently, think about caching the result. */
-
-/* Convenience function:
- Computes the current installation prefix, based on the original
- installation prefix, the original installation directory of a particular
- file, and the current pathname of this file. Returns NULL upon failure. */
-extern const char * compute_curr_prefix (const char *orig_installprefix,
- const char *orig_installdir,
- const char *curr_pathname);
-
-#else
-
-/* By default, we use the hardwired pathnames. */
-#define relocate(pathname) (pathname)
-
-#endif
-
-#endif /* _RELOCATABLE_H */
diff --git a/src/audacious/intl/textdomain.c b/src/audacious/intl/textdomain.c
deleted file mode 100644
index 6d3c192..0000000
--- a/src/audacious/intl/textdomain.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/* Implementation of the textdomain(3) function.
- Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU Library General Public License as published
- by the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Library General Public License for more details.
-
- You should have received a copy of the GNU Library General Public
- License along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef _LIBC
-# include <libintl.h>
-#else
-# include "libgnuintl.h"
-#endif
-#include "gettextP.h"
-
-#ifdef _LIBC
-/* We have to handle multi-threaded applications. */
-# include <bits/libc-lock.h>
-#else
-/* Provide dummy implementation if this is outside glibc. */
-# define __libc_rwlock_define(CLASS, NAME)
-# define __libc_rwlock_wrlock(NAME)
-# define __libc_rwlock_unlock(NAME)
-#endif
-
-/* The internal variables in the standalone libintl.a must have different
- names than the internal variables in GNU libc, otherwise programs
- using libintl.a cannot be linked statically. */
-#if !defined _LIBC
-# define _nl_default_default_domain libintl_nl_default_default_domain
-# define _nl_current_default_domain libintl_nl_current_default_domain
-#endif
-
-/* @@ end of prolog @@ */
-
-/* Name of the default text domain. */
-extern const char _nl_default_default_domain[] attribute_hidden;
-
-/* Default text domain in which entries for gettext(3) are to be found. */
-extern const char *_nl_current_default_domain attribute_hidden;
-
-
-/* Names for the libintl functions are a problem. They must not clash
- with existing names and they should follow ANSI C. But this source
- code is also used in GNU C Library where the names have a __
- prefix. So we have to make a difference here. */
-#ifdef _LIBC
-# define TEXTDOMAIN __textdomain
-# ifndef strdup
-# define strdup(str) __strdup (str)
-# endif
-#else
-# define TEXTDOMAIN libintl_textdomain
-#endif
-
-/* Lock variable to protect the global data in the gettext implementation. */
-__libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
-
-/* Set the current default message catalog to DOMAINNAME.
- If DOMAINNAME is null, return the current default.
- If DOMAINNAME is "", reset to the default of "messages". */
-char *
-TEXTDOMAIN (domainname)
- const char *domainname;
-{
- char *new_domain;
- char *old_domain;
-
- /* A NULL pointer requests the current setting. */
- if (domainname == NULL)
- return (char *) _nl_current_default_domain;
-
- __libc_rwlock_wrlock (_nl_state_lock);
-
- old_domain = (char *) _nl_current_default_domain;
-
- /* If domain name is the null string set to default domain "messages". */
- if (domainname[0] == '\0'
- || strcmp (domainname, _nl_default_default_domain) == 0)
- {
- _nl_current_default_domain = _nl_default_default_domain;
- new_domain = (char *) _nl_current_default_domain;
- }
- else if (strcmp (domainname, old_domain) == 0)
- /* This can happen and people will use it to signal that some
- environment variable changed. */
- new_domain = old_domain;
- else
- {
- /* If the following malloc fails `_nl_current_default_domain'
- will be NULL. This value will be returned and so signals we
- are out of core. */
-#if defined _LIBC || defined HAVE_STRDUP
- new_domain = strdup (domainname);
-#else
- size_t len = strlen (domainname) + 1;
- new_domain = (char *) malloc (len);
- if (new_domain != NULL)
- memcpy (new_domain, domainname, len);
-#endif
-
- if (new_domain != NULL)
- _nl_current_default_domain = new_domain;
- }
-
- /* We use this possibility to signal a change of the loaded catalogs
- since this is most likely the case and there is no other easy we
- to do it. Do it only when the call was successful. */
- if (new_domain != NULL)
- {
- ++_nl_msg_cat_cntr;
-
- if (old_domain != new_domain && old_domain != _nl_default_default_domain)
- free (old_domain);
- }
-
- __libc_rwlock_unlock (_nl_state_lock);
-
- return new_domain;
-}
-
-#ifdef _LIBC
-/* Alias for function name in GNU C Library. */
-weak_alias (__textdomain, textdomain);
-#endif
diff --git a/src/audacious/main.c b/src/audacious/main.c
index 3ce7c91..1d0ffce 100644
--- a/src/audacious/main.c
+++ b/src/audacious/main.c
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2007 Audacious development team.
+ * Copyright (C) 2005-2011 Audacious development team.
*
* Based on BMP:
* Copyright (C) 2003-2004 BMP development team.
@@ -23,53 +23,57 @@
* Audacious or using our public API to be a derived work.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include <errno.h>
+#include <limits.h>
#include <gtk/gtk.h>
-#include "main.h"
-
-#include <glib/gprintf.h>
-
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
#include <libaudtag/audtag.h>
+#include "config.h"
+
#ifdef USE_DBUS
-# include "dbus-service.h"
-# include "audctrl.h"
+#include "audctrl.h"
+#include "dbus-service.h"
#endif
#ifdef USE_EGGSM
-#include "eggsmclient.h"
#include "eggdesktopfile.h"
+#include "eggsmclient.h"
#endif
#include "audconfig.h"
-#include "chardet.h"
-#include "compatibility.h"
#include "configdb.h"
#include "debug.h"
#include "drct.h"
#include "equalizer.h"
+#include "glib-compat.h"
#include "i18n.h"
#include "interface.h"
-#include "output.h"
+#include "misc.h"
#include "playback.h"
#include "playlist.h"
-#include "pluginenum.h"
-#include "signals.h"
+#include "plugins.h"
#include "util.h"
-#include "visualization.h"
-#define AUTOSAVE_INTERVAL 300 /* seconds */
+/* chardet.c */
+void chardet_init (void);
-static const gchar *application_name = N_("Audacious");
+/* mpris-signals.c */
+void mpris_signals_init (void);
+void mpris_signals_cleanup (void);
-struct _AudCmdLineOpt
-{
+/* signals.c */
+void signals_init (void);
+
+/* smclient.c */
+void smclient_init (void);
+
+#define AUTOSAVE_INTERVAL 300 /* seconds */
+
+static struct {
gchar **filenames;
gint session;
gboolean play, stop, pause, fwd, rew, play_pause, show_jump_box;
@@ -77,78 +81,166 @@ struct _AudCmdLineOpt
gboolean enqueue_to_temp;
gboolean version;
gchar *previous_session_id;
-};
-typedef struct _AudCmdLineOpt AudCmdLineOpt;
+} options;
-static AudCmdLineOpt options;
+static gchar * aud_paths[AUD_PATH_COUNT];
-gchar * aud_paths[BMP_PATH_COUNT];
-
-#ifdef USE_DBUS
-MprisPlayer *mpris;
-MprisTrackList *mpris_tracklist;
+static void make_dirs(void)
+{
+#ifdef S_IRGRP
+ const mode_t mode755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+#else
+ const mode_t mode755 = S_IRWXU;
#endif
-static void print_version(void)
+ make_directory(aud_paths[AUD_PATH_USER_DIR], mode755);
+ make_directory(aud_paths[AUD_PATH_USER_PLUGIN_DIR], mode755);
+ make_directory(aud_paths[AUD_PATH_PLAYLISTS_DIR], mode755);
+}
+
+static void normalize_path (gchar * path)
{
- g_printf("%s %s (%s)\n", _(application_name), VERSION, BUILDSTAMP);
+#ifdef _WIN32
+ string_replace_char (path, '/', '\\');
+#endif
+ gint len = strlen (path);
+#ifdef _WIN32
+ if (len > 3 && path[len - 1] == '\\') /* leave "C:\" */
+#else
+ if (len > 1 && path[len - 1] == '/') /* leave leading "/" */
+#endif
+ path[len - 1] = 0;
}
-static void aud_make_user_dir(void)
+static gchar * last_path_element (gchar * path)
{
- const mode_t mode755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ gchar * slash = strrchr (path, G_DIR_SEPARATOR);
+ return (slash && slash[1]) ? slash + 1 : NULL;
+}
- make_directory(aud_paths[BMP_PATH_USER_DIR], mode755);
- make_directory(aud_paths[BMP_PATH_USER_PLUGIN_DIR], mode755);
- make_directory(aud_paths[BMP_PATH_USER_SKIN_DIR], mode755);
- make_directory(aud_paths[BMP_PATH_SKIN_THUMB_DIR], mode755);
- make_directory(aud_paths[BMP_PATH_PLAYLISTS_DIR], mode755);
+static void strip_path_element (gchar * path, gchar * elem)
+{
+#ifdef _WIN32
+ if (elem > path + 3)
+#else
+ if (elem > path + 1)
+#endif
+ elem[-1] = 0; /* overwrite slash */
+ else
+ elem[0] = 0; /* leave [drive letter and] leading slash */
}
-static void aud_free_paths(void)
+static void relocate_path (gchar * * pathp, const gchar * old, const gchar * new)
{
- gint i;
+ gchar * path = * pathp;
+ gint len = strlen (old);
- for (i = 0; i < BMP_PATH_COUNT; i++)
+#ifdef _WIN32
+ if (strncasecmp (path, old, len))
+#else
+ if (strncmp (path, old, len))
+#endif
{
- g_free(aud_paths[i]);
- aud_paths[i] = 0;
+ fprintf (stderr, "Failed to relocate a data path. Falling back to "
+ "compile-time path: %s\n", path);
+ return;
}
+
+ * pathp = g_strconcat (new, path + len, NULL);
+ g_free (path);
}
-static void aud_init_paths()
+static void relocate_paths (void)
{
- gchar *xdg_config_home;
- gchar *xdg_data_home;
- gchar *xdg_cache_home;
-
- xdg_config_home = (getenv ("XDG_CONFIG_HOME") == NULL) ? g_build_filename
- (getenv ("HOME"), ".config", NULL) : g_strdup (getenv ("XDG_CONFIG_HOME"));
- xdg_data_home = (getenv ("XDG_DATA_HOME") == NULL) ? g_build_filename
- (getenv ("HOME"), ".local", "share", NULL) : g_strdup (getenv
- ("XDG_DATA_HOME"));
- xdg_cache_home = (getenv ("XDG_CACHE_HOME") == NULL) ? g_build_filename
- (getenv ("HOME"), ".cache", NULL) : g_strdup (getenv ("XDG_CACHE_HOME"));
-
- aud_paths[BMP_PATH_USER_DIR] = g_build_filename(xdg_config_home, "audacious", NULL);
- aud_paths[BMP_PATH_USER_SKIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Skins", NULL);
- aud_paths[BMP_PATH_USER_PLUGIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Plugins", NULL);
+ /* Start with the paths hard coded at compile time. */
+ aud_paths[AUD_PATH_BIN_DIR] = g_strdup (HARDCODE_BINDIR);
+ aud_paths[AUD_PATH_DATA_DIR] = g_strdup (HARDCODE_DATADIR);
+ aud_paths[AUD_PATH_PLUGIN_DIR] = g_strdup (HARDCODE_PLUGINDIR);
+ aud_paths[AUD_PATH_LOCALE_DIR] = g_strdup (HARDCODE_LOCALEDIR);
+ aud_paths[AUD_PATH_DESKTOP_FILE] = g_strdup (HARDCODE_DESKTOPFILE);
+ aud_paths[AUD_PATH_ICON_FILE] = g_strdup (HARDCODE_ICONFILE);
+ normalize_path (aud_paths[AUD_PATH_BIN_DIR]);
+ normalize_path (aud_paths[AUD_PATH_DATA_DIR]);
+ normalize_path (aud_paths[AUD_PATH_PLUGIN_DIR]);
+ normalize_path (aud_paths[AUD_PATH_LOCALE_DIR]);
+ normalize_path (aud_paths[AUD_PATH_DESKTOP_FILE]);
+ normalize_path (aud_paths[AUD_PATH_ICON_FILE]);
+
+ /* Compare the compile-time path to the executable and the actual path to
+ * see if we have been moved. */
+ gchar * old = g_strdup (aud_paths[AUD_PATH_BIN_DIR]);
+ gchar * new = get_path_to_self ();
+ if (! new)
+ {
+ERR:
+ g_free (old);
+ g_free (new);
+ return;
+ }
+ normalize_path (new);
+
+ /* Strip the name of the executable file, leaving the path. */
+ gchar * base = last_path_element (new);
+ if (! base)
+ goto ERR;
+ strip_path_element (new, base);
+
+ /* Strip innermost folder names from both paths as long as they match. This
+ * leaves a compile-time prefix and a run-time one to replace it with. */
+ gchar * a, * b;
+ while ((a = last_path_element (old)) && (b = last_path_element (new)) &&
+#ifdef _WIN32
+ ! strcasecmp (a, b))
+#else
+ ! strcmp (a, b))
+#endif
+ {
+ strip_path_element (old, a);
+ strip_path_element (new, b);
+ }
- aud_paths[BMP_PATH_SKIN_THUMB_DIR] = g_build_filename(xdg_cache_home, "audacious", "thumbs", NULL);
+ /* Do the replacements. */
+ relocate_path (& aud_paths[AUD_PATH_BIN_DIR], old, new);
+ relocate_path (& aud_paths[AUD_PATH_DATA_DIR], old, new);
+ relocate_path (& aud_paths[AUD_PATH_PLUGIN_DIR], old, new);
+ relocate_path (& aud_paths[AUD_PATH_LOCALE_DIR], old, new);
+ relocate_path (& aud_paths[AUD_PATH_DESKTOP_FILE], old, new);
+ relocate_path (& aud_paths[AUD_PATH_ICON_FILE], old, new);
- aud_paths[BMP_PATH_PLAYLISTS_DIR] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlists", NULL);
+ g_free (old);
+ g_free (new);
+}
- aud_paths[BMP_PATH_CONFIG_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "config", NULL);
- aud_paths[BMP_PATH_PLAYLIST_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "playlist.xspf", NULL);
- aud_paths[BMP_PATH_ACCEL_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "accels", NULL);
+static void init_paths (void)
+{
+ relocate_paths ();
+
+ const gchar * xdg_config_home = g_get_user_config_dir ();
+ const gchar * xdg_data_home = g_get_user_data_dir ();
+
+#ifdef _WIN32
+ /* Some libraries (libmcs) and plugins (filewriter) use these variables,
+ * which are generally not set on Windows. */
+ g_setenv ("HOME", g_get_home_dir (), TRUE);
+ g_setenv ("XDG_CONFIG_HOME", xdg_config_home, TRUE);
+ g_setenv ("XDG_DATA_HOME", xdg_data_home, TRUE);
+ g_setenv ("XDG_CACHE_HOME", g_get_user_cache_dir (), TRUE);
+#endif
- aud_paths[BMP_PATH_GTKRC_FILE] = g_build_filename(aud_paths[BMP_PATH_USER_DIR], "gtkrc", NULL);
+ aud_paths[AUD_PATH_USER_DIR] = g_build_filename(xdg_config_home, "audacious", NULL);
+ aud_paths[AUD_PATH_USER_PLUGIN_DIR] = g_build_filename(xdg_data_home, "audacious", "Plugins", NULL);
+ aud_paths[AUD_PATH_PLAYLISTS_DIR] = g_build_filename(aud_paths[AUD_PATH_USER_DIR], "playlists", NULL);
+ aud_paths[AUD_PATH_PLAYLIST_FILE] = g_build_filename(aud_paths[AUD_PATH_USER_DIR], "playlist.xspf", NULL);
+ aud_paths[AUD_PATH_GTKRC_FILE] = g_build_filename(aud_paths[AUD_PATH_USER_DIR], "gtkrc", NULL);
- g_free(xdg_config_home);
- g_free(xdg_data_home);
- g_free(xdg_cache_home);
+ for (gint i = 0; i < AUD_PATH_COUNT; i ++)
+ AUDDBG ("Data path: %s\n", aud_paths[i]);
+}
- g_atexit(aud_free_paths);
+const gchar * get_path (gint id)
+{
+ g_return_val_if_fail (id >= 0 && id < AUD_PATH_COUNT, NULL);
+ return aud_paths[id];
}
static GOptionEntry cmd_entries[] = {
@@ -169,12 +261,12 @@ static GOptionEntry cmd_entries[] = {
{NULL},
};
-static void parse_cmd_line_options(gint * argc, gchar *** argv)
+static void parse_options (gint * argc, gchar *** argv)
{
GOptionContext *context;
GError *error = NULL;
- memset(&options, '\0', sizeof(AudCmdLineOpt));
+ memset (& options, 0, sizeof options);
options.session = -1;
context = g_option_context_new(_("- play multimedia files"));
@@ -185,123 +277,159 @@ static void parse_cmd_line_options(gint * argc, gchar *** argv)
#endif
if (!g_option_context_parse(context, argc, argv, &error))
- /* checking for MacOS X -psn_0_* errors */
- if (error->message && !g_strrstr(error->message, "-psn_0_"))
- {
- g_printerr(_("%s: %s\nTry `%s --help' for more information.\n"), (*argv)[0], error->message, (*argv)[0]);
- exit(EXIT_FAILURE);
- }
+ {
+ fprintf (stderr,
+ _("%s: %s\nTry `%s --help' for more information.\n"), (* argv)[0],
+ error->message, (* argv)[0]);
+ exit (EXIT_FAILURE);
+ }
g_option_context_free (context);
}
-static void handle_cmd_line_filenames(gboolean is_running)
+static gboolean get_lock (void)
{
- gint i;
- gchar *working, **filenames = options.filenames;
- GList * fns = NULL;
-#ifdef USE_DBUS
- DBusGProxy *session = audacious_get_dbus_proxy();
-#endif
+ gchar path[PATH_MAX];
+ snprintf (path, sizeof path, "%s" G_DIR_SEPARATOR_S "lock",
+ aud_paths[AUD_PATH_USER_DIR]);
- if (filenames == NULL)
- return;
+ int handle = open (path, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
- working = g_get_current_dir();
- for (i = 0; filenames[i] != NULL; i++)
+ if (handle < 0)
{
- gchar * uri;
+ if (errno != EEXIST)
+ fprintf (stderr, "Cannot create %s: %s.\n", path, strerror (errno));
+ return FALSE;
+ }
- if (strstr (filenames[i], "://"))
- uri = g_strdup (filenames[i]);
- else if (g_path_is_absolute (filenames[i]))
- uri = filename_to_uri (filenames[i]);
- else
- {
- gchar * absolute = g_build_filename (working, filenames[i], NULL);
- uri = filename_to_uri (absolute);
- g_free (absolute);
- }
+ close (handle);
+ return TRUE;
+}
- fns = g_list_prepend(fns, uri);
- }
- fns = g_list_reverse(fns);
- g_free(working);
+static void release_lock (void)
+{
+ gchar path[PATH_MAX];
+ snprintf (path, sizeof path, "%s" G_DIR_SEPARATOR_S "lock",
+ aud_paths[AUD_PATH_USER_DIR]);
-#ifdef USE_DBUS
- if (is_running)
- {
- if (options.enqueue_to_temp)
- audacious_remote_playlist_open_list_to_temp (session, fns);
- else if (options.enqueue)
- audacious_remote_playlist_add (session, fns);
- else
- audacious_remote_playlist_open_list (session, fns);
- }
- else /* !is_running */
-#endif
+ unlink (path);
+}
+
+static GList * convert_filenames (void)
+{
+ if (! options.filenames)
+ return NULL;
+
+ gchar * * f = options.filenames;
+ GList * list = NULL;
+ gchar * cur = g_get_current_dir ();
+
+ for (gint i = 0; f[i]; i ++)
{
- if (options.enqueue_to_temp)
- {
- drct_pl_open_temp_list (fns);
- cfg.resume_state = 0;
- }
- else if (options.enqueue)
- drct_pl_add_list (fns, -1);
+ gchar * uri;
+
+ if (strstr (f[i], "://"))
+ uri = g_strdup (f[i]);
+ else if (g_path_is_absolute (f[i]))
+ uri = filename_to_uri (f[i]);
else
{
- drct_pl_open_list (fns);
- cfg.resume_state = 0;
+ gchar * tmp = g_build_filename (cur, f[i], NULL);
+ uri = filename_to_uri (tmp);
+ g_free (tmp);
}
- } /* !is_running */
- g_list_foreach(fns, (GFunc) g_free, NULL);
- g_list_free(fns);
+ list = g_list_prepend (list, uri);
+ }
+
+ g_free (cur);
+ return g_list_reverse (list);
}
-static void handle_cmd_line_options_first(void)
+static void do_remote (void)
{
#ifdef USE_DBUS
- DBusGProxy *session;
-#endif
+ DBusGProxy * session = audacious_get_dbus_proxy ();
- if (options.version)
+ if (session && audacious_remote_is_running (session))
{
- print_version();
- exit(EXIT_SUCCESS);
- }
+ GList * list = convert_filenames ();
+
+ if (list)
+ {
+ if (options.enqueue_to_temp)
+ audacious_remote_playlist_open_list_to_temp (session, list);
+ else if (options.enqueue)
+ audacious_remote_playlist_add (session, list);
+ else
+ audacious_remote_playlist_open_list (session, list);
+
+ g_list_foreach (list, (GFunc) g_free, NULL);
+ g_list_free (list);
+ }
-#ifdef USE_DBUS
- session = audacious_get_dbus_proxy();
- if (audacious_remote_is_running(session))
- {
- handle_cmd_line_filenames(TRUE);
- if (options.rew)
- audacious_remote_playlist_prev(session);
if (options.play)
- audacious_remote_play(session);
+ audacious_remote_play (session);
if (options.pause)
- audacious_remote_pause(session);
+ audacious_remote_pause (session);
+ if (options.play_pause)
+ audacious_remote_play_pause (session);
if (options.stop)
- audacious_remote_stop(session);
+ audacious_remote_stop (session);
+ if (options.rew)
+ audacious_remote_playlist_prev (session);
if (options.fwd)
- audacious_remote_playlist_next(session);
- if (options.play_pause)
- audacious_remote_play_pause(session);
+ audacious_remote_playlist_next (session);
if (options.show_jump_box)
- audacious_remote_show_jtf_box(session);
- if (options.mainwin)
- audacious_remote_main_win_toggle(session, 1);
+ audacious_remote_show_jtf_box (session);
if (options.activate)
- audacious_remote_activate(session);
- exit(EXIT_SUCCESS);
+ audacious_remote_activate (session);
+ if (options.mainwin)
+ audacious_remote_main_win_toggle (session, TRUE);
+
+ exit (EXIT_SUCCESS);
}
#endif
+
+ GtkWidget * dialog = gtk_message_dialog_new (NULL, 0, GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK_CANCEL, _("Audacious seems to be already running but is "
+ "not responding. You can start another instance of the program, but "
+ "please be warned that this can cause data loss. If Audacious is not "
+ "running, you can safely ignore this message. Press OK to start "
+ "Audacious or Cancel to quit."));
+
+ g_signal_connect (dialog, "destroy", (GCallback) gtk_widget_destroyed,
+ & dialog);
+
+ if (gtk_dialog_run ((GtkDialog *) dialog) != GTK_RESPONSE_OK)
+ exit (EXIT_FAILURE);
+
+ if (dialog)
+ gtk_widget_destroy (dialog);
}
-static void handle_cmd_line_options(void)
+static void do_commands (void)
{
- handle_cmd_line_filenames(FALSE);
+ GList * list = convert_filenames ();
+
+ if (list)
+ {
+ if (options.enqueue_to_temp)
+ {
+ drct_pl_open_temp_list (list);
+ cfg.resume_state = 0;
+ }
+ else if (options.enqueue)
+ drct_pl_add_list (list, -1);
+ else
+ {
+ drct_pl_open_list (list);
+ cfg.resume_state = 0;
+ }
+
+ g_list_foreach (list, (GFunc) g_free, NULL);
+ g_list_free (list);
+ }
if (cfg.resume_playback_on_startup && cfg.resume_state > 0)
playback_play (cfg.resume_playback_on_startup_time, cfg.resume_state ==
@@ -321,199 +449,129 @@ static void handle_cmd_line_options(void)
interface_toggle_visibility ();
}
-void aud_quit (void)
+static void init_one (gint * p_argc, gchar * * * p_argv)
{
- AUDDBG ("Ending main loop.\n");
- gtk_main_quit ();
-}
-
-static void shut_down (void)
-{
- AUDDBG ("Saving configuration.\n");
- aud_config_save();
- save_playlists ();
-
- if (playback_get_playing ())
- playback_stop ();
-
- AUDDBG ("Shutting down user interface subsystem.\n");
- interface_unload ();
-
- output_cleanup ();
-
- AUDDBG ("Plugin subsystem shutdown.\n");
- plugin_system_cleanup();
+ init_paths ();
+ make_dirs ();
- cfg_db_flush (); /* must be after plugin cleanup */
+ bindtextdomain (PACKAGE_NAME, aud_paths[AUD_PATH_LOCALE_DIR]);
+ bind_textdomain_codeset (PACKAGE_NAME, "UTF-8");
+ bindtextdomain (PACKAGE_NAME "-plugins", aud_paths[AUD_PATH_LOCALE_DIR]);
+ bind_textdomain_codeset (PACKAGE_NAME "-plugins", "UTF-8");
+ textdomain (PACKAGE_NAME);
- AUDDBG ("Playlist cleanup.\n");
- playlist_end();
-}
+ mowgli_init ();
+ chardet_init ();
-#ifdef USE_DBUS
-static void mpris_status_cb1(gpointer hook_data, gpointer user_data)
-{
- mpris_emit_status_change(mpris, GPOINTER_TO_INT(user_data));
-}
+ g_thread_init (NULL);
+ gdk_threads_init ();
+ gdk_threads_enter ();
-static void mpris_status_cb2(gpointer hook_data, gpointer user_data)
-{
- mpris_emit_status_change(mpris, -1);
-}
+ gtk_rc_add_default_file (aud_paths[AUD_PATH_GTKRC_FILE]);
+ gtk_init (p_argc, p_argv);
-void init_playback_hooks(void)
-{
- hook_associate("playback begin", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PLAY));
- hook_associate("playback pause", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PAUSE));
- hook_associate("playback unpause", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_PLAY));
- hook_associate("playback stop", mpris_status_cb1, GINT_TO_POINTER(MPRIS_STATUS_STOP));
-
- hook_associate("playback shuffle", mpris_status_cb2, NULL);
- hook_associate("playback repeat", mpris_status_cb2, NULL);
- hook_associate("playback no playlist advance", mpris_status_cb2, NULL);
-}
+#ifdef USE_EGGSM
+ egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_NORMAL);
+ egg_set_desktop_file (aud_paths[AUD_PATH_DESKTOP_FILE]);
#endif
-
-static gboolean autosave_cb (void * unused)
-{
- AUDDBG ("Saving configuration.\n");
- aud_config_save ();
- cfg_db_flush ();
- save_playlists ();
- return TRUE;
-}
-
-static PluginHandle * current_iface = NULL;
-
-PluginHandle * iface_plugin_get_active (void)
-{
- return current_iface;
}
-void iface_plugin_set_active (PluginHandle * plugin)
+static void init_two (void)
{
- AUDDBG ("Unloading visualizers.\n");
- vis_cleanup ();
-
- AUDDBG ("Unloading %s.\n", plugin_get_name (current_iface));
- interface_unload ();
+ hook_init ();
+ tag_init ();
- current_iface = plugin;
- interface_set_default (plugin);
+ aud_config_load ();
+ tag_set_verbose (cfg.verbose);
+ vfs_set_verbose (cfg.verbose);
- AUDDBG ("Starting %s.\n", plugin_get_name (plugin));
- if (! interface_load (plugin))
- {
- fprintf (stderr, "%s failed to start.\n", plugin_get_name (plugin));
- exit (EXIT_FAILURE);
- }
-
- AUDDBG ("Loading visualizers.\n");
- vis_init ();
-}
-
-gint main(gint argc, gchar ** argv)
-{
- /* glib-2.13.0 requires g_thread_init() to be called before all
- other GLib functions */
- g_thread_init(NULL);
- if (!g_thread_supported())
- {
- g_printerr(_("Sorry, threads aren't supported on your platform.\n"));
- exit(EXIT_FAILURE);
- }
+ eq_init ();
+ register_interface_hooks ();
- gdk_threads_init();
- mowgli_init();
- chardet_init();
- tag_init();
+#ifdef HAVE_SIGWAIT
+ signals_init ();
+#endif
+#ifdef USE_EGGSM
+ smclient_init ();
+#endif
- hook_init();
- hook_associate ("quit", (HookFunction) gtk_main_quit, NULL);
+ AUDDBG ("Loading lowlevel plugins.\n");
+ start_plugins_one ();
- /* Setup l10n early so we can print localized error messages */
- gtk_set_locale();
- bindtextdomain(PACKAGE_NAME, LOCALEDIR);
- bind_textdomain_codeset(PACKAGE_NAME, "UTF-8");
- bindtextdomain(PACKAGE_NAME "-plugins", LOCALEDIR);
- bind_textdomain_codeset(PACKAGE_NAME "-plugins", "UTF-8");
- textdomain(PACKAGE_NAME);
+ playlist_init ();
+ load_playlists ();
-#if !defined(_WIN32) && defined(USE_EGGSM)
- egg_set_desktop_file(AUDACIOUS_DESKTOP_FILE);
+#ifdef USE_DBUS
+ init_dbus ();
#endif
- aud_init_paths();
- aud_make_user_dir();
- gtk_rc_add_default_file(aud_paths[BMP_PATH_GTKRC_FILE]);
+ do_commands ();
- parse_cmd_line_options(&argc, &argv);
+ AUDDBG ("Loading highlevel plugins.\n");
+ start_plugins_two ();
- if (!gtk_init_check(&argc, &argv))
- { /* XXX */
- /* GTK check failed, and no arguments passed to indicate
- that user is intending to only remote control a running
- session */
- g_printerr(_("%s: Unable to open display, exiting.\n"), argv[0]);
- exit(EXIT_FAILURE);
- }
+ mpris_signals_init ();
+}
- AUDDBG ("Loading configuration.\n");
- aud_config_load();
- atexit (aud_config_free);
+static void shut_down (void)
+{
+ mpris_signals_cleanup ();
- AUDDBG ("Initializing signal handlers.\n");
- signal_handlers_init();
+ AUDDBG ("Capturing state.\n");
+ aud_config_save ();
+ save_playlists ();
- AUDDBG ("Handling commandline options, part #1.\n");
- handle_cmd_line_options_first();
+ AUDDBG ("Unloading highlevel plugins.\n");
+ stop_plugins_two ();
- output_init ();
+ AUDDBG ("Stopping playback.\n");
+ if (playback_get_playing ())
+ playback_stop ();
-#ifdef USE_DBUS
- AUDDBG ("Initializing D-Bus.\n");
- init_dbus();
- init_playback_hooks();
-#endif
+ playlist_end ();
- AUDDBG ("Initializing plugin subsystems.\n");
- plugin_system_init();
+ AUDDBG ("Unloading lowlevel plugins.\n");
+ stop_plugins_one ();
- playlist_init ();
- load_playlists ();
- eq_init ();
+ AUDDBG ("Saving configuration.\n");
+ cfg_db_flush ();
- AUDDBG ("Handling commandline options, part #2.\n");
- handle_cmd_line_options();
+ gdk_threads_leave ();
+}
- AUDDBG ("Registering interface hooks.\n");
- register_interface_hooks();
+static gboolean autosave_cb (void * unused)
+{
+ AUDDBG ("Saving configuration.\n");
+ aud_config_save ();
+ cfg_db_flush ();
+ save_playlists ();
+ return TRUE;
+}
- g_timeout_add_seconds (AUTOSAVE_INTERVAL, autosave_cb, NULL);
+gint main(gint argc, gchar ** argv)
+{
+ init_one (& argc, & argv);
+ parse_options (& argc, & argv);
- if ((current_iface = interface_get_default ()) == NULL)
+ if (options.version)
{
- fprintf (stderr, "No interface plugin found.\n");
- return EXIT_FAILURE;
+ printf ("%s %s (%s)\n", _("Audacious"), VERSION, BUILDSTAMP);
+ return EXIT_SUCCESS;
}
- AUDDBG ("Starting %s.\n", plugin_get_name (current_iface));
- if (! interface_load (current_iface))
- {
- fprintf (stderr, "%s failed to start.\n", plugin_get_name (current_iface));
- return EXIT_FAILURE;
- }
+ if (! get_lock ())
+ do_remote (); /* may exit */
- AUDDBG ("Loading visualizers.\n");
- vis_init ();
+ AUDDBG ("No remote session; starting up.\n");
+ init_two ();
- AUDDBG ("Starting main loop.\n");
- gtk_main ();
+ AUDDBG ("Startup complete.\n");
+ g_timeout_add_seconds (AUTOSAVE_INTERVAL, autosave_cb, NULL);
+ hook_associate ("quit", (HookFunction) gtk_main_quit, NULL);
- AUDDBG ("Unloading visualizers.\n");
- vis_cleanup ();
+ gtk_main ();
- AUDDBG ("Shutting down.\n");
shut_down ();
+ release_lock ();
return EXIT_SUCCESS;
}
diff --git a/src/audacious/main.h b/src/audacious/main.h
deleted file mode 100644
index e280066..0000000
--- a/src/audacious/main.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2007 Audacious development team
- *
- * Based on BMP:
- * Copyright (C) 2003-2004 BMP development team
- *
- * Based on XMMS:
- * Copyright (C) 1998-2003 XMMS development team
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_MAIN_H
-#define AUDACIOUS_MAIN_H
-
-#include <glib.h>
-
-#define NOT_ALPHA_RELEASE
-
-#ifdef USE_DBUS
-#include "dbus-service.h"
-#endif
-
-enum {
- BMP_PATH_USER_DIR,
- BMP_PATH_USER_PLUGIN_DIR,
- BMP_PATH_USER_SKIN_DIR,
- BMP_PATH_SKIN_THUMB_DIR,
- BMP_PATH_PLAYLISTS_DIR,
- BMP_PATH_ACCEL_FILE,
- BMP_PATH_CONFIG_FILE,
- BMP_PATH_PLAYLIST_FILE,
- BMP_PATH_GTKRC_FILE,
- BMP_PATH_COUNT
-};
-
-extern gchar *aud_paths[];
-
-#ifdef USE_DBUS
-extern MprisPlayer *mpris;
-extern MprisTrackList *mpris_tracklist;
-#endif
-
-void aud_quit(void);
-
-#endif /* AUDACIOUS_MAIN_H */
diff --git a/src/audacious/misc-api.h b/src/audacious/misc-api.h
index ec045c5..7dd2a3e 100644
--- a/src/audacious/misc-api.h
+++ b/src/audacious/misc-api.h
@@ -36,9 +36,8 @@ AUD_FUNC2 (gboolean, save_preset_file, EqualizerPreset *, preset, const gchar *,
filename)
AUD_FUNC1 (GList *, import_winamp_eqf, VFSFile *, file)
-/* playlist_container.c */
-AUD_FUNC1 (void, playlist_container_register, PlaylistContainer *, container)
-AUD_FUNC1 (void, playlist_container_unregister, PlaylistContainer *, container)
+/* main.c */
+AUD_FUNC1 (const gchar *, get_path, gint, path)
/* playlist-utils.c */
AUD_FUNC0 (const gchar *, get_gentitle_format)
@@ -49,17 +48,17 @@ AUD_FUNC2 (void, uri_set_plugin, const gchar *, scheme, InputPlugin *, ip)
AUD_FUNC2 (void, mime_set_plugin, const gchar *, mimetype, InputPlugin *, ip)
/* probe.c */
-AUD_FUNC2 (InputPlugin *, file_find_decoder, const gchar *, filename, gboolean,
+AUD_FUNC2 (PluginHandle *, file_find_decoder, const gchar *, filename, gboolean,
fast)
-AUD_FUNC2 (Tuple *, file_read_tuple, const gchar *, filename, InputPlugin *,
+AUD_FUNC2 (Tuple *, file_read_tuple, const gchar *, filename, PluginHandle *,
decoder)
-AUD_FUNC4 (gboolean, file_read_image, const gchar *, filename, InputPlugin *,
+AUD_FUNC4 (gboolean, file_read_image, const gchar *, filename, PluginHandle *,
decoder, void * *, data, gint *, size)
AUD_FUNC2 (gboolean, file_can_write_tuple, const gchar *, filename,
- InputPlugin *, decoder)
-AUD_FUNC3 (gboolean, file_write_tuple, const gchar *, filename, InputPlugin *,
+ PluginHandle *, decoder)
+AUD_FUNC3 (gboolean, file_write_tuple, const gchar *, filename, PluginHandle *,
decoder, const Tuple *, tuple)
-AUD_FUNC2 (gboolean, custom_infowin, const gchar *, filename, InputPlugin *,
+AUD_FUNC2 (gboolean, custom_infowin, const gchar *, filename, PluginHandle *,
decoder)
/* ui_albumart.c */
@@ -92,3 +91,7 @@ AUD_FUNC3 (void, calc_mono_pcm, VisPCMData, buffer, const VisPCMData, data,
gint, channels)
AUD_FUNC3 (void, calc_stereo_pcm, VisPCMData, buffer, const VisPCMData, data,
gint, channels)
+
+/* New in 2.5-alpha2 */
+AUD_FUNC1 (void, interface_install_toolbar, void *, button)
+AUD_FUNC1 (void, interface_uninstall_toolbar, void *, button)
diff --git a/src/audacious/misc.h b/src/audacious/misc.h
index 6a4b673..386f974 100644
--- a/src/audacious/misc.h
+++ b/src/audacious/misc.h
@@ -38,17 +38,26 @@ enum {
AUDACIOUS_MENU_PLAYLIST_MISC,
TOTAL_PLUGIN_MENUS};
+enum {
+ AUD_PATH_BIN_DIR,
+ AUD_PATH_DATA_DIR,
+ AUD_PATH_PLUGIN_DIR,
+ AUD_PATH_LOCALE_DIR,
+ AUD_PATH_DESKTOP_FILE,
+ AUD_PATH_ICON_FILE,
+ AUD_PATH_USER_DIR,
+ AUD_PATH_USER_PLUGIN_DIR,
+ AUD_PATH_PLAYLISTS_DIR,
+ AUD_PATH_PLAYLIST_FILE,
+ AUD_PATH_GTKRC_FILE,
+ AUD_PATH_COUNT
+};
+
typedef struct {
gchar * name;
gfloat preamp, bands[10];
} EqualizerPreset;
-typedef struct {
- const gchar * name, * ext;
- void (* plc_read) (const gchar * filename, gint at);
- void (* plc_write) (const gchar * filename, gint at);
-} PlaylistContainer;
-
typedef gint16 VisFreqData[2][256];
typedef gint16 VisPCMData[2][512];
diff --git a/src/audacious/mpris-signals.c b/src/audacious/mpris-signals.c
new file mode 100644
index 0000000..51dda6b
--- /dev/null
+++ b/src/audacious/mpris-signals.c
@@ -0,0 +1,71 @@
+/* Audacious - Cross-platform multimedia player
+ * Copyright (C) 2005-2011 Audacious development team.
+ *
+ * Based on BMP:
+ * Copyright (C) 2003-2004 BMP development team.
+ *
+ * Based on XMMS:
+ * Copyright (C) 1998-2003 XMMS development team.
+ *
+ * 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; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#ifdef USE_DBUS
+
+#include "dbus-service.h"
+
+static void mpris_status_cb1 (void * hook_data, void * user_data)
+{
+ mpris_emit_status_change (mpris, GPOINTER_TO_INT (user_data));
+}
+
+static void mpris_status_cb2 (void * hook_data, void * user_data)
+{
+ mpris_emit_status_change (mpris, -1);
+}
+#endif
+
+void mpris_signals_init (void)
+{
+#ifdef USE_DBUS
+ hook_associate ("playback begin", mpris_status_cb1, GINT_TO_POINTER
+ (MPRIS_STATUS_PLAY));
+ hook_associate ("playback pause", mpris_status_cb1, GINT_TO_POINTER
+ (MPRIS_STATUS_PAUSE));
+ hook_associate ("playback unpause", mpris_status_cb1, GINT_TO_POINTER
+ (MPRIS_STATUS_PLAY));
+ hook_associate ("playback stop", mpris_status_cb1, GINT_TO_POINTER
+ (MPRIS_STATUS_STOP));
+
+ hook_associate ("toggle shuffle", mpris_status_cb2, NULL);
+ hook_associate ("toggle repeat", mpris_status_cb2, NULL);
+/* hook_associate ("toggle no playlist advance", mpris_status_cb2, NULL); */
+#endif
+}
+
+void mpris_signals_cleanup (void)
+{
+#ifdef USE_DBUS
+ hook_dissociate ("playback begin", mpris_status_cb1);
+ hook_dissociate ("playback pause", mpris_status_cb1);
+ hook_dissociate ("playback unpause", mpris_status_cb1);
+ hook_dissociate ("playback stop", mpris_status_cb1);
+
+ hook_dissociate ("toggle shuffle", mpris_status_cb2, NULL);
+ hook_dissociate ("toggle repeat", mpris_status_cb2, NULL);
+/* hook_dissociate ("toggle no playlist advance", mpris_status_cb2, NULL); */
+#endif
+}
diff --git a/src/audacious/output.c b/src/audacious/output.c
index cfa8572..a38eae3 100644
--- a/src/audacious/output.c
+++ b/src/audacious/output.c
@@ -20,7 +20,6 @@
*/
#include <math.h>
-
#include <libaudcore/audio.h>
#include "audconfig.h"
@@ -34,30 +33,7 @@
#define SW_VOLUME_RANGE 40 /* decibels */
-OutputPlugin * current_output_plugin = NULL;
-#define COP current_output_plugin
-
-static gboolean plugin_list_func (PluginHandle * plugin, GList * * list)
-{
- OutputPlugin * op = plugin_get_header (plugin);
- g_return_val_if_fail (op != NULL, TRUE);
- * list = g_list_prepend (* list, op);
- return TRUE;
-}
-
-GList * get_output_list (void)
-{
- static GList * list = NULL;
-
- if (list == NULL)
- {
- plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc)
- plugin_list_func, & list);
- list = g_list_reverse (list);
- }
-
- return list;
-}
+static OutputPlugin * cop = NULL;
void output_get_volume (gint * l, gint * r)
{
@@ -66,8 +42,8 @@ void output_get_volume (gint * l, gint * r)
* l = cfg.sw_volume_left;
* r = cfg.sw_volume_right;
}
- else if (COP != NULL && COP->get_volume != NULL)
- COP->get_volume (l, r);
+ else if (cop != NULL && cop->get_volume != NULL)
+ cop->get_volume (l, r);
else
{
* l = 0;
@@ -82,98 +58,80 @@ void output_set_volume (gint l, gint r)
cfg.sw_volume_left = l;
cfg.sw_volume_right = r;
}
- else if (COP != NULL && COP->set_volume != NULL)
- COP->set_volume (l, r);
+ else if (cop != NULL && cop->set_volume != NULL)
+ cop->set_volume (l, r);
}
-static GMutex * output_mutex;
-static gboolean output_opened, output_aborted, output_leave_open, output_paused;
+static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+static gboolean locked = FALSE;
-static gint decoder_format, output_format;
-static gint decoder_channels, decoder_rate, effect_channels, effect_rate,
- output_channels, output_rate;
+#define LOCK do {g_static_mutex_lock (& mutex); locked = TRUE;} while (0)
+#define UNLOCK do {locked = FALSE; g_static_mutex_unlock (& mutex);} while (0)
+#define LOCKED g_return_if_fail (locked)
+#define LOCKED_RET(a) g_return_val_if_fail (locked, a)
+#define LOCK_VIS do {vis_runner_lock (); LOCK;} while (0)
+#define UNLOCK_VIS do {UNLOCK; vis_runner_unlock ();} while (0)
+#define LOCKED_VIS g_return_if_fail (locked && vis_runner_locked ())
+#define LOCKED_VIS_RET(a) g_return_val_if_fail (locked && vis_runner_locked (), a)
+
+static gboolean opened = FALSE;
+static gboolean leave_open = FALSE;
+
+static gboolean waiting, aborted, paused;
+static gint decoder_format, decoder_channels, decoder_rate, effect_channels,
+ effect_rate, output_format, output_channels, output_rate;
static gint64 frames_written;
static gboolean have_replay_gain;
static ReplayGainInfo replay_gain_info;
-#define REMOVE_SOURCE(s) \
-do { \
- if (s != 0) { \
- g_source_remove (s); \
- s = 0; \
- } \
-} while (0)
-
-#define LOCK g_mutex_lock (output_mutex)
-#define UNLOCK g_mutex_unlock (output_mutex)
-
-static void write_buffers (void);
-static void drain (void);
-
-/* output_mutex must be locked */
-static void real_close (void)
+static void reset_time (void)
{
- vis_runner_start_stop (FALSE, FALSE);
- COP->close_audio ();
- output_opened = FALSE;
- output_leave_open = FALSE;
+ LOCKED_VIS;
+ g_return_if_fail (cop->set_written_time != NULL);
+ vis_runner_time_offset (- cop->written_time ());
+ cop->set_written_time (0);
}
-void output_init (void)
+static void drain (void)
{
- output_mutex = g_mutex_new ();
- output_opened = FALSE;
- output_leave_open = FALSE;
+ LOCKED;
+ g_return_if_fail (cop->drain != NULL);
+ cop->drain ();
}
-void output_cleanup (void)
+static void real_close (void)
{
- LOCK;
-
- if (output_leave_open)
- real_close ();
-
- UNLOCK;
-
- g_mutex_free (output_mutex);
+ LOCKED_VIS;
+ vis_runner_start_stop (FALSE, FALSE);
+ cop->close_audio ();
+ opened = FALSE;
+ leave_open = FALSE;
}
-static gboolean output_open_audio (gint format, gint rate, gint channels)
+static gboolean open_audio (gint format, gint rate, gint channels)
{
- if (COP == NULL)
- {
- fprintf (stderr, "No output plugin selected.\n");
- return FALSE;
- }
-
- LOCK;
-
- if (output_leave_open && COP->set_written_time != NULL)
- {
- vis_runner_time_offset (- COP->written_time ());
- COP->set_written_time (0);
- }
+ LOCKED_VIS_RET (FALSE);
+ g_return_val_if_fail (! opened, FALSE);
decoder_format = format;
decoder_channels = channels;
decoder_rate = rate;
- frames_written = 0;
-
effect_channels = channels;
effect_rate = rate;
effect_start (& effect_channels, & effect_rate);
eq_set_format (effect_channels, effect_rate);
- if (output_leave_open && COP->set_written_time != NULL && effect_channels ==
- output_channels && effect_rate == output_rate)
- output_opened = TRUE;
+ if (leave_open && effect_channels == output_channels && effect_rate ==
+ output_rate)
+ {
+ reset_time ();
+ opened = TRUE;
+ }
else
{
- if (output_leave_open)
+ if (leave_open)
{
- UNLOCK;
drain ();
- LOCK;
real_close ();
}
@@ -183,90 +141,37 @@ static gboolean output_open_audio (gint format, gint rate, gint channels)
output_channels = effect_channels;
output_rate = effect_rate;
- if (COP->open_audio (output_format, output_rate, output_channels) > 0)
+ if (cop->open_audio (output_format, output_rate, output_channels))
{
vis_runner_start_stop (TRUE, FALSE);
- output_opened = TRUE;
+ opened = TRUE;
}
}
- output_aborted = FALSE;
- output_leave_open = FALSE;
- output_paused = FALSE;
-
- UNLOCK;
- return output_opened;
-}
-
-static void output_close_audio (void)
-{
- LOCK;
-
- output_opened = FALSE;
-
- if (! output_leave_open)
- {
- effect_flush ();
- real_close ();
- }
-
- UNLOCK;
-}
-
-static void output_flush (gint time)
-{
- LOCK;
-
- frames_written = time * (gint64) decoder_rate / 1000;
- output_aborted = FALSE;
-
- vis_runner_flush ();
- effect_flush ();
- COP->flush (effect_decoder_to_output_time (time));
+ leave_open = FALSE;
+ waiting = FALSE;
+ aborted = FALSE;
+ paused = FALSE;
+ frames_written = 0;
+ have_replay_gain = FALSE;
- UNLOCK;
+ return opened;
}
-static void output_pause (gboolean pause)
+static gboolean output_open_audio (gint format, gint rate, gint channels)
{
- LOCK;
- COP->pause (pause);
- vis_runner_start_stop (TRUE, pause);
- output_paused = pause;
- UNLOCK;
+ g_return_val_if_fail (cop != NULL, FALSE);
+ LOCK_VIS;
+ gboolean success = open_audio (format, rate, channels);
+ UNLOCK_VIS;
+ return success;
}
-static gint get_written_time (void)
+static void set_gain (ReplayGainInfo * info)
{
- gint time = 0;
+ LOCKED;
+ g_return_if_fail (opened && ! waiting);
- LOCK;
-
- if (output_opened)
- time = frames_written * (gint64) 1000 / decoder_rate;
-
- UNLOCK;
- return time;
-}
-
-static gboolean output_buffer_playing (void)
-{
- LOCK;
-
- if (! output_paused)
- {
- UNLOCK;
- write_buffers ();
- LOCK;
- output_leave_open = TRUE;
- }
-
- UNLOCK;
- return FALSE;
-}
-
-static void output_set_replaygain_info (ReplayGainInfo * info)
-{
AUDDBG ("Replay Gain info:\n");
AUDDBG (" album gain: %f dB\n", info->album_gain);
AUDDBG (" album peak: %f\n", info->album_peak);
@@ -277,6 +182,14 @@ static void output_set_replaygain_info (ReplayGainInfo * info)
memcpy (& replay_gain_info, info, sizeof (ReplayGainInfo));
}
+static void output_set_replaygain_info (ReplayGainInfo * info)
+{
+ g_return_if_fail (cop != NULL);
+ LOCK;
+ set_gain (info);
+ UNLOCK;
+}
+
static void apply_replay_gain (gfloat * data, gint samples)
{
gfloat factor = powf (10, (gfloat) cfg.replay_gain_preamp / 20);
@@ -339,80 +252,70 @@ static void apply_software_volume (gfloat * data, gint channels, gint frames)
audio_amplify (data, channels, frames, factors);
}
-static void do_write (void * data, gint samples)
+static void write_processed (void * data, gint samples)
{
+ LOCKED_VIS;
+
if (! samples)
return;
- void * allocated = NULL;
-
- vis_runner_pass_audio (COP->written_time (), data, samples, output_channels,
+ vis_runner_pass_audio (cop->written_time (), data, samples, output_channels,
output_rate);
eq_filter (data, samples);
apply_software_volume (data, output_channels, samples / output_channels);
+ void * allocated = NULL;
+
if (output_format != FMT_FLOAT)
{
void * new = g_malloc (FMT_SIZEOF (output_format) * samples);
-
audio_to_int (data, new, output_format, samples);
-
data = new;
g_free (allocated);
allocated = new;
}
- while (1)
+ while (! aborted)
{
- gint ready;
-
- if (COP->buffer_free)
- ready = COP->buffer_free () / FMT_SIZEOF (output_format);
- else
- ready = output_channels * (output_rate / 50);
-
- LOCK;
-
- if (output_aborted)
- {
- UNLOCK;
- break;
- }
-
- UNLOCK;
-
+ gint ready = (cop->buffer_free != NULL) ? cop->buffer_free () /
+ FMT_SIZEOF (output_format) : output_channels * (output_rate / 50);
ready = MIN (ready, samples);
- COP->write_audio (data, FMT_SIZEOF (output_format) * ready);
+ cop->write_audio (data, FMT_SIZEOF (output_format) * ready);
data = (char *) data + FMT_SIZEOF (output_format) * ready;
samples -= ready;
if (! samples)
break;
- if (COP->period_wait)
- COP->period_wait ();
- else if (COP->buffer_free)
+ waiting = TRUE;
+ UNLOCK_VIS;
+
+ if (cop->period_wait != NULL)
+ cop->period_wait ();
+ else if (cop->buffer_free != NULL)
g_usleep (20000);
+
+ LOCK_VIS;
+ waiting = FALSE;
}
g_free (allocated);
}
-static void output_write_audio (void * data, gint size)
+static void write_audio (void * data, gint size)
{
- gint samples = size / FMT_SIZEOF (decoder_format);
- void * allocated = NULL;
+ LOCKED;
+ g_return_if_fail (opened && ! waiting);
- LOCK;
+ gint samples = size / FMT_SIZEOF (decoder_format);
frames_written += samples / decoder_channels;
- UNLOCK;
+
+ void * allocated = NULL;
if (decoder_format != FMT_FLOAT)
{
gfloat * new = g_malloc (sizeof (gfloat) * samples);
-
audio_from_int (data, decoder_format, new, samples);
-
data = new;
g_free (allocated);
allocated = new;
@@ -429,39 +332,153 @@ static void output_write_audio (void * data, gint size)
allocated = NULL;
}
- do_write (data, samples);
+ write_processed (data, samples);
g_free (allocated);
}
-static void write_buffers (void)
+static void output_write_audio (void * data, gint size)
{
- gfloat * data = NULL;
- gint samples = 0;
+ g_return_if_fail (cop != NULL);
+ LOCK_VIS;
+ write_audio (data, size);
+ UNLOCK_VIS;
+}
- effect_finish (& data, & samples);
- do_write (data, samples);
+static void close_audio (void)
+{
+ LOCKED;
+ g_return_if_fail (opened && ! waiting);
+ opened = FALSE;
+
+ if (! leave_open)
+ {
+ effect_flush ();
+ real_close ();
+ }
}
-static void abort_write (void)
+static void output_close_audio (void)
+{
+ g_return_if_fail (cop != NULL);
+ LOCK_VIS;
+ close_audio ();
+ UNLOCK_VIS;
+}
+
+static void do_pause (gboolean p)
+{
+ LOCKED_VIS;
+ g_return_if_fail (opened);
+ cop->pause (p);
+ vis_runner_start_stop (TRUE, p);
+ paused = p;
+}
+
+static void output_pause (gboolean p)
{
+ g_return_if_fail (cop != NULL);
+ LOCK_VIS;
+ do_pause (p);
+ UNLOCK_VIS;
+}
+
+static void flush (gint time)
+{
+ LOCKED_VIS;
+ g_return_if_fail (opened);
+
+ aborted = FALSE;
+
+ /* When playback is started from the middle of a song, flush() is called
+ * before any audio is actually written in order to set the time counter.
+ * In this case, we do not want to cut off the end of the previous song, so
+ * we do not actually flush. */
+ if (! frames_written)
+ {
+ g_return_if_fail (cop->set_written_time != NULL);
+ cop->set_written_time (time);
+ }
+ else
+ {
+ vis_runner_flush ();
+ effect_flush ();
+ cop->flush (effect_decoder_to_output_time (time));
+ }
+
+ frames_written = time * (gint64) decoder_rate / 1000;
+}
+
+static void output_flush (gint time)
+{
+ g_return_if_fail (cop != NULL);
+ LOCK_VIS;
+ flush (time);
+ UNLOCK_VIS;
+}
+
+static gint written_time (void)
+{
+ LOCKED_RET (0);
+ g_return_val_if_fail (opened && ! waiting, 0);
+ return frames_written * (gint64) 1000 / decoder_rate;
+}
+
+static gint output_written_time (void)
+{
+ g_return_val_if_fail (cop != NULL, 0);
LOCK;
- output_aborted = TRUE;
- COP->flush (COP->output_time ()); /* signal wait to return immediately */
+ gint time = written_time ();
UNLOCK;
+ return time;
}
-static void drain (void)
+static void write_buffers (void)
+{
+ LOCKED;
+ gfloat * data = NULL;
+ gint samples = 0;
+ effect_finish (& data, & samples);
+ write_processed (data, samples);
+}
+
+static void set_leave_open (void)
{
- if (COP->buffer_playing != NULL)
+ LOCKED;
+ g_return_if_fail (opened && ! waiting);
+
+ if (! paused)
{
- while (COP->buffer_playing ())
- g_usleep (30000);
+ write_buffers ();
+ leave_open = TRUE;
}
- else
- COP->drain ();
}
-struct OutputAPI output_api =
+static gboolean output_buffer_playing (void)
+{
+ g_return_val_if_fail (cop != NULL, FALSE);
+ LOCK_VIS;
+ set_leave_open ();
+ UNLOCK_VIS;
+ return FALSE;
+}
+
+static void abort_write (void)
+{
+ LOCKED;
+ g_return_if_fail (opened);
+ aborted = TRUE;
+ cop->flush (cop->output_time ());
+}
+
+static void output_abort_write (void)
+{
+ g_return_if_fail (cop != NULL);
+ LOCK;
+ abort_write ();
+ UNLOCK;
+}
+
+const struct OutputAPI output_api =
{
.open_audio = output_open_audio,
.set_replaygain_info = output_set_replaygain_info,
@@ -470,20 +487,27 @@ struct OutputAPI output_api =
.pause = output_pause,
.flush = output_flush,
- .written_time = get_written_time,
+ .written_time = output_written_time,
.buffer_playing = output_buffer_playing,
- .abort_write = abort_write,
+ .abort_write = output_abort_write,
};
-gint get_output_time (void)
+static gint output_time (void)
{
- gint time = 0;
+ LOCKED_RET (0);
+ g_return_val_if_fail (opened || leave_open, 0);
+ return cop->output_time ();
+}
+gint get_output_time (void)
+{
+ g_return_val_if_fail (cop != NULL, 0);
LOCK;
- if (output_opened)
+ gint time = 0;
+ if (opened)
{
- time = effect_output_to_decoder_time (COP->output_time ());
+ time = effect_output_to_decoder_time (output_time ());
time = MAX (0, time);
}
@@ -491,61 +515,80 @@ gint get_output_time (void)
return time;
}
-void output_drain (void)
+gint get_raw_output_time (void)
{
+ g_return_val_if_fail (cop != NULL, 0);
LOCK;
+ gint time = output_time ();
+ UNLOCK;
+ return time;
+}
- if (output_leave_open)
+void output_drain (void)
+{
+ g_return_if_fail (cop != NULL);
+ LOCK_VIS;
+
+ if (leave_open)
{
- UNLOCK;
- write_buffers (); /* tell effect plugins this is the last song */
+ write_buffers ();
drain ();
- LOCK;
real_close ();
}
- UNLOCK;
+ UNLOCK_VIS;
}
-void set_current_output_plugin (OutputPlugin * plugin)
+static gboolean probe_cb (PluginHandle * p, PluginHandle * * pp)
{
- OutputPlugin * old = COP;
- gboolean playing = playback_get_playing ();
- gboolean paused = FALSE;
- gint time = 0;
+ OutputPlugin * op = plugin_get_header (p);
+ g_return_val_if_fail (op != NULL && op->init != NULL, TRUE);
- if (playing)
- {
- paused = playback_get_paused ();
- time = playback_get_time ();
- playback_stop ();
- }
+ if (! op->init ())
+ return TRUE;
+
+ if (op->cleanup != NULL)
+ op->cleanup ();
+
+ * pp = p;
+ return FALSE;
+}
- /* This function is also used to restart playback (for example, when
- resampling is switched on or off), in which case we don't need to do an
- init cycle. -jlindgren */
- if (plugin != COP)
+PluginHandle * output_plugin_probe (void)
+{
+ PluginHandle * p = NULL;
+ plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) probe_cb, & p);
+ return p;
+}
+
+PluginHandle * output_plugin_get_current (void)
+{
+ return (cop != NULL) ? plugin_by_header (cop) : NULL;
+}
+
+gboolean output_plugin_set_current (PluginHandle * plugin)
+{
+ if (cop != NULL)
{
- COP = NULL;
+ if (playback_get_playing ())
+ playback_stop ();
- if (old != NULL && old->cleanup != NULL)
- old->cleanup ();
+ if (cop->cleanup != NULL)
+ cop->cleanup ();
- if (plugin->init () == OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
- COP = plugin;
- else
- {
- fprintf (stderr, "Output plugin failed to load: %s\n",
- plugin->description);
+ cop = NULL;
+ }
- if (old == NULL || old->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
- return;
+ if (plugin != NULL)
+ {
+ OutputPlugin * op = plugin_get_header (plugin);
+ g_return_val_if_fail (op != NULL && op->init != NULL, FALSE);
- fprintf (stderr, "Falling back to: %s\n", old->description);
- COP = old;
- }
+ if (! op->init ())
+ return FALSE;
+
+ cop = op;
}
- if (playing)
- playback_play (time, paused);
+ return TRUE;
}
diff --git a/src/audacious/output.h b/src/audacious/output.h
index 8399f5f..c7525d5 100644
--- a/src/audacious/output.h
+++ b/src/audacious/output.h
@@ -30,17 +30,17 @@
#include "plugin.h"
-extern struct OutputAPI output_api;
-extern OutputPlugin * current_output_plugin;
+extern const struct OutputAPI output_api;
-GList *get_output_list(void);
void output_get_volume(gint * l, gint * r);
void output_set_volume(gint l, gint r);
-void output_init (void);
-void output_cleanup (void);
-void set_current_output_plugin (OutputPlugin * plugin);
gint get_output_time (void);
+gint get_raw_output_time (void);
void output_drain (void);
+PluginHandle * output_plugin_probe (void);
+PluginHandle * output_plugin_get_current (void);
+gboolean output_plugin_set_current (PluginHandle * plugin);
+
#endif /* AUDACIOUS_OUTPUT_H */
diff --git a/src/audacious/playback.c b/src/audacious/playback.c
index 6d31652..9aa239b 100644
--- a/src/audacious/playback.c
+++ b/src/audacious/playback.c
@@ -1,29 +1,26 @@
-/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2009 Audacious development team
+/*
+ * playback.c
+ * Copyright 2005-2011 Audacious Development Team
*
- * Based on BMP:
- * Copyright (C) 2003-2004 BMP development team.
+ * This file is part of Audacious.
*
- * Based on XMMS:
- * Copyright (C) 1998-2003 XMMS development team.
+ * Audacious 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, version 2 or version 3 of the License.
*
- * 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; under version 3 of the License.
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
*/
#include <glib.h>
+#include <pthread.h>
#include <libaudcore/audstrings.h>
#include <libaudcore/eventqueue.h>
@@ -33,30 +30,42 @@
#include "config.h"
#include "i18n.h"
#include "interface.h"
-#include "main.h"
#include "output.h"
#include "playback.h"
#include "playlist.h"
-static void set_params (InputPlayback * playback, const gchar * title, gint
- length, gint bitrate, gint samplerate, gint channels);
-static void set_tuple (InputPlayback * playback, Tuple * tuple);
-static void set_gain_from_playlist (InputPlayback * playback);
-
-static void playback_free (InputPlayback * playback);
-static gboolean playback_play_file (gint playlist, gint entry, gint seek_time,
+static gboolean playback_start (gint playlist, gint entry, gint seek_time,
gboolean pause);
-InputPlayback * current_playback = NULL;
+static InputPlayback playback_api;
-static gint time_offset;
-static gboolean paused;
-static gboolean stopping;
-static gint ready_source;
+static gboolean playing = FALSE;
+static gboolean playback_error;
static gint failed_entries;
+
+static gint current_entry;
+static const gchar * current_filename;
+static InputPlugin * current_decoder;
+static void * current_data;
+static gint current_bitrate, current_samplerate, current_channels;
+static gchar * current_title;
+static gint current_length;
+
+static ReplayGainInfo gain_from_playlist;
+
+static gint time_offset, start_time, stop_time;
+static gboolean paused;
+
+static pthread_t playback_thread_handle;
+static gint end_source = 0;
+
+static pthread_mutex_t ready_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t ready_cond = PTHREAD_COND_INITIALIZER;
+static gboolean ready_flag;
+static gint ready_source = 0;
+
static gint set_tuple_source = 0;
static Tuple * tuple_to_be_set = NULL;
-static ReplayGainInfo gain_from_playlist;
static void cancel_set_tuple (void)
{
@@ -74,7 +83,7 @@ static void cancel_set_tuple (void)
}
/* clears gain info if tuple == NULL */
-static void read_gain_from_tuple (Tuple * tuple)
+static void read_gain_from_tuple (const Tuple * tuple)
{
gint album_gain, album_peak, track_gain, track_peak, gain_unit, peak_unit;
@@ -105,78 +114,86 @@ static void read_gain_from_tuple (Tuple * tuple)
static gboolean ready_cb (void * unused)
{
- g_return_val_if_fail (current_playback != NULL, FALSE);
-
- g_mutex_lock (current_playback->pb_ready_mutex);
- ready_source = 0;
- g_mutex_unlock (current_playback->pb_ready_mutex);
+ g_return_val_if_fail (playing, FALSE);
+ hook_call ("playback ready", NULL);
hook_call ("title change", NULL);
+ ready_source = 0;
return FALSE;
}
-static gboolean playback_is_ready (void)
+gboolean playback_get_ready (void)
{
- gboolean ready;
-
- g_return_val_if_fail (current_playback != NULL, FALSE);
-
- g_mutex_lock (current_playback->pb_ready_mutex);
- ready = (current_playback->pb_ready_val && ! ready_source);
- g_mutex_unlock (current_playback->pb_ready_mutex);
+ g_return_val_if_fail (playing, FALSE);
+ pthread_mutex_lock (& ready_mutex);
+ gboolean ready = ready_flag;
+ pthread_mutex_unlock (& ready_mutex);
return ready;
}
-static gint
-playback_set_pb_ready(InputPlayback *playback)
+static void set_pb_ready (InputPlayback * p)
{
- g_mutex_lock(playback->pb_ready_mutex);
- playback->pb_ready_val = 1;
+ g_return_if_fail (playing);
+
+ pthread_mutex_lock (& ready_mutex);
+ ready_flag = TRUE;
+ pthread_cond_signal (& ready_cond);
+ pthread_mutex_unlock (& ready_mutex);
+
ready_source = g_timeout_add (0, ready_cb, NULL);
- g_cond_signal(playback->pb_ready_cond);
- g_mutex_unlock(playback->pb_ready_mutex);
- return 0;
}
-static void update_cb (void * hook_data, void * user_data)
+static void wait_until_ready (void)
{
- gint playlist, entry, length;
- const gchar * title;
+ g_return_if_fail (playing);
+ pthread_mutex_lock (& ready_mutex);
- g_return_if_fail (current_playback != NULL);
+ while (! ready_flag)
+ pthread_cond_wait (& ready_cond, & ready_mutex);
+
+ pthread_mutex_unlock (& ready_mutex);
+}
+
+static void update_cb (void * hook_data, void * user_data)
+{
+ g_return_if_fail (playing);
if (GPOINTER_TO_INT (hook_data) < PLAYLIST_UPDATE_METADATA)
return;
- playlist = playlist_get_playing ();
- entry = playlist_get_position (playlist);
+ gint playlist = playlist_get_playing ();
+ gint entry = playlist_get_position (playlist);
+ const gchar * title = playlist_entry_get_title (playlist, entry, FALSE);
- if ((title = playlist_entry_get_title (playlist, entry, FALSE)) == NULL)
+ if (title == NULL)
title = playlist_entry_get_filename (playlist, entry);
- length = playlist_entry_get_length (playlist, entry, FALSE);
+ gint length = playlist_entry_get_length (playlist, entry, FALSE);
- if (! strcmp (title, current_playback->title) && length ==
- current_playback->length)
+ if (entry == current_entry && ! strcmp (title, current_title) && length ==
+ current_length)
return;
- g_free (current_playback->title);
- current_playback->title = g_strdup (title);
- current_playback->length = length;
+ current_entry = entry;
+ g_free (current_title);
+ current_title = g_strdup (title);
+ current_length = length;
- if (playback_is_ready ())
+ if (playback_get_ready ())
hook_call ("title change", NULL);
}
gint playback_get_time (void)
{
- if (! playback_is_ready ())
+ g_return_val_if_fail (playing, 0);
+
+ if (! playback_get_ready ())
return 0;
gint time = -1;
- if (current_playback->plugin->get_time != NULL)
- time = current_playback->plugin->get_time (current_playback);
+ if (current_decoder->get_time != NULL)
+ time = current_decoder->get_time (& playback_api);
if (time < 0)
time = get_output_time ();
@@ -186,9 +203,9 @@ gint playback_get_time (void)
void playback_play (gint seek_time, gboolean pause)
{
- gint playlist, entry;
+ g_return_if_fail (! playing);
- playlist = playlist_get_playing ();
+ gint playlist = playlist_get_playing ();
if (playlist == -1)
{
@@ -196,7 +213,7 @@ void playback_play (gint seek_time, gboolean pause)
playlist_set_playing (playlist);
}
- entry = playlist_get_position (playlist);
+ gint entry = playlist_get_position (playlist);
if (entry == -1)
{
@@ -207,38 +224,35 @@ void playback_play (gint seek_time, gboolean pause)
return;
}
- if (playback_get_playing())
- playback_stop();
-
failed_entries = 0;
- playback_play_file (playlist, entry, seek_time, pause);
+ playback_start (playlist, entry, seek_time, pause);
}
void playback_pause (void)
{
- if (! playback_is_ready ())
- return;
+ g_return_if_fail (playing);
+ wait_until_ready ();
paused = ! paused;
- g_return_if_fail (current_playback->plugin->pause != NULL);
- current_playback->plugin->pause (current_playback, paused);
+ g_return_if_fail (current_decoder->pause != NULL);
+ current_decoder->pause (& playback_api, paused);
if (paused)
- hook_call("playback pause", NULL);
+ hook_call ("playback pause", NULL);
else
- hook_call("playback unpause", NULL);
+ hook_call ("playback unpause", NULL);
}
-static void playback_finalize (void)
+static void playback_cleanup (void)
{
- hook_dissociate ("playlist update", update_cb);
+ g_return_if_fail (playing);
- g_mutex_lock (current_playback->pb_ready_mutex);
+ pthread_join (playback_thread_handle, NULL);
+ playing = FALSE;
+ playback_error = FALSE;
- while (! current_playback->pb_ready_val)
- g_cond_wait (current_playback->pb_ready_cond,
- current_playback->pb_ready_mutex);
+ g_free (current_title);
if (ready_source)
{
@@ -246,17 +260,8 @@ static void playback_finalize (void)
ready_source = 0;
}
- g_mutex_unlock (current_playback->pb_ready_mutex);
-
- current_playback->plugin->stop (current_playback);
-
- /* some plugins do this themselves */
- if (current_playback->thread != NULL)
- g_thread_join (current_playback->thread);
-
cancel_set_tuple ();
- playback_free (current_playback);
- current_playback = NULL;
+ hook_dissociate ("playlist update", update_cb);
}
static void complete_stop (void)
@@ -273,43 +278,45 @@ static void complete_stop (void)
void playback_stop (void)
{
- g_return_if_fail (current_playback != NULL);
-
- stopping = TRUE;
- playback_finalize ();
- stopping = FALSE;
+ g_return_if_fail (playing);
+ wait_until_ready ();
+ current_decoder->stop (& playback_api);
+ playback_cleanup ();
complete_stop ();
+
+ if (end_source)
+ {
+ g_source_remove (end_source);
+ end_source = 0;
+ }
}
-static gboolean playback_ended (void * unused)
+static gboolean end_cb (void * unused)
{
- gint playlist = playlist_get_playing ();
- gboolean play;
-
- g_return_val_if_fail (current_playback != NULL, FALSE);
+ g_return_val_if_fail (playing, FALSE);
hook_call ("playback end", NULL);
- if (current_playback->error)
+ if (playback_error)
failed_entries ++;
else
failed_entries = 0;
- playback_finalize ();
+ playback_cleanup ();
+
+ gint playlist = playlist_get_playing ();
while (1)
{
+ gboolean play;
+
if (cfg.no_playlist_advance)
play = cfg.repeat && ! failed_entries;
- else
- {
- if (! (play = playlist_next_song (playlist, cfg.repeat)))
- playlist_set_position (playlist, -1);
-
- if (failed_entries >= 10)
- play = FALSE;
- }
+ else if (! (play = playlist_next_song (playlist, cfg.repeat)))
+ playlist_set_position (playlist, -1);
+ else if (failed_entries >= 10)
+ play = FALSE;
if (cfg.stopaftersong)
play = FALSE;
@@ -321,192 +328,90 @@ static gboolean playback_ended (void * unused)
break;
}
- if (playback_play_file (playlist, playlist_get_position (playlist), 0,
- FALSE))
+ if (playback_start (playlist, playlist_get_position (playlist), 0, FALSE))
break;
failed_entries ++;
}
+ end_source = 0;
return FALSE;
}
-typedef struct
+static void * playback_thread (void * unused)
{
- gint start_time, stop_time;
- gboolean pause;
-}
-PlayParams;
+ gchar * real = filename_split_subtune (current_filename, NULL);
+ VFSFile * file = vfs_fopen (real, "r");
+ g_free (real);
-static void * playback_monitor_thread (void * data)
-{
- if (current_playback->plugin->play != NULL)
- {
- PlayParams * params = data;
- VFSFile * file = vfs_fopen (current_playback->filename, "r");
-
- current_playback->error = ! current_playback->plugin->play
- (current_playback, current_playback->filename, file,
- params->start_time, params->stop_time, params->pause);
-
- if (file != NULL)
- vfs_fclose (file);
- }
- else
- {
- fprintf (stderr, "%s should be updated to provide play().\n",
- current_playback->plugin->description);
- g_return_val_if_fail (current_playback->plugin->play_file != NULL, NULL);
- current_playback->plugin->play_file (current_playback);
- }
+ playback_error = ! current_decoder->play (& playback_api, current_filename,
+ file, start_time, stop_time, paused);
- g_mutex_lock (current_playback->pb_ready_mutex);
- current_playback->pb_ready_val = TRUE;
+ if (file != NULL)
+ vfs_fclose (file);
- if (ready_source != 0)
- {
- g_source_remove (ready_source);
- ready_source = 0;
- }
-
- g_cond_signal (current_playback->pb_ready_cond);
- g_mutex_unlock (current_playback->pb_ready_mutex);
-
- if (! stopping)
- g_timeout_add (0, playback_ended, NULL);
+ if (! ready_flag)
+ set_pb_ready (& playback_api);
+ end_source = g_timeout_add (0, end_cb, NULL);
return NULL;
}
-/* compatibility */
-static void playback_set_replaygain_info (InputPlayback * playback,
- ReplayGainInfo * info)
-{
- fprintf (stderr, "Plugin %s should be updated to use OutputAPI::"
- "set_replaygain_info or (better) InputPlayback::set_gain_from_playlist.\n",
- playback->plugin->description);
-
- playback->output->set_replaygain_info (info);
-}
-
-/* compatibility */
-static void playback_pass_audio (InputPlayback * playback, gint format, gint
- channels, gint size, void * data, gint * going)
-{
- static gboolean warned = FALSE;
-
- if (! warned)
- {
- fprintf (stderr, "Plugin %s should be updated to use OutputAPI::"
- "write_audio.\n", playback->plugin->description);
- warned = TRUE;
- }
-
- playback->output->write_audio (data, size);
-}
-
-static InputPlayback * playback_new (void)
-{
- InputPlayback *playback = (InputPlayback *) g_slice_new0(InputPlayback);
-
- playback->pb_ready_mutex = g_mutex_new();
- playback->pb_ready_cond = g_cond_new();
- playback->pb_ready_val = 0;
-
- playback->output = & output_api;
-
- /* init vtable functors */
- playback->set_pb_ready = playback_set_pb_ready;
- playback->set_params = set_params;
- playback->set_tuple = set_tuple;
- playback->set_gain_from_playlist = set_gain_from_playlist;
-
- /* compatibility */
- playback->set_replaygain_info = playback_set_replaygain_info;
- playback->pass_audio = playback_pass_audio;
-
- return playback;
-}
-
-/**
- * Destroys InputPlayback.
- *
- * Playback comes from playback_new() function but there can be also
- * other sources for allocated playback data (like filename and title)
- * and this tries to deallocate all that data.
- */
-static void playback_free (InputPlayback * playback)
+static gboolean playback_start (gint playlist, gint entry, gint seek_time,
+ gboolean pause)
{
- g_free(playback->filename);
- g_free(playback->title);
+ g_return_val_if_fail (! playing, FALSE);
- g_mutex_free(playback->pb_ready_mutex);
- g_cond_free(playback->pb_ready_cond);
-
- g_slice_free(InputPlayback, playback);
-}
+ current_entry = entry;
+ current_filename = playlist_entry_get_filename (playlist, entry);
-static void playback_run (gint start_time, gint stop_time, gboolean pause)
-{
- current_playback->playing = FALSE;
- current_playback->eof = FALSE;
- current_playback->error = FALSE;
-
- paused = pause;
- stopping = FALSE;
- ready_source = 0;
+ vfs_prepare_filename (current_filename);
- static PlayParams params;
- params.start_time = start_time;
- params.stop_time = stop_time;
- params.pause = pause;
+ PluginHandle * p = playlist_entry_get_decoder (playlist, entry, FALSE);
+ current_decoder = p ? plugin_get_header (p) : NULL;
- current_playback->thread = g_thread_create (playback_monitor_thread,
- & params, TRUE, NULL);
-}
-
-static gboolean playback_play_file (gint playlist, gint entry, gint seek_time,
- gboolean pause)
-{
- const gchar * filename = playlist_entry_get_filename (playlist, entry);
- const gchar * title = playlist_entry_get_title (playlist, entry, FALSE);
- InputPlugin * decoder = playlist_entry_get_decoder (playlist, entry);
- Tuple * tuple = (Tuple *) playlist_entry_get_tuple (playlist, entry, FALSE);
-
- g_return_val_if_fail (current_playback == NULL, FALSE);
-
- if (decoder == NULL)
+ if (current_decoder == NULL)
{
- gchar * error = g_strdup_printf (_("No decoder found for %s."), filename);
-
- interface_show_error_message (error);
- g_free (error);
+ gchar * error = g_strdup_printf (_("No decoder found for %s."),
+ current_filename);
+ /* The interface may not be up yet at this point. --jlindgren */
+ event_queue_with_data_free ("interface show error", error);
return FALSE;
}
- read_gain_from_tuple (tuple); /* even if tuple == NULL */
+ current_data = NULL;
+ current_bitrate = 0;
+ current_samplerate = 0;
+ current_channels = 0;
- current_playback = playback_new ();
- current_playback->plugin = decoder;
- current_playback->filename = g_strdup (filename);
- current_playback->title = g_strdup ((title != NULL) ? title : filename);
- current_playback->length = playlist_entry_get_length (playlist, entry, FALSE);
+ const gchar * title = playlist_entry_get_title (playlist, entry, FALSE);
+ current_title = g_strdup ((title != NULL) ? title : current_filename);
+
+ current_length = playlist_entry_get_length (playlist, entry, FALSE);
+ read_gain_from_tuple (playlist_entry_get_tuple (playlist, entry, FALSE));
- if (playlist_entry_is_segmented (playlist, entry))
+ if (current_length > 0 && playlist_entry_is_segmented (playlist, entry))
{
time_offset = playlist_entry_get_start_time (playlist, entry);
- playback_run (time_offset + seek_time, playlist_entry_get_end_time
- (playlist, entry), pause);
+ stop_time = playlist_entry_get_end_time (playlist, entry);
}
else
{
time_offset = 0;
- playback_run (seek_time, -1, pause);
+ stop_time = -1;
}
-#ifdef USE_DBUS /* Fix me: Use a "playback begin" hook in dbus.c. */
- mpris_emit_track_change(mpris);
-#endif
+ if (current_length > 0)
+ start_time = time_offset + seek_time;
+ else
+ start_time = 0;
+
+ playing = TRUE;
+ playback_error = FALSE;
+ paused = pause;
+ ready_flag = FALSE;
+
+ pthread_create (& playback_thread_handle, NULL, playback_thread, NULL);
hook_associate ("playlist update", update_cb, NULL);
hook_call ("playback begin", NULL);
@@ -515,144 +420,158 @@ static gboolean playback_play_file (gint playlist, gint entry, gint seek_time,
gboolean playback_get_playing (void)
{
- return (current_playback != NULL);
+ return playing;
}
gboolean playback_get_paused (void)
{
- g_return_val_if_fail (current_playback != NULL, FALSE);
-
+ g_return_val_if_fail (playing, FALSE);
return paused;
}
void playback_seek (gint time)
{
- g_return_if_fail (current_playback != NULL);
+ g_return_if_fail (playing);
+ wait_until_ready ();
- if (! playback_is_ready ())
+ if (current_decoder->mseek == NULL || playback_get_length () < 1)
return;
- time = CLAMP (time, 0, current_playback->length);
- time += time_offset;
-
- if (current_playback->plugin->mseek != NULL)
- current_playback->plugin->mseek (current_playback, time);
- else if (current_playback->plugin->seek != NULL)
- {
- fprintf (stderr, "%s should be updated to provide mseek().\n",
- current_playback->plugin->description);
- current_playback->plugin->seek (current_playback, time / 1000);
- }
+ current_decoder->mseek (& playback_api, time_offset + CLAMP (time, 0,
+ current_length));
hook_call ("playback seek", NULL);
}
-static void set_params (InputPlayback * playback, const gchar * title, gint
- length, gint bitrate, gint samplerate, gint channels)
+static void set_data (InputPlayback * p, void * data)
+{
+ g_return_if_fail (playing);
+ current_data = data;
+}
+
+static void * get_data (InputPlayback * p)
{
- playback->rate = bitrate;
- playback->freq = samplerate;
- playback->nch = channels;
+ g_return_val_if_fail (playing, NULL);
+ return current_data;
+}
+
+static void set_params (InputPlayback * p, gint bitrate, gint samplerate,
+ gint channels)
+{
+ g_return_if_fail (playing);
+
+ current_bitrate = bitrate;
+ current_samplerate = samplerate;
+ current_channels = channels;
event_queue ("info change", NULL);
}
static gboolean set_tuple_cb (void * unused)
{
- gint playlist = playlist_get_playing ();
-
- g_return_val_if_fail (current_playback != NULL, FALSE);
- g_mutex_lock (current_playback->pb_ready_mutex);
+ g_return_val_if_fail (playing, FALSE);
+ pthread_mutex_lock (& ready_mutex);
+ gint playlist = playlist_get_playing ();
playlist_entry_set_tuple (playlist, playlist_get_position (playlist),
tuple_to_be_set);
set_tuple_source = 0;
tuple_to_be_set = NULL;
- g_mutex_unlock (current_playback->pb_ready_mutex);
-
+ pthread_mutex_unlock (& ready_mutex);
return FALSE;
}
-static void set_tuple (InputPlayback * playback, Tuple * tuple)
+static void set_tuple (InputPlayback * p, Tuple * tuple)
{
- g_mutex_lock (playback->pb_ready_mutex);
+ g_return_if_fail (playing);
+ pthread_mutex_lock (& ready_mutex);
- /* playlist_entry_set_tuple must execute in main thread */
cancel_set_tuple ();
set_tuple_source = g_timeout_add (0, set_tuple_cb, NULL);
tuple_to_be_set = tuple;
read_gain_from_tuple (tuple);
-
- g_mutex_unlock (playback->pb_ready_mutex);
+ pthread_mutex_unlock (& ready_mutex);
}
-static void set_gain_from_playlist (InputPlayback * playback)
+static void set_gain_from_playlist (InputPlayback * p)
{
- playback->output->set_replaygain_info (& gain_from_playlist);
+ g_return_if_fail (playing);
+ p->output->set_replaygain_info (& gain_from_playlist);
}
+static InputPlayback playback_api = {
+ .output = & output_api,
+ .set_data = set_data,
+ .get_data = get_data,
+ .set_pb_ready = set_pb_ready,
+ .set_params = set_params,
+ .set_tuple = set_tuple,
+ .set_gain_from_playlist = set_gain_from_playlist,
+};
+
gchar * playback_get_title (void)
{
- gchar * suffix, * title;
+ g_return_val_if_fail (playing, NULL);
- g_return_val_if_fail (current_playback != NULL, NULL);
-
- if (! playback_is_ready ())
+ if (! playback_get_ready ())
return g_strdup (_("Buffering ..."));
- suffix = (current_playback->length > 0) ? g_strdup_printf (" (%d:%02d)",
- current_playback->length / 60000, current_playback->length / 1000 % 60) :
- NULL;
+ gchar s[128];
- if (cfg.show_numbers_in_pl)
- title = g_strdup_printf ("%d. %s%s", 1 + playlist_get_position
- (playlist_get_playing ()), current_playback->title, (suffix != NULL) ?
- suffix : "");
+ if (current_length)
+ {
+ gint len = current_length / 1000;
+
+ if (len < 3600)
+ snprintf (s, sizeof s, cfg.leading_zero ? " (%02d:%02d)" :
+ " (%d:%02d)", len / 60, len % 60);
+ else
+ snprintf (s, sizeof s, " (%d:%02d:%02d)", len / 3600, (len / 60) %
+ 60, len % 60);
+ }
else
- title = g_strdup_printf ("%s%s", current_playback->title, (suffix !=
- NULL) ? suffix : "");
+ s[0] = 0;
- g_free (suffix);
- return title;
+ if (cfg.show_numbers_in_pl)
+ return g_strdup_printf ("%d. %s%s", 1 + playlist_get_position
+ (playlist_get_playing ()), current_title, s);
+
+ return g_strdup_printf ("%s%s", current_title, s);
}
gint playback_get_length (void)
{
- g_return_val_if_fail (current_playback != NULL, 0);
-
- return current_playback->length;
+ g_return_val_if_fail (playing, 0);
+ return current_length;
}
void playback_get_info (gint * bitrate, gint * samplerate, gint * channels)
{
- g_return_if_fail (current_playback != NULL);
-
- * bitrate = current_playback->rate;
- * samplerate = current_playback->freq;
- * channels = current_playback->nch;
+ g_return_if_fail (playing);
+ * bitrate = current_bitrate;
+ * samplerate = current_samplerate;
+ * channels = current_channels;
}
-void
-input_get_volume(gint * l, gint * r)
+void playback_get_volume (gint * l, gint * r)
{
- if (current_playback && current_playback->plugin->get_volume &&
- current_playback->plugin->get_volume (l, r))
+ if (playing && current_decoder->get_volume != NULL &&
+ current_decoder->get_volume (l, r))
return;
output_get_volume (l, r);
}
-void
-input_set_volume(gint l, gint r)
+void playback_set_volume(gint l, gint r)
{
gint h_vol[2] = {l, r};
- hook_call("volume set", h_vol);
+ hook_call ("volume set", h_vol);
- if (current_playback && current_playback->plugin->set_volume &&
- current_playback->plugin->set_volume (l, r))
+ if (playing && current_decoder->set_volume != NULL &&
+ current_decoder->set_volume (l, r))
return;
output_set_volume (l, r);
diff --git a/src/audacious/playback.h b/src/audacious/playback.h
index 96c1a5d..2bf7f0d 100644
--- a/src/audacious/playback.h
+++ b/src/audacious/playback.h
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2007 Audacious development team
+ * Copyright (C) 2005-2011 Audacious development team
*
* Based on BMP:
* Copyright (C) 2003-2004 BMP development team
@@ -30,6 +30,7 @@ gint playback_get_time(void);
void playback_pause(void);
void playback_stop(void);
gboolean playback_get_playing(void);
+gboolean playback_get_ready (void);
gboolean playback_get_paused(void);
void playback_seek(gint time);
@@ -37,7 +38,7 @@ gchar * playback_get_title (void);
gint playback_get_length (void);
void playback_get_info (gint * bitrate, gint * samplerate, gint * channels);
-void input_get_volume(gint * l, gint * r);
-void input_set_volume(gint l, gint r);
+void playback_get_volume (gint * l, gint * r);
+void playback_set_volume (gint l, gint r);
#endif /* AUDACIOUS_PLAYBACK_H */
diff --git a/src/audacious/playlist-api.h b/src/audacious/playlist-api.h
index 8520261..39ee7bf 100644
--- a/src/audacious/playlist-api.h
+++ b/src/audacious/playlist-api.h
@@ -1,6 +1,6 @@
/*
* playlist-api.h
- * Copyright 2010 John Lindgren
+ * Copyright 2010-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -38,7 +38,11 @@ AUD_FUNC1 (void, playlist_insert, gint, at)
AUD_FUNC3 (void, playlist_reorder, gint, from, gint, to, gint, count)
/* Closes a playlist. CAUTION: The playlist is not saved, and no confirmation
- * is presented to the user. */
+ * is presented to the user. If <playlist> is the only playlist, a new playlist
+ * is added. If <playlist> is the active playlist, another playlist is marked
+ * active. If <playlist> is the one from which the last song played was taken,
+ * playback is stopped. In this case, calls to playlist_get_playing() will
+ * return -1, and the behavior of drct_play() is unspecified. */
AUD_FUNC1 (void, playlist_delete, gint, playlist)
/* Sets the filename associated with a playlist. (Audacious currently makes no
@@ -96,7 +100,9 @@ AUD_FUNC4 (void, playlist_entry_insert_batch, gint, playlist, gint, at,
struct index *, filenames, struct index *, tuples)
/* Removes a contiguous block of <number> entries starting from the one numbered
- * <at> from a playlist. */
+ * <at> from a playlist. If the last song played is in this block, playback is
+ * stopped. In this case, calls to playlist_get_position() will return -1, and
+ * the behavior of drct_play() is unspecified. */
AUD_FUNC3 (void, playlist_entry_delete, gint, playlist, gint, at, gint, number)
/* Returns the filename of an entry. The returned string is valid until another
@@ -104,6 +110,12 @@ AUD_FUNC3 (void, playlist_entry_delete, gint, playlist, gint, at, gint, number)
AUD_FUNC2 (const gchar *, playlist_entry_get_filename, gint, playlist, gint,
entry)
+/* Returns a handle to the decoder plugin associated with an entry, or NULL if
+ * none can be found. If <fast> is nonzero, returns NULL if no decoder plugin
+ * has yet been found. */
+AUD_FUNC3 (PluginHandle *, playlist_entry_get_decoder, gint, playlist, gint,
+ entry, gboolean, fast)
+
/* Returns the tuple associated with an entry, or NULL if one is not available.
* The returned tuple is read-only and valid until another playlist function is
* called or control returns to the program's main loop. If <fast> is nonzero,
@@ -115,10 +127,20 @@ AUD_FUNC3 (const Tuple *, playlist_entry_get_tuple, gint, playlist, gint, entry,
/* Returns a formatted title string for an entry. This may include information
* such as the filename, song title, and/or artist. The returned string is
* valid until another playlist function is called or control returns to the
- * program's main loop. <fast> is as in playlist_entry_get_tuple(). */
+ * program's main loop. If <fast> is nonzero, returns the entry's filename if
+ * metadata for the entry has not yet been read. */
AUD_FUNC3 (const gchar *, playlist_entry_get_title, gint, playlist, gint, entry,
gboolean, fast)
+/* Returns three strings (title, artist, and album) describing an entry. The
+ * returned strings are valid until another playlist function is called or
+ * control returns to the program's main loop. If <fast> is nonzero, return's
+ * the entry's filename for <title> and NULL for <artist> and <album> if
+ * metadata for the entry has not yet been read. */
+AUD_FUNC6 (void, playlist_entry_describe, gint, playlist, gint, entry,
+ const gchar * *, title, const gchar * *, artist, const gchar * *, album,
+ gboolean, fast)
+
/* Returns the length in milliseconds of an entry, or -1 if the length is not
* known. <fast> is as in playlist_entry_get_tuple(). */
AUD_FUNC3 (gint, playlist_entry_get_length, gint, playlist, gint, entry,
@@ -148,33 +170,44 @@ AUD_FUNC1 (gint, playlist_selected_count, gint, playlist)
/* Selects all (or none) of the entries in a playlist. */
AUD_FUNC2 (void, playlist_select_all, gint, playlist, gboolean, selected)
-/* Moves an entry, along with selected entries near it, within a playlist, by an
- * offset of <distance> entries. For an exact definition of "near it", read the
- * source code. Returns the offset by which the entry was actually moved, which
- * may be less (in absolute value) than the requested offset. */
+/* Moves a selected entry within a playlist by an offset of <distance> entries.
+ * Other selected entries are gathered around it. Returns the offset by which
+ * the entry was actually moved, which may be less in absolute value than the
+ * requested offset. */
AUD_FUNC3 (gint, playlist_shift, gint, playlist, gint, position, gint, distance)
-/* Removes the selected entries from a playlist. */
+/* Removes the selected entries from a playlist. If the last song played is one
+ * of these entries, playback is stopped. In this case, calls to
+ * playlist_get_position() will return -1, and the behavior of drct_play() is
+ * unspecified. */
AUD_FUNC1 (void, playlist_delete_selected, gint, playlist)
/* Sorts the entries in a playlist based on filename. The callback function
* should return negative if the first filename comes before the second,
* positive if it comes after, or zero if the two are indistinguishable. */
AUD_FUNC2 (void, playlist_sort_by_filename, gint, playlist,
- PlaylistFilenameCompareFunc, compare)
+ PlaylistStringCompareFunc, compare)
/* Sorts the entries in a playlist based on tuple. */
AUD_FUNC2 (void, playlist_sort_by_tuple, gint, playlist,
PlaylistTupleCompareFunc, compare)
+/* Sorts the entries in a playlist based on formatted title string. */
+AUD_FUNC2 (void, playlist_sort_by_title, gint, playlist,
+ PlaylistStringCompareFunc, compare)
+
/* Sorts only the selected entries in a playlist based on filename. */
AUD_FUNC2 (void, playlist_sort_selected_by_filename, gint, playlist,
- PlaylistFilenameCompareFunc, compare)
+ PlaylistStringCompareFunc, compare)
/* Sorts only the selected entries in a playlist based on tuple. */
AUD_FUNC2 (void, playlist_sort_selected_by_tuple, gint, playlist,
PlaylistTupleCompareFunc, compare)
+/* Sorts only the selected entries in a playlist based on formatted title string. */
+AUD_FUNC2 (void, playlist_sort_selected_by_title, gint, playlist,
+ PlaylistStringCompareFunc, compare)
+
/* Reverses the order of the entries in a playlist. */
AUD_FUNC1 (void, playlist_reverse, gint, playlist)
@@ -185,6 +218,9 @@ AUD_FUNC1 (void, playlist_randomize, gint, playlist)
* reading it afresh from the song files in the background. */
AUD_FUNC1 (void, playlist_rescan, gint, playlist)
+/* Like playlist_rescan, but applies only to the selected entries in a playlist. */
+AUD_FUNC1 (void, playlist_rescan_selected, gint, playlist)
+
/* Discards the metadata stored for all the entries that refer to a particular
* song file, in whatever playlist they appear, and starts reading it afresh
* from that file in the background. */
@@ -231,6 +267,16 @@ AUD_FUNC1 (void, playlist_queue_delete_selected, gint, playlist)
* "playlist update" hook. If called from within the hook, returns nonzero. */
AUD_FUNC0 (gboolean, playlist_update_pending)
+/* May be called within the "playlist update" hook to determine what range of
+ * entries must be updated. If all entries in all playlists must be updated,
+ * returns zero. If a limited range in a single playlist must be updated,
+ * returns nonzero. In this case, stores the number of that playlist at
+ * <playlist>, the number of the first entry to be updated at <at>, and the
+ * number of contiguous entries to be updated at <count>. Note that entries may
+ * have been added or removed within this range. */
+AUD_FUNC3 (gboolean, playlist_update_range, gint *, playlist, gint *, at,
+ gint *, count)
+
/* --- PLAYLIST UTILITY API --- */
/* Sorts the entries in a playlist according to one of the schemes listed in
@@ -277,3 +323,15 @@ AUD_FUNC2 (gboolean, playlist_save, gint, playlist, const gchar *, filename)
* unexpected results. */
AUD_FUNC4 (void, playlist_insert_folder, gint, playlist, gint, at,
const gchar *, folder, gboolean, play)
+
+/* --- ADDED IN AUDACIOUS 2.5-BETA2 --- */
+
+/* Returns a unique non-negative integer which can be used to identify a given
+ * playlist even if its numbering changes (as when playlists are reordered).
+ * On error, returns -1. */
+AUD_FUNC1 (gint, playlist_get_unique_id, gint, playlist)
+
+/* Returns the number of the playlist identified by a given integer ID as
+ * returned by playlist_get_unique_id(). If the playlist no longer exists,
+ * returns -1. */
+AUD_FUNC1 (gint, playlist_by_unique_id, gint, id)
diff --git a/src/audacious/playlist-files.c b/src/audacious/playlist-files.c
new file mode 100644
index 0000000..d2ea3f3
--- /dev/null
+++ b/src/audacious/playlist-files.c
@@ -0,0 +1,84 @@
+/*
+ * playlist-files.c
+ * Copyright 2010 John Lindgren
+ *
+ * This file is part of Audacious.
+ *
+ * Audacious 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, version 2 or version 3 of the License.
+ *
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
+ */
+
+#include "debug.h"
+#include "playlist.h"
+#include "plugin.h"
+#include "plugins.h"
+
+static const gchar * get_extension (const gchar * filename, gboolean quiet)
+{
+ const gchar * s = strrchr (filename, '/');
+ if (! s)
+ goto FAIL;
+
+ const gchar * p = strrchr (s + 1, '.');
+ if (! p)
+ goto FAIL;
+
+ return p + 1;
+
+FAIL:
+ if (! quiet)
+ fprintf (stderr, "Failed to parse playlist filename %s.\n", filename);
+ return NULL;
+}
+
+gboolean filename_is_playlist (const gchar * filename)
+{
+ const gchar * ext = get_extension (filename, TRUE);
+ if (! ext)
+ return FALSE;
+
+ return playlist_plugin_for_extension (ext) ? TRUE : FALSE;
+}
+
+static PlaylistPlugin * get_plugin (const gchar * filename)
+{
+ const gchar * ext = get_extension (filename, FALSE);
+ if (! ext)
+ return NULL;
+
+ PluginHandle * plugin = playlist_plugin_for_extension (ext);
+ if (! plugin)
+ {
+ fprintf (stderr, "Unrecognized playlist file type \"%s\".\n", ext);
+ return NULL;
+ }
+
+ return plugin_get_header (plugin);
+}
+
+gboolean playlist_insert_playlist (gint list, gint at, const gchar * filename)
+{
+ AUDDBG ("Loading playlist %s.\n", filename);
+ PlaylistPlugin * pp = get_plugin (filename);
+ g_return_val_if_fail (pp && pp->load, FALSE);
+ return pp->load (filename, list, at);
+}
+
+gboolean playlist_save (gint list, const gchar * filename)
+{
+ AUDDBG ("Saving playlist %s.\n", filename);
+ PlaylistPlugin * pp = get_plugin (filename);
+ g_return_val_if_fail (pp && pp->save, FALSE);
+ return pp->save (filename, list);
+}
diff --git a/src/audacious/playlist-new.c b/src/audacious/playlist-new.c
index 56fd746..0c26db2 100644
--- a/src/audacious/playlist-new.c
+++ b/src/audacious/playlist-new.c
@@ -1,6 +1,6 @@
/*
* playlist-new.c
- * Copyright 2009-2010 John Lindgren
+ * Copyright 2009-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -20,7 +20,6 @@
*/
#include <assert.h>
-#include <inttypes.h>
#include <stdlib.h>
#include <time.h>
@@ -28,92 +27,76 @@
#include <libaudcore/audstrings.h>
#include <libaudcore/hook.h>
+#include <libaudcore/stringpool.h>
#include <libaudcore/tuple_formatter.h>
#include "audconfig.h"
#include "config.h"
#include "i18n.h"
-#include "main.h"
#include "misc.h"
#include "playback.h"
#include "playlist.h"
#include "playlist-utils.h"
-#include "plugin.h"
-
-#define SCAN_DEBUG(...)
+#include "plugins.h"
+#include "util.h"
#define SCAN_THREADS 4
#define STATE_FILE "playlist-state"
#define DECLARE_PLAYLIST \
- struct playlist * playlist
+ Playlist * playlist
#define DECLARE_PLAYLIST_ENTRY \
- struct playlist * playlist; \
- struct entry * entry
+ Playlist * playlist; \
+ Entry * entry
-#define LOOKUP_PLAYLIST \
-{ \
+#define LOOKUP_PLAYLIST do { \
playlist = lookup_playlist (playlist_num); \
g_return_if_fail (playlist != NULL); \
-}
+} while (0)
-#define LOOKUP_PLAYLIST_RET(ret) \
-{ \
+#define LOOKUP_PLAYLIST_RET(ret) do { \
playlist = lookup_playlist (playlist_num); \
g_return_val_if_fail (playlist != NULL, ret); \
-}
+} while (0)
-#define LOOKUP_PLAYLIST_ENTRY \
-{ \
+#define LOOKUP_PLAYLIST_ENTRY do { \
playlist = lookup_playlist (playlist_num); \
g_return_if_fail (playlist != NULL); \
entry = lookup_entry (playlist, entry_num); \
g_return_if_fail (entry != NULL); \
-}
+} while (0)
-#define LOOKUP_PLAYLIST_ENTRY_RET(ret) \
-{ \
+#define LOOKUP_PLAYLIST_ENTRY_RET(ret) do { \
playlist = lookup_playlist (playlist_num); \
g_return_val_if_fail (playlist != NULL, ret); \
entry = lookup_entry (playlist, entry_num); \
g_return_val_if_fail (entry != NULL, ret); \
-}
+} while (0)
-#define SELECTION_HAS_CHANGED \
-{ \
- queue_update (PLAYLIST_UPDATE_SELECTION); \
-}
+#define SELECTION_HAS_CHANGED(p, a, c) \
+ queue_update (PLAYLIST_UPDATE_SELECTION, p, a, c)
-#define METADATA_WILL_CHANGE \
-{ \
- scan_stop (); \
-}
+#define METADATA_WILL_CHANGE scan_stop ()
-#define METADATA_HAS_CHANGED \
-{ \
+#define METADATA_HAS_CHANGED(p, a, c) do { \
scan_reset (); \
- queue_update (PLAYLIST_UPDATE_METADATA); \
-}
+ queue_update (PLAYLIST_UPDATE_METADATA, p, a, c); \
+} while (0)
-#define PLAYLIST_WILL_CHANGE \
-{ \
- scan_stop (); \
-}
+#define PLAYLIST_WILL_CHANGE scan_stop ()
-#define PLAYLIST_HAS_CHANGED \
-{ \
+#define PLAYLIST_HAS_CHANGED(p, a, c) do { \
scan_reset (); \
- queue_update (PLAYLIST_UPDATE_STRUCTURE); \
-}
+ queue_update (PLAYLIST_UPDATE_STRUCTURE, p, a, c); \
+} while (0)
-struct entry
-{
+typedef struct {
gint number;
gchar *filename;
- InputPlugin *decoder;
+ PluginHandle * decoder;
Tuple *tuple;
- gchar *title;
+ gchar * formatted, * title, * artist, * album;
gint length;
gboolean failed;
gboolean selected;
@@ -122,37 +105,41 @@ struct entry
gboolean segmented;
gint start;
gint end;
-};
+} Entry;
-struct playlist
-{
+typedef struct {
gint number;
+ gint unique_id;
gchar *filename;
gchar *title;
struct index *entries;
- struct entry *position;
+ Entry * position;
gint selected_count;
gint last_shuffle_num;
GList *queued;
gint64 total_length;
gint64 selected_length;
-};
+} Playlist;
+
+static gint next_unique_id = 1000;
-static struct index *playlists;
-static struct playlist *active_playlist;
-static struct playlist *playing_playlist;
+static struct index * playlists = NULL;
+static Playlist * active_playlist = NULL;
+static Playlist * playing_playlist = NULL;
static gint update_source, update_level;
+static Playlist * update_playlist;
+static gint unchanged_before, unchanged_after;
+
static gint scan_source;
static GMutex * scan_mutex;
static GCond * scan_conds[SCAN_THREADS];
static const gchar * scan_filenames[SCAN_THREADS];
-static InputPlugin * scan_decoders[SCAN_THREADS];
+static PluginHandle * scan_decoders[SCAN_THREADS];
static Tuple * scan_tuples[SCAN_THREADS];
static gboolean scan_quit;
static GThread * scan_threads[SCAN_THREADS];
static gint scan_positions[SCAN_THREADS];
-gint updated_ago;
static void * scanner (void * unused);
@@ -166,34 +153,37 @@ static gchar *title_from_tuple(Tuple * tuple)
return tuple_formatter_make_title_string(tuple, format);
}
-static void entry_set_tuple_real (struct entry * entry, Tuple * tuple)
+static void entry_set_tuple_real (Entry * entry, Tuple * tuple)
{
/* Hack: We cannot refresh segmented entries (since their info is read from
* the cue sheet when it is first loaded), so leave them alone. -jlindgren */
- if (entry->segmented)
- {
- if (tuple != NULL)
- tuple_free (tuple);
-
+ if (entry->segmented && ! tuple)
return;
- }
if (entry->tuple != NULL)
tuple_free (entry->tuple);
-
- g_free (entry->title);
entry->tuple = tuple;
+ g_free (entry->formatted);
+ stringpool_unref (entry->title);
+ stringpool_unref (entry->artist);
+ stringpool_unref (entry->album);
+
if (tuple == NULL)
{
+ entry->formatted = NULL;
entry->title = NULL;
+ entry->artist = NULL;
+ entry->album = NULL;
entry->length = 0;
entry->segmented = FALSE;
entry->start = entry->end = -1;
}
else
{
- entry->title = title_from_tuple (tuple);
+ entry->formatted = title_from_tuple (tuple);
+ describe_song (entry->filename, tuple, & entry->title, & entry->artist,
+ & entry->album);
entry->length = tuple_get_int (tuple, FIELD_LENGTH, NULL);
entry->length = MAX (entry->length, 0);
@@ -213,8 +203,7 @@ static void entry_set_tuple_real (struct entry * entry, Tuple * tuple)
}
}
-static void entry_set_tuple (struct playlist * playlist, struct entry * entry,
- Tuple * tuple)
+static void entry_set_tuple (Playlist * playlist, Entry * entry, Tuple * tuple)
{
if (entry->tuple != NULL)
{
@@ -235,20 +224,24 @@ static void entry_set_tuple (struct playlist * playlist, struct entry * entry,
}
}
-static void entry_set_failed (struct playlist * playlist, struct entry * entry)
+static void entry_set_failed (Playlist * playlist, Entry * entry)
{
entry_set_tuple (playlist, entry, tuple_new_from_filename (entry->filename));
entry->failed = TRUE;
}
-static struct entry *entry_new(gchar * filename, InputPlugin * decoder, Tuple * tuple)
+static Entry * entry_new (gchar * filename, PluginHandle * decoder, Tuple *
+ tuple)
{
- struct entry *entry = g_malloc(sizeof(struct entry));
+ Entry * entry = g_malloc (sizeof (Entry));
entry->filename = filename;
entry->decoder = decoder;
entry->tuple = NULL;
+ entry->formatted = NULL;
entry->title = NULL;
+ entry->artist = NULL;
+ entry->album = NULL;
entry->failed = FALSE;
entry->number = -1;
entry->selected = FALSE;
@@ -261,19 +254,21 @@ static struct entry *entry_new(gchar * filename, InputPlugin * decoder, Tuple *
return entry;
}
-static void entry_free(struct entry *entry)
+static void entry_free (Entry * entry)
{
g_free(entry->filename);
if (entry->tuple != NULL)
tuple_free(entry->tuple);
- g_free(entry->title);
- g_free(entry);
+ g_free (entry->formatted);
+ stringpool_unref (entry->title);
+ stringpool_unref (entry->artist);
+ stringpool_unref (entry->album);
+ g_free (entry);
}
-static void entry_check_has_decoder (struct playlist * playlist, struct entry *
- entry)
+static void entry_check_has_decoder (Playlist * playlist, Entry * entry)
{
if (entry->decoder != NULL || entry->failed)
return;
@@ -283,11 +278,12 @@ static void entry_check_has_decoder (struct playlist * playlist, struct entry *
entry_set_failed (playlist, entry);
}
-static struct playlist *playlist_new(void)
+static Playlist * playlist_new (void)
{
- struct playlist *playlist = g_malloc(sizeof(struct playlist));
+ Playlist * playlist = g_malloc (sizeof (Playlist));
playlist->number = -1;
+ playlist->unique_id = next_unique_id ++;
playlist->filename = NULL;
playlist->title = g_strdup(_("Untitled Playlist"));
playlist->entries = index_new();
@@ -301,7 +297,7 @@ static struct playlist *playlist_new(void)
return playlist;
}
-static void playlist_free(struct playlist *playlist)
+static void playlist_free (Playlist * playlist)
{
gint count;
@@ -322,33 +318,35 @@ static void number_playlists(gint at, gint length)
for (count = 0; count < length; count++)
{
- struct playlist *playlist = index_get(playlists, at + count);
-
+ Playlist * playlist = index_get (playlists, at + count);
playlist->number = at + count;
}
}
-static struct playlist *lookup_playlist(gint playlist_num)
+static Playlist * lookup_playlist (gint playlist_num)
{
+ /* Not initted or already shut down */
+ if (! playlists)
+ return NULL;
+
if (playlist_num < 0 || playlist_num >= index_count(playlists))
return NULL;
return index_get(playlists, playlist_num);
}
-static void number_entries(struct playlist *playlist, gint at, gint length)
+static void number_entries (Playlist * playlist, gint at, gint length)
{
gint count;
for (count = 0; count < length; count++)
{
- struct entry *entry = index_get(playlist->entries, at + count);
-
+ Entry * entry = index_get (playlist->entries, at + count);
entry->number = at + count;
}
}
-static struct entry *lookup_entry(struct playlist *playlist, gint entry_num)
+static Entry * lookup_entry (Playlist * playlist, gint entry_num)
{
if (entry_num < 0 || entry_num >= index_count(playlist->entries))
return NULL;
@@ -359,19 +357,55 @@ static struct entry *lookup_entry(struct playlist *playlist, gint entry_num)
static gboolean update (void * unused)
{
hook_call ("playlist update", GINT_TO_POINTER (update_level));
-
update_source = 0;
- update_level = 0;
return FALSE;
}
-static void queue_update (gint level)
+static void queue_update (gint level, Playlist * list, gint at, gint count)
{
- update_level = MAX (update_level, level);
-
- if (update_source == 0)
+ if (! update_source)
+ {
update_source = g_idle_add_full (G_PRIORITY_HIGH_IDLE, update, NULL,
NULL);
+ update_level = 0;
+ update_playlist = list;
+ unchanged_before = list ? index_count (list->entries) : 0;
+ unchanged_after = list ? index_count (list->entries) : 0;
+ }
+
+ update_level = MAX (update_level, level);
+
+ if (list && list == update_playlist)
+ {
+ unchanged_before = MIN (unchanged_before, at);
+ unchanged_after = MIN (unchanged_after, index_count (list->entries) - at
+ - count);
+ }
+ else
+ {
+ update_playlist = NULL;
+ unchanged_before = 0;
+ unchanged_after = 0;
+ }
+}
+
+gboolean playlist_update_pending (void)
+{
+ return update_source ? TRUE : FALSE;
+}
+
+gboolean playlist_update_range (gint * playlist, gint * at, gint * count)
+{
+ g_return_val_if_fail (update_source, FALSE);
+
+ if (! update_playlist)
+ return FALSE;
+
+ * playlist = update_playlist->number;
+ * at = unchanged_before;
+ * count = index_count (update_playlist->entries) - unchanged_before -
+ unchanged_after;
+ return TRUE;
}
/* scan_mutex must be locked! */
@@ -379,13 +413,10 @@ void scan_receive (void)
{
for (gint i = 0; i < SCAN_THREADS; i ++)
{
- struct entry * entry;
-
if (! scan_filenames[i] || scan_decoders[i])
continue; /* thread not in use or still working */
- SCAN_DEBUG ("receive (#%d): %d\n", i, scan_positions[i]);
- entry = index_get (active_playlist->entries, scan_positions[i]);
+ Entry * entry = index_get (active_playlist->entries, scan_positions[i]);
if (scan_tuples[i])
entry_set_tuple (active_playlist, entry, scan_tuples[i]);
@@ -395,7 +426,8 @@ void scan_receive (void)
scan_filenames[i] = NULL;
scan_tuples[i] = NULL;
- updated_ago ++;
+ queue_update (PLAYLIST_UPDATE_METADATA, active_playlist,
+ scan_positions[i], 1);
}
}
@@ -424,7 +456,7 @@ static gboolean scan_next (void * unused)
for (; search < entries; search ++)
{
- struct entry * entry = index_get (active_playlist->entries, search);
+ Entry * entry = index_get (active_playlist->entries, search);
if (entry->tuple)
continue;
@@ -433,7 +465,8 @@ static gboolean scan_next (void * unused)
if (entry->failed)
continue;
- SCAN_DEBUG ("start (#%d): %d\n", i, search);
+ vfs_prepare_filename (entry->filename);
+
scan_positions[i] = search;
scan_filenames[i] = entry->filename;
scan_decoders[i] = entry->decoder;
@@ -444,41 +477,29 @@ static gboolean scan_next (void * unused)
}
}
- if (updated_ago >= 10 || (search == entries && updated_ago > 0))
- {
- SCAN_DEBUG ("queue update\n");
- queue_update (PLAYLIST_UPDATE_METADATA);
- updated_ago = 0;
- }
-
g_mutex_unlock (scan_mutex);
return FALSE;
}
static void scan_continue (void)
{
- SCAN_DEBUG ("scan_continue\n");
if (! scan_source)
scan_source = g_idle_add_full (G_PRIORITY_LOW, scan_next, NULL, NULL);
}
static void scan_reset (void)
{
- SCAN_DEBUG ("scan_reset\n");
-
for (gint i = 0; i < SCAN_THREADS; i ++)
{
assert (! scan_filenames[i]); /* scan in progress == very, very bad */
scan_positions[i] = -1;
}
- updated_ago = 0;
scan_continue ();
}
static void scan_stop (void)
{
- SCAN_DEBUG ("scan_stop\n");
g_mutex_lock (scan_mutex);
if (scan_source != 0)
@@ -493,10 +514,7 @@ static void scan_stop (void)
continue;
while (scan_decoders[i])
- {
- SCAN_DEBUG ("wait for stop (#%d)\n", i);
g_cond_wait (scan_conds[i], scan_mutex);
- }
}
scan_receive ();
@@ -512,26 +530,20 @@ static void * scanner (void * data)
while (1)
{
- SCAN_DEBUG ("scanner (#%d): wait\n", i);
g_cond_wait (scan_conds[i], scan_mutex);
if (scan_quit)
break;
if (! scan_filenames[i])
- {
- SCAN_DEBUG ("scanner (#%d): idle\n", i);
continue;
- }
- SCAN_DEBUG ("scanner (#%d): scan %s\n", i, scan_filenames[i]);
scan_tuples[i] = file_read_tuple (scan_filenames[i], scan_decoders[i]);
scan_decoders[i] = NULL;
g_cond_signal (scan_conds[i]);
scan_continue ();
}
- SCAN_DEBUG ("scanner (#%d): exit\n", i);
g_mutex_unlock (scan_mutex);
return NULL;
}
@@ -541,7 +553,7 @@ static void * scanner (void * data)
* we are concerned with in the main thread, this is better in the long run
* because the scanner can work on the following entries while the caller is
* processing this one. */
-static gboolean scan_threaded (struct playlist * playlist, struct entry * entry)
+static gboolean scan_threaded (Playlist * playlist, Entry * entry)
{
gint i;
@@ -559,17 +571,14 @@ static gboolean scan_threaded (struct playlist * playlist, struct entry * entry)
goto FOUND;
}
- SCAN_DEBUG ("manual scan of %d\n", entry->number);
return FALSE;
FOUND:
- SCAN_DEBUG ("threaded scan (#%d) of %d\n", i, entry->number);
g_mutex_lock (scan_mutex);
scan_receive ();
while (scan_filenames[i])
{
- SCAN_DEBUG ("wait (#%d) for %d\n", i, entry->number);
g_cond_wait (scan_conds[i], scan_mutex);
scan_receive ();
}
@@ -578,7 +587,7 @@ FOUND:
return TRUE;
}
-static void check_scanned (struct playlist * playlist, struct entry * entry)
+static void check_scanned (Playlist * playlist, Entry * entry)
{
if (entry->tuple)
return;
@@ -594,21 +603,21 @@ static void check_scanned (struct playlist * playlist, struct entry * entry)
if (! entry->tuple)
entry_set_failed (playlist, entry);
- queue_update (PLAYLIST_UPDATE_METADATA);
+ queue_update (PLAYLIST_UPDATE_METADATA, playlist, entry->number, 1);
}
-static void check_selected_scanned (struct playlist * playlist)
+static void check_selected_scanned (Playlist * playlist)
{
gint entries = index_count (playlist->entries);
for (gint count = 0; count < entries; count++)
{
- struct entry * entry = index_get (playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (entry->selected)
check_scanned (playlist, entry);
}
}
-static void check_all_scanned (struct playlist * playlist)
+static void check_all_scanned (Playlist * playlist)
{
gint entries = index_count (playlist->entries);
for (gint count = 0; count < entries; count++)
@@ -617,19 +626,16 @@ static void check_all_scanned (struct playlist * playlist)
void playlist_init (void)
{
- struct playlist * playlist;
-
- srandom (time (NULL));
+ srand (time (NULL));
playlists = index_new ();
- playlist = playlist_new ();
+ Playlist * playlist = playlist_new ();
index_append (playlists, playlist);
playlist->number = 0;
active_playlist = playlist;
playing_playlist = NULL;
update_source = 0;
- update_level = 0;
scan_mutex = g_mutex_new ();
memset (scan_filenames, 0, sizeof scan_filenames);
@@ -678,6 +684,9 @@ void playlist_end(void)
playlist_free(index_get(playlists, count));
index_free(playlists);
+ playlists = NULL;
+ active_playlist = NULL;
+ playing_playlist = NULL;
}
gint playlist_count(void)
@@ -699,8 +708,7 @@ void playlist_insert(gint at)
number_playlists(at, index_count(playlists) - at);
- PLAYLIST_HAS_CHANGED;
- hook_call ("playlist insert", GINT_TO_POINTER (at));
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
}
void playlist_reorder (gint from, gint to, gint count)
@@ -735,7 +743,7 @@ void playlist_reorder (gint from, gint to, gint count)
index_free (displaced);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
}
void playlist_delete (gint playlist_num)
@@ -744,8 +752,6 @@ void playlist_delete (gint playlist_num)
LOOKUP_PLAYLIST;
- hook_call ("playlist delete", GINT_TO_POINTER (playlist_num));
-
if (playlist == playing_playlist)
{
if (playback_get_playing ())
@@ -767,7 +773,29 @@ void playlist_delete (gint playlist_num)
active_playlist = index_get (playlists, MIN (playlist_num, index_count
(playlists) - 1));
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
+}
+
+gint playlist_get_unique_id (gint playlist_num)
+{
+ DECLARE_PLAYLIST;
+ LOOKUP_PLAYLIST_RET (-1);
+ return playlist->unique_id;
+}
+
+gint playlist_by_unique_id (gint id)
+{
+ g_return_val_if_fail (playlists, -1);
+ gint n = index_count (playlists);
+
+ for (gint i = 0; i < n; i ++)
+ {
+ Playlist * p = index_get (playlists, i);
+ if (p->unique_id == id)
+ return p->number;
+ }
+
+ return -1;
}
void playlist_set_filename(gint playlist_num, const gchar * filename)
@@ -780,7 +808,7 @@ void playlist_set_filename(gint playlist_num, const gchar * filename)
g_free(playlist->filename);
playlist->filename = g_strdup(filename);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
}
const gchar *playlist_get_filename(gint playlist_num)
@@ -802,7 +830,7 @@ void playlist_set_title(gint playlist_num, const gchar * title)
g_free(playlist->title);
playlist->title = g_strdup(title);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
}
const gchar *playlist_get_title(gint playlist_num)
@@ -823,7 +851,7 @@ void playlist_set_active(gint playlist_num)
active_playlist = playlist;
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (NULL, 0, 0);
}
gint playlist_get_active(void)
@@ -853,7 +881,7 @@ gint playlist_get_playing(void)
/* If we are already at the song or it is already at the top of the shuffle
* list, we let it be. Otherwise, we move it to the top. */
-static void set_position (struct playlist * playlist, struct entry * entry)
+static void set_position (Playlist * playlist, Entry * entry)
{
if (entry == playlist->position)
return;
@@ -879,16 +907,16 @@ gint playlist_entry_count(gint playlist_num)
return index_count(playlist->entries);
}
-static void make_entries (gchar * filename, InputPlugin * decoder, Tuple *
+static void make_entries (gchar * filename, PluginHandle * decoder, Tuple *
tuple, struct index * list)
{
uri_check_utf8 (& filename, TRUE);
- if (tuple == NULL && decoder == NULL)
+ if (! tuple && ! decoder)
decoder = file_find_decoder (filename, TRUE);
- if (tuple == NULL && decoder != NULL && decoder->have_subtune && strchr
- (filename, '?') == NULL)
+ if (! tuple && decoder && input_plugin_has_subtunes (decoder) && ! strchr
+ (filename, '?'))
tuple = file_read_tuple (filename, decoder);
if (tuple != NULL && tuple->nsubtunes > 0)
@@ -916,53 +944,60 @@ void playlist_entry_insert(gint playlist_num, gint at, gchar * filename, Tuple *
index_append(filenames, filename);
index_append(tuples, tuple);
- playlist_entry_insert_batch(playlist_num, at, filenames, tuples);
+ playlist_entry_insert_batch_with_decoders (playlist_num, at, filenames,
+ NULL, tuples);
}
-void playlist_entry_insert_batch(gint playlist_num, gint at, struct index *filenames, struct index *tuples)
+void playlist_entry_insert_batch (gint playlist_num, gint at,
+ struct index * filenames, struct index * tuples)
{
- DECLARE_PLAYLIST;
- gint entries, number, count;
- struct index *add;
+ playlist_entry_insert_batch_with_decoders (playlist_num, at, filenames,
+ NULL, tuples);
+}
+void playlist_entry_insert_batch_with_decoders (gint playlist_num, gint at,
+ struct index * filenames, struct index * decoders, struct index * tuples)
+{
+ DECLARE_PLAYLIST;
LOOKUP_PLAYLIST;
PLAYLIST_WILL_CHANGE;
- entries = index_count (playlist->entries);
+ gint entries = index_count (playlist->entries);
if (at < 0 || at > entries)
at = entries;
- number = index_count(filenames);
- add = index_new();
-
- for (count = 0; count < number; count++)
- make_entries(index_get(filenames, count), NULL, (tuples == NULL) ? NULL : index_get(tuples, count), add);
-
- index_free(filenames);
+ gint number = index_count (filenames);
+ struct index * add = index_new ();
- if (tuples != NULL)
- index_free(tuples);
+ /* Preallocate space to avoid reallocs. (The actual number of entries may
+ * turn out to be greater due to subtunes.) */
+ index_allocate (add, number);
- number = index_count(add);
+ for (gint count = 0; count < number; count ++)
+ make_entries (index_get (filenames, count), decoders ? index_get
+ (decoders, count) : NULL, tuples ? index_get (tuples, count) : NULL,
+ add);
- if (at == entries)
- index_merge_append(playlist->entries, add);
- else
- index_merge_insert(playlist->entries, at, add);
+ index_free (filenames);
+ if (decoders)
+ index_free (decoders);
+ if (tuples)
+ index_free (tuples);
- index_free(add);
+ number = index_count (add);
+ index_merge_insert (playlist->entries, at, add);
+ index_free (add);
number_entries(playlist, at, entries + number - at);
- for (count = 0; count < number; count++)
+ for (gint count = 0; count < number; count ++)
{
- struct entry *entry = index_get(playlist->entries, at + count);
-
+ Entry * entry = index_get (playlist->entries, at + count);
playlist->total_length += entry->length;
}
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, at, number);
}
void playlist_entry_delete(gint playlist_num, gint at, gint number)
@@ -983,7 +1018,7 @@ void playlist_entry_delete(gint playlist_num, gint at, gint number)
for (count = 0; count < number; count++)
{
- struct entry *entry = index_get(playlist->entries, at + count);
+ Entry * entry = index_get (playlist->entries, at + count);
if (entry == playlist->position)
{
@@ -1005,13 +1040,13 @@ void playlist_entry_delete(gint playlist_num, gint at, gint number)
entry_free(entry);
}
- index_delete(playlist->entries, at, number);
- number_entries(playlist, at, entries - number - at);
+ index_delete (playlist->entries, at, number);
+ number_entries (playlist, at, entries - at - number);
if (stop && playback_get_playing ())
playback_stop ();
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, at, 0);
}
const gchar *playlist_entry_get_filename(gint playlist_num, gint entry_num)
@@ -1023,13 +1058,14 @@ const gchar *playlist_entry_get_filename(gint playlist_num, gint entry_num)
return entry->filename;
}
-InputPlugin *playlist_entry_get_decoder(gint playlist_num, gint entry_num)
+PluginHandle * playlist_entry_get_decoder (gint playlist_num, gint entry_num,
+ gboolean fast)
{
DECLARE_PLAYLIST_ENTRY;
-
LOOKUP_PLAYLIST_ENTRY_RET (NULL);
- entry_check_has_decoder (playlist, entry);
+ if (! fast)
+ entry_check_has_decoder (playlist, entry);
return entry->decoder;
}
@@ -1043,7 +1079,7 @@ void playlist_entry_set_tuple (gint playlist_num, gint entry_num, Tuple * tuple)
entry_set_tuple (playlist, entry, tuple);
- METADATA_HAS_CHANGED;
+ METADATA_HAS_CHANGED (playlist, entry_num, 1);
}
const Tuple * playlist_entry_get_tuple (gint playlist_num, gint entry_num,
@@ -1067,7 +1103,28 @@ const gchar * playlist_entry_get_title (gint playlist_num, gint entry_num,
if (! fast)
check_scanned (playlist, entry);
- return (entry->title == NULL) ? entry->filename : entry->title;
+ return (entry->formatted == NULL) ? entry->filename : entry->formatted;
+}
+
+void playlist_entry_describe (gint playlist_num, gint entry_num,
+ const gchar * * title, const gchar * * artist, const gchar * * album,
+ gboolean fast)
+{
+ * title = * artist = * album = NULL;
+ DECLARE_PLAYLIST_ENTRY;
+ LOOKUP_PLAYLIST_ENTRY;
+
+ if (! fast)
+ check_scanned (playlist, entry);
+
+ if (entry->title)
+ {
+ * title = entry->title;
+ * artist = entry->artist;
+ * album = entry->album;
+ }
+ else
+ * title = entry->filename;
}
gint playlist_entry_get_length (gint playlist_num, gint entry_num, gboolean fast)
@@ -1125,8 +1182,6 @@ void playlist_set_position (gint playlist_num, gint entry_num)
set_position (playlist, entry);
- SELECTION_HAS_CHANGED;
-
hook_call ("playlist position", GINT_TO_POINTER (playlist_num));
}
@@ -1161,7 +1216,7 @@ void playlist_entry_set_selected(gint playlist_num, gint entry_num, gboolean sel
playlist->selected_length -= entry->length;
}
- SELECTION_HAS_CHANGED;
+ SELECTION_HAS_CHANGED (playlist, entry_num, 1);
}
gboolean playlist_entry_get_selected(gint playlist_num, gint entry_num)
@@ -1182,20 +1237,24 @@ gint playlist_selected_count(gint playlist_num)
return playlist->selected_count;
}
-void playlist_select_all(gint playlist_num, gboolean selected)
+void playlist_select_all (gint playlist_num, gboolean selected)
{
DECLARE_PLAYLIST;
- gint entries, count;
-
LOOKUP_PLAYLIST;
- entries = index_count(playlist->entries);
+ gint entries = index_count (playlist->entries);
+ gint first = entries, last = 0;
- for (count = 0; count < entries; count++)
+ for (gint count = 0; count < entries; count ++)
{
- struct entry *entry = index_get(playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
- entry->selected = selected;
+ if ((selected && ! entry->selected) || (entry->selected && ! selected))
+ {
+ entry->selected = selected;
+ first = MIN (first, entry->number);
+ last = entry->number;
+ }
}
if (selected)
@@ -1209,80 +1268,86 @@ void playlist_select_all(gint playlist_num, gboolean selected)
playlist->selected_length = 0;
}
- SELECTION_HAS_CHANGED;
+ if (first < entries)
+ SELECTION_HAS_CHANGED (playlist, first, last + 1 - first);
}
gint playlist_shift (gint playlist_num, gint entry_num, gint distance)
{
DECLARE_PLAYLIST_ENTRY;
- gint entries, first, last, shift, count;
- struct index *move, *others;
-
LOOKUP_PLAYLIST_ENTRY_RET (0);
- if (! entry->selected)
+ if (! entry->selected || ! distance)
return 0;
PLAYLIST_WILL_CHANGE;
- entries = index_count(playlist->entries);
- shift = 0;
+ gint entries = index_count (playlist->entries);
+ gint shift = 0, center, top, bottom;
- for (first = entry_num; first > 0; first--)
+ if (distance < 0)
{
- entry = index_get(playlist->entries, first - 1);
-
- if (!entry->selected)
+ for (center = entry_num; center > 0 && shift > distance; )
{
- if (shift <= distance)
- break;
-
- shift--;
+ entry = index_get (playlist->entries, -- center);
+ if (! entry->selected)
+ shift --;
}
}
-
- for (last = entry_num; last < entries - 1; last++)
+ else
{
- entry = index_get(playlist->entries, last + 1);
-
- if (!entry->selected)
+ for (center = entry_num + 1; center < entries && shift < distance; )
{
- if (shift >= distance)
- break;
-
- shift++;
+ entry = index_get (playlist->entries, center ++);
+ if (! entry->selected)
+ shift ++;
}
}
- move = index_new();
- others = index_new();
+ top = bottom = center;
- for (count = first; count <= last; count++)
+ for (gint i = 0; i < top; i ++)
{
- entry = index_get(playlist->entries, count);
- index_append(entry->selected ? move : others, entry);
+ entry = index_get (playlist->entries, i);
+ if (entry->selected)
+ top = i;
}
- if (shift < 0)
+ for (gint i = entries; i > bottom; i --)
{
- index_merge_append(move, others);
- index_free(others);
+ entry = index_get (playlist->entries, i - 1);
+ if (entry->selected)
+ bottom = i;
}
- else
+
+ struct index * temp = index_new ();
+
+ for (gint i = top; i < center; i ++)
+ {
+ entry = index_get (playlist->entries, i);
+ if (! entry->selected)
+ index_append (temp, entry);
+ }
+
+ for (gint i = top; i < bottom; i ++)
{
- index_merge_append(others, move);
- index_free(move);
- move = others;
+ entry = index_get (playlist->entries, i);
+ if (entry->selected)
+ index_append (temp, entry);
}
- for (count = first; count <= last; count++)
- index_set(playlist->entries, count, index_get(move, count - first));
+ for (gint i = center; i < bottom; i ++)
+ {
+ entry = index_get (playlist->entries, i);
+ if (! entry->selected)
+ index_append (temp, entry);
+ }
- index_free(move);
+ index_copy_set (temp, 0, playlist->entries, top, bottom - top);
- number_entries(playlist, first, 1 + last - first);
+ number_entries (playlist, top, bottom - top);
+ PLAYLIST_HAS_CHANGED (playlist, top, bottom - top);
- PLAYLIST_HAS_CHANGED;
return shift;
}
@@ -1301,7 +1366,7 @@ void playlist_delete_selected(gint playlist_num)
for (count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (entry->selected)
{
@@ -1332,7 +1397,7 @@ void playlist_delete_selected(gint playlist_num)
if (stop && playback_get_playing ())
playback_stop ();
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, 0, index_count (playlist->entries));
}
void playlist_reverse(gint playlist_num)
@@ -1356,7 +1421,7 @@ void playlist_reverse(gint playlist_num)
number_entries(playlist, 0, entries);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, 0, entries);
}
void playlist_randomize (gint playlist_num)
@@ -1369,7 +1434,7 @@ void playlist_randomize (gint playlist_num)
for (gint i = 0; i < entries; i ++)
{
- gint j = i + random () % (entries - i);
+ gint j = i + rand () % (entries - i);
struct entry * entry = index_get (playlist->entries, j);
index_set (playlist->entries, j, index_get (playlist->entries, i));
@@ -1377,12 +1442,12 @@ void playlist_randomize (gint playlist_num)
}
number_entries (playlist, 0, entries);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, 0, entries);
}
static gint filename_compare (const void * _a, const void * _b, void * _compare)
{
- const struct entry * a = _a, * b = _b;
+ const Entry * a = _a, * b = _b;
gint (* compare) (const gchar * a, const gchar * b) = _compare;
gint diff = compare (a->filename, b->filename);
@@ -1395,7 +1460,7 @@ static gint filename_compare (const void * _a, const void * _b, void * _compare)
static gint tuple_compare (const void * _a, const void * _b, void * _compare)
{
- const struct entry * a = _a, * b = _b;
+ const Entry * a = _a, * b = _b;
gint (* compare) (const Tuple * a, const Tuple * b) = _compare;
if (a->tuple == NULL)
@@ -1411,7 +1476,21 @@ static gint tuple_compare (const void * _a, const void * _b, void * _compare)
return a->number - b->number;
}
-static void sort (struct playlist * playlist, gint (* compare) (const void * a,
+static gint title_compare (const void * _a, const void * _b, void * _compare)
+{
+ const Entry * a = _a, * b = _b;
+ gint (* compare) (const gchar * a, const gchar * b) = _compare;
+
+ gint diff = compare (a->formatted ? a->formatted : a->filename, b->formatted
+ ? b->formatted : b->filename);
+ if (diff)
+ return diff;
+
+ /* preserve order of "equal" entries */
+ return a->number - b->number;
+}
+
+static void sort (Playlist * playlist, gint (* compare) (const void * a,
const void * b, void * inner), void * inner)
{
PLAYLIST_WILL_CHANGE;
@@ -1419,11 +1498,11 @@ static void sort (struct playlist * playlist, gint (* compare) (const void * a,
index_sort_with_data (playlist->entries, compare, inner);
number_entries (playlist, 0, index_count (playlist->entries));
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, 0, index_count (playlist->entries));
}
-static void sort_selected (struct playlist * playlist, gint (* compare)
- (const void * a, const void * b, void * inner), void * inner)
+static void sort_selected (Playlist * playlist, gint (* compare) (const void *
+ a, const void * b, void * inner), void * inner)
{
gint entries, count, count2;
struct index *selected;
@@ -1435,8 +1514,7 @@ static void sort_selected (struct playlist * playlist, gint (* compare)
for (count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
-
+ Entry * entry = index_get (playlist->entries, count);
if (entry->selected)
index_append(selected, entry);
}
@@ -1447,8 +1525,7 @@ static void sort_selected (struct playlist * playlist, gint (* compare)
for (count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
-
+ Entry * entry = index_get (playlist->entries, count);
if (entry->selected)
index_set(playlist->entries, count, index_get(selected, count2++));
}
@@ -1456,7 +1533,7 @@ static void sort_selected (struct playlist * playlist, gint (* compare)
index_free(selected);
number_entries(playlist, 0, entries);
- PLAYLIST_HAS_CHANGED;
+ PLAYLIST_HAS_CHANGED (playlist, 0, entries);
}
void playlist_sort_by_filename (gint playlist_num, gint (* compare)
@@ -1478,6 +1555,15 @@ void playlist_sort_by_tuple (gint playlist_num, gint (* compare)
sort (playlist, tuple_compare, compare);
}
+void playlist_sort_by_title (gint playlist_num, gint (* compare) (const gchar *
+ a, const gchar * b))
+{
+ DECLARE_PLAYLIST;
+ LOOKUP_PLAYLIST;
+ check_all_scanned (playlist);
+ sort (playlist, title_compare, compare);
+}
+
void playlist_sort_selected_by_filename (gint playlist_num, gint (* compare)
(const gchar * a, const gchar * b))
{
@@ -1497,6 +1583,15 @@ void playlist_sort_selected_by_tuple (gint playlist_num, gint (* compare)
sort_selected (playlist, tuple_compare, compare);
}
+void playlist_sort_selected_by_title (gint playlist_num, gint (* compare)
+ (const gchar * a, const gchar * b))
+{
+ DECLARE_PLAYLIST;
+ LOOKUP_PLAYLIST;
+ check_selected_scanned (playlist);
+ sort (playlist, title_compare, compare);
+}
+
void playlist_reformat_titles (void)
{
gint playlist_num;
@@ -1505,23 +1600,22 @@ void playlist_reformat_titles (void)
for (playlist_num = 0; playlist_num < index_count(playlists); playlist_num++)
{
- struct playlist *playlist = index_get(playlists, playlist_num);
+ Playlist * playlist = index_get (playlists, playlist_num);
gint entries = index_count(playlist->entries);
gint count;
for (count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
-
- g_free(entry->title);
- entry->title = (entry->tuple == NULL) ? NULL : title_from_tuple(entry->tuple);
+ Entry * entry = index_get (playlist->entries, count);
+ g_free(entry->formatted);
+ entry->formatted = (entry->tuple == NULL) ? NULL : title_from_tuple(entry->tuple);
}
}
- METADATA_HAS_CHANGED;
+ METADATA_HAS_CHANGED (NULL, 0, 0);
}
-void playlist_rescan(gint playlist_num)
+void playlist_rescan_real (gint playlist_num, gboolean onlyselected)
{
DECLARE_PLAYLIST;
gint entries, count;
@@ -1533,13 +1627,25 @@ void playlist_rescan(gint playlist_num)
for (count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
-
- entry_set_tuple (playlist, entry, NULL);
- entry->failed = FALSE;
+ Entry * entry = index_get (playlist->entries, count);
+ if (! onlyselected || entry->selected)
+ {
+ entry_set_tuple (playlist, entry, NULL);
+ entry->failed = FALSE;
+ }
}
- METADATA_HAS_CHANGED;
+ METADATA_HAS_CHANGED (playlist, 0, entries);
+}
+
+void playlist_rescan (gint playlist_num)
+{
+ playlist_rescan_real (playlist_num, FALSE);
+}
+
+void playlist_rescan_selected (gint playlist_num)
+{
+ playlist_rescan_real (playlist_num, TRUE);
}
void playlist_rescan_file (const gchar * filename)
@@ -1555,13 +1661,13 @@ void playlist_rescan_file (const gchar * filename)
for (playlist_num = 0; playlist_num < num_playlists; playlist_num ++)
{
- struct playlist * playlist = index_get (playlists, playlist_num);
+ Playlist * playlist = index_get (playlists, playlist_num);
gint num_entries = index_count (playlist->entries);
gint entry_num;
for (entry_num = 0; entry_num < num_entries; entry_num ++)
{
- struct entry * entry = index_get (playlist->entries, entry_num);
+ Entry * entry = index_get (playlist->entries, entry_num);
if (! strcmp (entry->filename, filename))
{
@@ -1573,7 +1679,7 @@ void playlist_rescan_file (const gchar * filename)
g_free (copy);
- METADATA_HAS_CHANGED;
+ METADATA_HAS_CHANGED (NULL, 0, 0);
}
gint64 playlist_get_total_length (gint playlist_num, gboolean fast)
@@ -1623,20 +1729,20 @@ void playlist_queue_insert(gint playlist_num, gint at, gint entry_num)
entry->queued = TRUE;
- SELECTION_HAS_CHANGED;
+ SELECTION_HAS_CHANGED (playlist, entry_num, 1);
}
void playlist_queue_insert_selected (gint playlist_num, gint at)
{
DECLARE_PLAYLIST;
- gint entries, count;
-
LOOKUP_PLAYLIST;
- entries = index_count(playlist->entries);
- for (count = 0; count < entries; count++)
+ gint entries = index_count(playlist->entries);
+ gint first = entries, last = 0;
+
+ for (gint count = 0; count < entries; count++)
{
- struct entry *entry = index_get(playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (!entry->selected || entry->queued)
continue;
@@ -1647,16 +1753,18 @@ void playlist_queue_insert_selected (gint playlist_num, gint at)
playlist->queued = g_list_insert(playlist->queued, entry, at++);
entry->queued = TRUE;
+ first = MIN (first, entry->number);
+ last = entry->number;
}
- SELECTION_HAS_CHANGED;
+ if (first < entries)
+ SELECTION_HAS_CHANGED (playlist, first, last + 1 - first);
}
gint playlist_queue_get_entry(gint playlist_num, gint at)
{
DECLARE_PLAYLIST;
GList *node;
- struct entry *entry;
LOOKUP_PLAYLIST_RET (-1);
node = g_list_nth(playlist->queued, at);
@@ -1664,8 +1772,7 @@ gint playlist_queue_get_entry(gint playlist_num, gint at)
if (node == NULL)
return -1;
- entry = node->data;
- return entry->number;
+ return ((Entry *) node->data)->number;
}
gint playlist_queue_find_entry(gint playlist_num, gint entry_num)
@@ -1683,18 +1790,22 @@ gint playlist_queue_find_entry(gint playlist_num, gint entry_num)
void playlist_queue_delete(gint playlist_num, gint at, gint number)
{
DECLARE_PLAYLIST;
-
LOOKUP_PLAYLIST;
+ gint entries = index_count (playlist->entries);
+ gint first = entries, last = 0;
+
if (at == 0)
{
while (playlist->queued != NULL && number--)
{
- struct entry *entry = playlist->queued->data;
+ Entry * entry = playlist->queued->data;
playlist->queued = g_list_delete_link(playlist->queued, playlist->queued);
entry->queued = FALSE;
+ first = MIN (first, entry->number);
+ last = entry->number;
}
}
else
@@ -1706,16 +1817,19 @@ void playlist_queue_delete(gint playlist_num, gint at, gint number)
while (anchor->next != NULL && number--)
{
- struct entry *entry = anchor->next->data;
+ Entry * entry = anchor->next->data;
playlist->queued = g_list_delete_link(playlist->queued, anchor->next);
entry->queued = FALSE;
+ first = MIN (first, entry->number);
+ last = entry->number;
}
}
DONE:
- SELECTION_HAS_CHANGED;
+ if (first < entries)
+ SELECTION_HAS_CHANGED (playlist, first, last + 1 - first);
}
void playlist_queue_delete_selected (gint playlist_num)
@@ -1723,26 +1837,36 @@ void playlist_queue_delete_selected (gint playlist_num)
DECLARE_PLAYLIST;
LOOKUP_PLAYLIST;
+ gint entries = index_count (playlist->entries);
+ gint first = entries, last = 0;
+
for (GList * node = playlist->queued; node != NULL; )
{
GList * next = node->next;
- struct entry * entry = node->data;
+ Entry * entry = node->data;
+
if (entry->selected)
+ {
playlist->queued = g_list_delete_link (playlist->queued, node);
+ first = MIN (first, entry->number);
+ last = entry->number;
+ }
+
node = next;
}
- SELECTION_HAS_CHANGED;
+ if (first < entries)
+ SELECTION_HAS_CHANGED (playlist, first, last + 1 - first);
}
-static gboolean shuffle_prev (struct playlist * playlist)
+static gboolean shuffle_prev (Playlist * playlist)
{
gint entries = index_count (playlist->entries), count;
- struct entry * found = NULL;
+ Entry * found = NULL;
for (count = 0; count < entries; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (entry->shuffle_num && (playlist->position == NULL ||
entry->shuffle_num < playlist->position->shuffle_num) && (found == NULL
@@ -1780,20 +1904,18 @@ gboolean playlist_prev_song(gint playlist_num)
if (playlist == playing_playlist && playback_get_playing ())
playback_stop();
- SELECTION_HAS_CHANGED;
-
hook_call ("playlist position", GINT_TO_POINTER (playlist_num));
return TRUE;
}
-static gboolean shuffle_next (struct playlist * playlist)
+static gboolean shuffle_next (Playlist * playlist)
{
gint entries = index_count (playlist->entries), choice = 0, count;
- struct entry * found = NULL;
+ Entry * found = NULL;
for (count = 0; count < entries; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (! entry->shuffle_num)
choice ++;
@@ -1812,11 +1934,11 @@ static gboolean shuffle_next (struct playlist * playlist)
if (! choice)
return FALSE;
- choice = random () % choice;
+ choice = rand () % choice;
for (count = 0; ; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
+ Entry * entry = index_get (playlist->entries, count);
if (! entry->shuffle_num)
{
@@ -1831,7 +1953,7 @@ static gboolean shuffle_next (struct playlist * playlist)
}
}
-static void shuffle_reset (struct playlist * playlist)
+static void shuffle_reset (Playlist * playlist)
{
gint entries = index_count (playlist->entries), count;
@@ -1839,8 +1961,7 @@ static void shuffle_reset (struct playlist * playlist)
for (count = 0; count < entries; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
-
+ Entry * entry = index_get (playlist->entries, count);
entry->shuffle_num = 0;
}
}
@@ -1896,17 +2017,10 @@ gboolean playlist_next_song(gint playlist_num, gboolean repeat)
if (playlist == playing_playlist && playback_get_playing ())
playback_stop();
- SELECTION_HAS_CHANGED;
-
hook_call ("playlist position", GINT_TO_POINTER (playlist_num));
return TRUE;
}
-gboolean playlist_update_pending (void)
-{
- return (update_source != 0);
-}
-
void playlist_save_state (void)
{
gchar scratch[512];
@@ -1914,7 +2028,7 @@ void playlist_save_state (void)
gint playlist_num;
snprintf (scratch, sizeof scratch, "%s/" STATE_FILE,
- aud_paths[BMP_PATH_USER_DIR]);
+ get_path (AUD_PATH_USER_DIR));
handle = fopen (scratch, "w");
if (handle == NULL)
@@ -1926,7 +2040,7 @@ void playlist_save_state (void)
for (playlist_num = 0; playlist_num < index_count (playlists);
playlist_num ++)
{
- struct playlist * playlist = index_get (playlists, playlist_num);
+ Playlist * playlist = index_get (playlists, playlist_num);
gint entries = index_count (playlist->entries), count;
fprintf (handle, "playlist %d\n", playlist_num);
@@ -1935,8 +2049,7 @@ void playlist_save_state (void)
for (count = 0; count < entries; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
-
+ Entry * entry = index_get (playlist->entries, count);
fprintf (handle, "S %d\n", entry->shuffle_num);
}
}
@@ -1980,10 +2093,10 @@ void playlist_load_state (void)
{
gchar scratch[512];
FILE * handle;
- gint playlist_num, obsolete = 0;
+ gint playlist_num;
snprintf (scratch, sizeof scratch, "%s/" STATE_FILE,
- aud_paths[BMP_PATH_USER_DIR]);
+ get_path (AUD_PATH_USER_DIR));
handle = fopen (scratch, "r");
if (handle == NULL)
@@ -2006,7 +2119,7 @@ void playlist_load_state (void)
while (parse_integer ("playlist", & playlist_num) && playlist_num >= 0 &&
playlist_num < index_count (playlists))
{
- struct playlist * playlist = index_get (playlists, playlist_num);
+ Playlist * playlist = index_get (playlists, playlist_num);
gint entries = index_count (playlist->entries), position, count;
parse_next (handle);
@@ -2017,6 +2130,7 @@ void playlist_load_state (void)
if (position >= 0 && position < entries)
playlist->position = index_get (playlist->entries, position);
+ gint obsolete = 0;
if (parse_integer ("shuffled", & obsolete)) /* compatibility with 2.3 */
parse_next (handle);
@@ -2027,8 +2141,7 @@ void playlist_load_state (void)
for (count = 0; count < entries; count ++)
{
- struct entry * entry = index_get (playlist->entries, count);
-
+ Entry * entry = index_get (playlist->entries, count);
if (parse_integer ("S", & entry->shuffle_num))
parse_next (handle);
}
diff --git a/src/audacious/playlist-utils.c b/src/audacious/playlist-utils.c
index 0c795c7..cbb001f 100644
--- a/src/audacious/playlist-utils.c
+++ b/src/audacious/playlist-utils.c
@@ -26,10 +26,8 @@
#include <libaudcore/audstrings.h>
#include "audconfig.h"
-#include "main.h"
#include "misc.h"
#include "playlist.h"
-#include "playlist_container.h"
#include "playlist-utils.h"
static const gchar * aud_titlestring_presets[] =
@@ -109,14 +107,15 @@ static gint tuple_compare_track (const Tuple * a, const Tuple * b)
return tuple_compare_int (a, b, FIELD_TRACK_NUMBER);
}
-static const PlaylistFilenameCompareFunc filename_comparisons[] = {
+static const PlaylistStringCompareFunc filename_comparisons[] = {
[PLAYLIST_SORT_PATH] = string_compare_encoded,
[PLAYLIST_SORT_FILENAME] = filename_compare_basename,
[PLAYLIST_SORT_TITLE] = NULL,
[PLAYLIST_SORT_ALBUM] = NULL,
[PLAYLIST_SORT_ARTIST] = NULL,
[PLAYLIST_SORT_DATE] = NULL,
- [PLAYLIST_SORT_TRACK] = NULL};
+ [PLAYLIST_SORT_TRACK] = NULL,
+ [PLAYLIST_SORT_FORMATTED_TITLE] = NULL};
static const PlaylistTupleCompareFunc tuple_comparisons[] = {
[PLAYLIST_SORT_PATH] = NULL,
@@ -125,7 +124,18 @@ static const PlaylistTupleCompareFunc tuple_comparisons[] = {
[PLAYLIST_SORT_ALBUM] = tuple_compare_album,
[PLAYLIST_SORT_ARTIST] = tuple_compare_artist,
[PLAYLIST_SORT_DATE] = tuple_compare_date,
- [PLAYLIST_SORT_TRACK] = tuple_compare_track};
+ [PLAYLIST_SORT_TRACK] = tuple_compare_track,
+ [PLAYLIST_SORT_FORMATTED_TITLE] = NULL};
+
+static const PlaylistStringCompareFunc title_comparisons[] = {
+ [PLAYLIST_SORT_PATH] = NULL,
+ [PLAYLIST_SORT_FILENAME] = NULL,
+ [PLAYLIST_SORT_TITLE] = NULL,
+ [PLAYLIST_SORT_ALBUM] = NULL,
+ [PLAYLIST_SORT_ARTIST] = NULL,
+ [PLAYLIST_SORT_DATE] = NULL,
+ [PLAYLIST_SORT_TRACK] = NULL,
+ [PLAYLIST_SORT_FORMATTED_TITLE] = string_compare};
const gchar * get_gentitle_format (void)
{
@@ -142,6 +152,8 @@ void playlist_sort_by_scheme (gint playlist, gint scheme)
playlist_sort_by_filename (playlist, filename_comparisons[scheme]);
else if (tuple_comparisons[scheme] != NULL)
playlist_sort_by_tuple (playlist, tuple_comparisons[scheme]);
+ else if (title_comparisons[scheme] != NULL)
+ playlist_sort_by_title (playlist, title_comparisons[scheme]);
}
void playlist_sort_selected_by_scheme (gint playlist, gint scheme)
@@ -151,6 +163,8 @@ void playlist_sort_selected_by_scheme (gint playlist, gint scheme)
filename_comparisons[scheme]);
else if (tuple_comparisons[scheme] != NULL)
playlist_sort_selected_by_tuple (playlist, tuple_comparisons[scheme]);
+ else if (title_comparisons[scheme] != NULL)
+ playlist_sort_selected_by_title (playlist, title_comparisons[scheme]);
}
/* Fix me: This considers empty fields as duplicates. */
@@ -216,8 +230,7 @@ void playlist_remove_failed (gint playlist)
for (count = 0; count < entries; count ++)
{
- if (playlist_entry_get_decoder (playlist, count) == NULL ||
- playlist_entry_get_tuple (playlist, count, FALSE) == NULL)
+ if (! playlist_entry_get_decoder (playlist, count, FALSE))
playlist_entry_set_selected (playlist, count, TRUE);
}
@@ -275,65 +288,14 @@ void playlist_select_by_patterns (gint playlist, const Tuple * patterns)
}
}
-gboolean filename_is_playlist (const gchar * filename)
-{
- const gchar * period = strrchr (filename, '.');
-
- return (period != NULL && playlist_container_find ((gchar *) period + 1) !=
- NULL);
-}
-
-gboolean playlist_insert_playlist (gint playlist, gint at, const gchar *
- filename)
-{
- const gchar * period = strrchr (filename, '.');
- PlaylistContainer * container;
- gint last;
-
- if (period == NULL)
- return FALSE;
-
- container = playlist_container_find ((gchar *) period + 1);
-
- if (container == NULL || container->plc_read == NULL)
- return FALSE;
-
- last = playlist_get_active ();
- playlist_set_active (playlist);
- container->plc_read (filename, at);
- playlist_set_active (last);
- return TRUE;
-}
-
-gboolean playlist_save (gint playlist, const gchar * filename)
-{
- const gchar * period = strrchr (filename, '.');
- PlaylistContainer * container;
- gint last;
-
- if (period == NULL)
- return FALSE;
-
- container = playlist_container_find ((gchar *) period + 1);
-
- if (container == NULL || container->plc_write == NULL)
- return FALSE;
-
- last = playlist_get_active ();
- playlist_set_active (playlist);
- container->plc_write (filename, 0);
- playlist_set_active (last);
- return TRUE;
-}
-
/* The algorithm is a bit quirky for historical reasons. -jlindgren */
static gchar * make_playlist_path (gint playlist)
{
if (! playlist)
- return g_strdup (aud_paths[BMP_PATH_PLAYLIST_FILE]);
+ return g_strdup (get_path (AUD_PATH_PLAYLIST_FILE));
return g_strdup_printf ("%s/playlist_%02d.xspf",
- aud_paths[BMP_PATH_PLAYLISTS_DIR], 1 + playlist);
+ get_path (AUD_PATH_PLAYLISTS_DIR), 1 + playlist);
}
void load_playlists (void)
diff --git a/src/audacious/playlist.h b/src/audacious/playlist.h
index 13f9d95..9b0b555 100644
--- a/src/audacious/playlist.h
+++ b/src/audacious/playlist.h
@@ -56,9 +56,11 @@ enum {
PLAYLIST_SORT_ARTIST,
PLAYLIST_SORT_DATE,
PLAYLIST_SORT_TRACK,
+ PLAYLIST_SORT_FORMATTED_TITLE,
PLAYLIST_SORT_SCHEMES};
-typedef gint (* PlaylistFilenameCompareFunc) (const gchar * a, const gchar * b);
+#define PlaylistFilenameCompareFunc PlaylistStringCompareFunc /* deprecated */
+typedef gint (* PlaylistStringCompareFunc) (const gchar * a, const gchar * b);
typedef gint (* PlaylistTupleCompareFunc) (const Tuple * a, const Tuple * b);
#define AUD_API_NAME PlaylistAPI
@@ -78,7 +80,8 @@ void playlist_save_state (void);
void playlist_reformat_titles (void);
-InputPlugin * playlist_entry_get_decoder (gint playlist, gint entry);
+void playlist_entry_insert_batch_with_decoders (gint playlist, gint at,
+ struct index * filenames, struct index * decoders, struct index * tuples);
void playlist_entry_set_tuple (gint playlist, gint entry, Tuple * tuple);
gboolean playlist_entry_is_segmented (gint playlist, gint entry);
diff --git a/src/audacious/playlist_container.c b/src/audacious/playlist_container.c
deleted file mode 100644
index 0462347..0000000
--- a/src/audacious/playlist_container.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2006-2007 William Pitcock, Tony Vroon, George Averill,
- * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#include <glib.h>
-#include <string.h>
-
-#include "misc.h"
-#include "playlist_container.h"
-
-/*
- * PlaylistContainer objects handle the import and export of Playlist
- * data. Basically, a PlaylistContainer acts as a filter for a PlaylistEntry.
- */
-
-static GList *registered_plcs = NULL;
-
-void playlist_container_register(PlaylistContainer *plc)
-{
- registered_plcs = g_list_append(registered_plcs, plc);
-}
-
-void playlist_container_unregister(PlaylistContainer *plc)
-{
- registered_plcs = g_list_remove(registered_plcs, plc);
-}
-
-PlaylistContainer *playlist_container_find(gchar *ext)
-{
- GList *node;
- PlaylistContainer *plc;
-
- /* check ext neither is NULL nor 1 (in a consequence of optimization). */
- g_return_val_if_fail(ext != NULL && ext != (void *)1, NULL);
-
- for (node = registered_plcs; node != NULL; node = g_list_next(node)) {
- plc = node->data;
-
- if (!g_ascii_strncasecmp(plc->ext, ext, strlen(plc->ext)))
- return plc;
- }
-
- return NULL;
-}
-
-void playlist_container_read(gchar *filename, gint pos)
-{
- gchar *ext = strrchr(filename, '.') + 1; /* optimization: skip past the dot -nenolod */
- PlaylistContainer *plc = playlist_container_find(ext);
-
- if (plc->plc_read == NULL)
- return;
-
- plc->plc_read(filename, pos);
-}
-
-void playlist_container_write(gchar *filename, gint pos)
-{
- gchar *ext = strrchr(filename, '.') + 1; /* optimization: skip past the dot -nenolod */
- PlaylistContainer *plc = playlist_container_find(ext);
-
- if (plc->plc_write == NULL)
- return;
-
- plc->plc_write(filename, pos);
-}
diff --git a/src/audacious/playlist_container.h b/src/audacious/playlist_container.h
deleted file mode 100644
index c86928d..0000000
--- a/src/audacious/playlist_container.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Audacious: A cross-platform multimedia player
- * Copyright (c) 2006-2007 William Pitcock, Tony Vroon, George Averill,
- * Giacomo Lozito, Derek Pomery and Yoshiki Yazawa.
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_PLAYLIST_CONTAINER_H
-#define AUDACIOUS_PLAYLIST_CONTAINER_H
-
-#include <glib.h>
-
-#include "misc.h"
-
-void playlist_container_read (gchar * filename, gint pos);
-void playlist_container_write (gchar * filename, gint pos);
-PlaylistContainer * playlist_container_find (gchar * ext);
-
-#endif /* AUDACIOUS_PLAYLIST_CONTAINER_H */
diff --git a/src/audacious/plugin-init.c b/src/audacious/plugin-init.c
new file mode 100644
index 0000000..a12ea11
--- /dev/null
+++ b/src/audacious/plugin-init.c
@@ -0,0 +1,298 @@
+/*
+ * plugin-init.c
+ * Copyright 2010 John Lindgren
+ *
+ * This file is part of Audacious.
+ *
+ * Audacious 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, version 2 or version 3 of the License.
+ *
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "debug.h"
+#include "effect.h"
+#include "general.h"
+#include "interface.h"
+#include "output.h"
+#include "plugin.h"
+#include "plugins.h"
+#include "ui_preferences.h"
+#include "visualization.h"
+
+static gboolean dummy_plugin_start (PluginHandle * p)
+{
+ return TRUE;
+}
+
+static void dummy_plugin_stop (PluginHandle * p)
+{
+}
+
+static const struct {
+ const gchar * name;
+ gboolean is_managed, is_single;
+
+ union {
+ struct {
+ gboolean (* start) (PluginHandle * plugin);
+ void (* stop) (PluginHandle * plugin);
+ } m;
+
+ struct {
+ PluginHandle * (* probe) (void);
+ PluginHandle * (* get_current) (void);
+ gboolean (* set_current) (PluginHandle * plugin);
+ } s;
+ } u;
+} table[PLUGIN_TYPES] = {
+ [PLUGIN_TYPE_LOWLEVEL] = {"lowlevel", FALSE},
+ [PLUGIN_TYPE_TRANSPORT] = {"transport", TRUE, FALSE, .u.m =
+ {dummy_plugin_start, dummy_plugin_stop}},
+ [PLUGIN_TYPE_PLAYLIST] = {"playlist", TRUE, FALSE, .u.m = {dummy_plugin_start,
+ dummy_plugin_stop}},
+ [PLUGIN_TYPE_INPUT] = {"input", TRUE, FALSE, .u.m = {dummy_plugin_start,
+ dummy_plugin_stop}},
+ [PLUGIN_TYPE_EFFECT] = {"effect", TRUE, FALSE, .u.m = {effect_plugin_start,
+ effect_plugin_stop}},
+ [PLUGIN_TYPE_OUTPUT] = {"output", TRUE, TRUE, .u.s = {output_plugin_probe,
+ output_plugin_get_current, output_plugin_set_current}},
+ [PLUGIN_TYPE_VIS] = {"visualization", TRUE, FALSE, .u.m = {vis_plugin_start,
+ vis_plugin_stop}},
+ [PLUGIN_TYPE_GENERAL] = {"general", TRUE, FALSE, .u.m = {general_plugin_start,
+ general_plugin_stop}},
+ [PLUGIN_TYPE_IFACE] = {"interface", TRUE, TRUE, .u.s = {iface_plugin_probe,
+ iface_plugin_get_current, iface_plugin_set_current}}};
+
+static gboolean find_enabled_cb (PluginHandle * p, PluginHandle * * pp)
+{
+ * pp = p;
+ return FALSE;
+}
+
+static PluginHandle * find_enabled (gint type)
+{
+ PluginHandle * p = NULL;
+ plugin_for_enabled (type, (PluginForEachFunc) find_enabled_cb, & p);
+ return p;
+}
+
+static void start_single (gint type)
+{
+ PluginHandle * p;
+
+ if ((p = find_enabled (type)) != NULL)
+ {
+ AUDDBG ("Starting selected %s plugin %s.\n", table[type].name,
+ plugin_get_name (p));
+
+ if (table[type].u.s.set_current (p))
+ return;
+
+ AUDDBG ("%s failed to start.\n", plugin_get_name (p));
+ plugin_set_enabled (p, FALSE);
+ }
+
+ AUDDBG ("Probing for %s plugin.\n", table[type].name);
+
+ if ((p = table[type].u.s.probe ()) == NULL)
+ {
+ fprintf (stderr, "FATAL: No %s plugin found.\n", table[type].name);
+ exit (EXIT_FAILURE);
+ }
+
+ AUDDBG ("Starting %s.\n", plugin_get_name (p));
+ plugin_set_enabled (p, TRUE);
+
+ if (! table[type].u.s.set_current (p))
+ {
+ fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (p));
+ plugin_set_enabled (p, FALSE);
+ exit (EXIT_FAILURE);
+ }
+}
+
+static gboolean start_multi_cb (PluginHandle * p, void * type)
+{
+ AUDDBG ("Starting %s.\n", plugin_get_name (p));
+
+ if (! table[GPOINTER_TO_INT (type)].u.m.start (p))
+ {
+ AUDDBG ("%s failed to start; disabling.\n", plugin_get_name (p));
+ plugin_set_enabled (p, FALSE);
+ }
+
+ return TRUE;
+}
+
+static void start_plugins (gint type)
+{
+ if (! table[type].is_managed)
+ return;
+
+ if (table[type].is_single)
+ start_single (type);
+ else
+ plugin_for_enabled (type, (PluginForEachFunc) start_multi_cb,
+ GINT_TO_POINTER (type));
+}
+
+static VFSConstructor * lookup_transport (const gchar * scheme)
+{
+ PluginHandle * plugin = transport_plugin_for_scheme (scheme);
+ if (! plugin)
+ return NULL;
+
+ TransportPlugin * tp = plugin_get_header (plugin);
+ return tp->vtable;
+}
+
+void start_plugins_one (void)
+{
+ plugin_system_init ();
+ vfs_set_lookup_func (lookup_transport);
+
+ for (gint i = 0; i < PLUGIN_TYPE_GENERAL; i ++)
+ start_plugins (i);
+}
+
+void start_plugins_two (void)
+{
+ for (gint i = PLUGIN_TYPE_GENERAL; i < PLUGIN_TYPES; i ++)
+ start_plugins (i);
+}
+
+static gboolean stop_multi_cb (PluginHandle * p, void * type)
+{
+ AUDDBG ("Shutting down %s.\n", plugin_get_name (p));
+ table[GPOINTER_TO_INT (type)].u.m.stop (p);
+ return TRUE;
+}
+
+static void stop_plugins (gint type)
+{
+ if (! table[type].is_managed)
+ return;
+
+ if (table[type].is_single)
+ {
+ AUDDBG ("Shutting down %s.\n", plugin_get_name
+ (table[type].u.s.get_current ()));
+ table[type].u.s.set_current (NULL);
+ }
+ else
+ plugin_for_enabled (type, (PluginForEachFunc) stop_multi_cb,
+ GINT_TO_POINTER (type));
+}
+
+void stop_plugins_two (void)
+{
+ for (gint i = PLUGIN_TYPES - 1; i >= PLUGIN_TYPE_GENERAL; i --)
+ stop_plugins (i);
+}
+
+void stop_plugins_one (void)
+{
+ for (gint i = PLUGIN_TYPE_GENERAL - 1; i >= 0; i --)
+ stop_plugins (i);
+
+ vfs_set_lookup_func (NULL);
+ plugin_system_cleanup ();
+}
+
+PluginHandle * plugin_get_current (gint type)
+{
+ g_return_val_if_fail (table[type].is_managed && table[type].is_single, NULL);
+ return table[type].u.s.get_current ();
+}
+
+static gboolean enable_single (gint type, PluginHandle * p)
+{
+ PluginHandle * old = table[type].u.s.get_current ();
+
+ AUDDBG ("Switching from %s to %s.\n", plugin_get_name (old),
+ plugin_get_name (p));
+ plugin_set_enabled (old, FALSE);
+ plugin_set_enabled (p, TRUE);
+
+ if (table[type].u.s.set_current (p))
+ return TRUE;
+
+ fprintf (stderr, "%s failed to start; falling back to %s.\n",
+ plugin_get_name (p), plugin_get_name (old));
+ plugin_set_enabled (p, FALSE);
+ plugin_set_enabled (old, TRUE);
+
+ if (table[type].u.s.set_current (old))
+ return FALSE;
+
+ fprintf (stderr, "FATAL: %s failed to start.\n", plugin_get_name (old));
+ plugin_set_enabled (old, FALSE);
+ exit (EXIT_FAILURE);
+}
+
+static gboolean enable_multi (gint type, PluginHandle * p, gboolean enable)
+{
+ AUDDBG ("%sabling %s.\n", enable ? "En" : "Dis", plugin_get_name (p));
+ plugin_set_enabled (p, enable);
+
+ if (enable)
+ {
+ if (! table[type].u.m.start (p))
+ {
+ fprintf (stderr, "%s failed to start.\n", plugin_get_name (p));
+ plugin_set_enabled (p, FALSE);
+ return FALSE;
+ }
+ }
+ else
+ table[type].u.m.stop (p);
+
+ return TRUE;
+}
+
+gboolean plugin_enable (PluginHandle * plugin, gboolean enable)
+{
+ if (! enable == ! plugin_get_enabled (plugin))
+ {
+ AUDDBG ("%s is already %sabled.\n", plugin_get_name (plugin), enable ?
+ "en" : "dis");
+ return TRUE;
+ }
+
+ gint type = plugin_get_type (plugin);
+ g_return_val_if_fail (table[type].is_managed, FALSE);
+
+ if (table[type].is_single)
+ {
+ g_return_val_if_fail (enable, FALSE);
+ return enable_single (type, plugin);
+ }
+
+ return enable_multi (type, plugin, enable);
+}
+
+/* This doesn't really belong here, but it's a bit of an oddball. */
+PluginHandle * plugin_by_widget (/* GtkWidget * */ void * widget)
+{
+ PluginHandle * p;
+ if ((p = vis_plugin_by_widget (widget)))
+ return p;
+ if ((p = general_plugin_by_widget (widget)))
+ return p;
+ return NULL;
+}
diff --git a/src/audacious/plugin-registry.c b/src/audacious/plugin-registry.c
index 15ec913..59b5464 100644
--- a/src/audacious/plugin-registry.c
+++ b/src/audacious/plugin-registry.c
@@ -28,15 +28,13 @@
#include "debug.h"
#include "interface.h"
-#include "main.h"
#include "misc.h"
#include "plugin.h"
-#include "pluginenum.h"
#include "plugins.h"
#include "util.h"
#define FILENAME "plugin-registry"
-#define FORMAT 2
+#define FORMAT 5
typedef struct {
gchar * path;
@@ -47,31 +45,50 @@ typedef struct {
} ModuleData;
typedef struct {
+ GList * schemes;
+} TransportPluginData;
+
+typedef struct {
+ GList * exts;
+} PlaylistPluginData;
+
+typedef struct {
GList * keys[INPUT_KEYS];
+ gboolean has_images, has_subtunes, can_write_tuple, has_infowin;
} InputPluginData;
struct PluginHandle {
ModuleData * module;
gint type, number;
gboolean confirmed;
- void * header;
+ const void * header;
gchar * name;
gint priority;
gboolean has_about, has_configure, enabled;
+ GList * watches;
union {
+ TransportPluginData t;
+ PlaylistPluginData p;
InputPluginData i;
} u;
};
+typedef struct {
+ PluginForEachFunc func;
+ void * data;
+} PluginWatch;
+
static const gchar * plugin_type_names[] = {
- [PLUGIN_TYPE_BASIC] = NULL,
+ [PLUGIN_TYPE_LOWLEVEL] = NULL,
+ [PLUGIN_TYPE_TRANSPORT] = "transport",
+ [PLUGIN_TYPE_PLAYLIST] = "playlist",
[PLUGIN_TYPE_INPUT] = "input",
- [PLUGIN_TYPE_OUTPUT] = "output",
[PLUGIN_TYPE_EFFECT] = "effect",
+ [PLUGIN_TYPE_OUTPUT] = "output",
[PLUGIN_TYPE_VIS] = "vis",
- [PLUGIN_TYPE_IFACE] = "iface",
- [PLUGIN_TYPE_GENERAL] = "general"};
+ [PLUGIN_TYPE_GENERAL] = "general",
+ [PLUGIN_TYPE_IFACE] = "iface"};
static const gchar * input_key_names[] = {
[INPUT_KEY_SCHEME] = "scheme",
[INPUT_KEY_EXTENSION] = "ext",
@@ -97,7 +114,7 @@ static ModuleData * module_new (gchar * path, gboolean confirmed, gint
}
static PluginHandle * plugin_new (ModuleData * module, gint type, gint number,
- gboolean confirmed, void * header)
+ gboolean confirmed, const void * header)
{
PluginHandle * plugin = g_malloc (sizeof (PluginHandle));
@@ -111,14 +128,27 @@ static PluginHandle * plugin_new (ModuleData * module, gint type, gint number,
plugin->has_about = FALSE;
plugin->has_configure = FALSE;
plugin->enabled = FALSE;
+ plugin->watches = NULL;
- if (type == PLUGIN_TYPE_INPUT)
+ if (type == PLUGIN_TYPE_TRANSPORT)
{
plugin->enabled = TRUE;
- memset (plugin->u.i.keys, 0, sizeof plugin->u.i.keys);
+ plugin->u.t.schemes = NULL;
}
- else if (type == PLUGIN_TYPE_IFACE)
+ else if (type == PLUGIN_TYPE_PLAYLIST)
+ {
plugin->enabled = TRUE;
+ plugin->u.p.exts = NULL;
+ }
+ else if (type == PLUGIN_TYPE_INPUT)
+ {
+ plugin->enabled = TRUE;
+ memset (plugin->u.i.keys, 0, sizeof plugin->u.i.keys);
+ plugin->u.i.has_images = FALSE;
+ plugin->u.i.has_subtunes = FALSE;
+ plugin->u.i.can_write_tuple = FALSE;
+ plugin->u.i.has_infowin = FALSE;
+ }
plugin_list = g_list_prepend (plugin_list, plugin);
module->plugin_list = g_list_prepend (module->plugin_list, plugin);
@@ -131,7 +161,20 @@ static void plugin_free (PluginHandle * plugin, ModuleData * module)
plugin_list = g_list_remove (plugin_list, plugin);
module->plugin_list = g_list_remove (module->plugin_list, plugin);
- if (plugin->type == PLUGIN_TYPE_INPUT)
+ g_list_foreach (plugin->watches, (GFunc) g_free, NULL);
+ g_list_free (plugin->watches);
+
+ if (plugin->type == PLUGIN_TYPE_TRANSPORT)
+ {
+ g_list_foreach (plugin->u.t.schemes, (GFunc) g_free, NULL);
+ g_list_free (plugin->u.t.schemes);
+ }
+ else if (plugin->type == PLUGIN_TYPE_PLAYLIST)
+ {
+ g_list_foreach (plugin->u.p.exts, (GFunc) g_free, NULL);
+ g_list_free (plugin->u.p.exts);
+ }
+ else if (plugin->type == PLUGIN_TYPE_INPUT)
{
for (gint key = 0; key < INPUT_KEYS; key ++)
{
@@ -157,10 +200,22 @@ static void module_free (ModuleData * module)
static FILE * open_registry_file (const gchar * mode)
{
gchar path[PATH_MAX];
- snprintf (path, sizeof path, "%s/" FILENAME, aud_paths[BMP_PATH_USER_DIR]);
+ snprintf (path, sizeof path, "%s/" FILENAME, get_path (AUD_PATH_USER_DIR));
return fopen (path, mode);
}
+static void transport_plugin_save (PluginHandle * plugin, FILE * handle)
+{
+ for (GList * node = plugin->u.t.schemes; node; node = node->next)
+ fprintf (handle, "scheme %s\n", (const gchar *) node->data);
+}
+
+static void playlist_plugin_save (PluginHandle * plugin, FILE * handle)
+{
+ for (GList * node = plugin->u.p.exts; node; node = node->next)
+ fprintf (handle, "ext %s\n", (const gchar *) node->data);
+}
+
static void input_plugin_save (PluginHandle * plugin, FILE * handle)
{
for (gint key = 0; key < INPUT_KEYS; key ++)
@@ -170,6 +225,11 @@ static void input_plugin_save (PluginHandle * plugin, FILE * handle)
fprintf (handle, "%s %s\n", input_key_names[key], (const gchar *)
node->data);
}
+
+ fprintf (handle, "images %d\n", plugin->u.i.has_images);
+ fprintf (handle, "subtunes %d\n", plugin->u.i.has_subtunes);
+ fprintf (handle, "writes %d\n", plugin->u.i.can_write_tuple);
+ fprintf (handle, "infowin %d\n", plugin->u.i.has_infowin);
}
static void plugin_save (PluginHandle * plugin, FILE * handle)
@@ -181,12 +241,14 @@ static void plugin_save (PluginHandle * plugin, FILE * handle)
fprintf (handle, "config %d\n", plugin->has_configure);
fprintf (handle, "enabled %d\n", plugin->enabled);
- if (plugin->type == PLUGIN_TYPE_INPUT)
+ if (plugin->type == PLUGIN_TYPE_TRANSPORT)
+ transport_plugin_save (plugin, handle);
+ else if (plugin->type == PLUGIN_TYPE_PLAYLIST)
+ playlist_plugin_save (plugin, handle);
+ else if (plugin->type == PLUGIN_TYPE_INPUT)
input_plugin_save (plugin, handle);
}
-/* If the module contains any plugins that we do not handle, we do not save it,
- * thereby forcing it to be loaded on next startup. */
static gint plugin_not_handled_cb (PluginHandle * plugin)
{
return (plugin_type_names[plugin->type] == NULL) ? 0 : -1;
@@ -194,8 +256,12 @@ static gint plugin_not_handled_cb (PluginHandle * plugin)
static void module_save (ModuleData * module, FILE * handle)
{
- if (g_list_find_custom (module->plugin_list, NULL, (GCompareFunc)
- plugin_not_handled_cb) != NULL)
+ /* If the module contains any plugins that we do not handle, we do not save
+ * it, thereby forcing it to be loaded on next startup. If the module
+ * appears to contain no plugins at all, we can assume that it failed to
+ * load, in which case we also want to try to load it again. */
+ if (! module->plugin_list || g_list_find_custom (module->plugin_list, NULL,
+ (GCompareFunc) plugin_not_handled_cb) != NULL)
return;
fprintf (handle, "module %s\n", module->path);
@@ -252,6 +318,26 @@ static gchar * parse_string (const gchar * key)
(parse_value) : NULL;
}
+static void transport_plugin_parse (PluginHandle * plugin, FILE * handle)
+{
+ gchar * value;
+ while ((value = parse_string ("scheme")))
+ {
+ plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, value);
+ parse_next (handle);
+ }
+}
+
+static void playlist_plugin_parse (PluginHandle * plugin, FILE * handle)
+{
+ gchar * value;
+ while ((value = parse_string ("ext")))
+ {
+ plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, value);
+ parse_next (handle);
+ }
+}
+
static void input_plugin_parse (PluginHandle * plugin, FILE * handle)
{
for (gint key = 0; key < INPUT_KEYS; key ++)
@@ -264,6 +350,15 @@ static void input_plugin_parse (PluginHandle * plugin, FILE * handle)
parse_next (handle);
}
}
+
+ if (parse_integer ("images", & plugin->u.i.has_images))
+ parse_next (handle);
+ if (parse_integer ("subtunes", & plugin->u.i.has_subtunes))
+ parse_next (handle);
+ if (parse_integer ("writes", & plugin->u.i.can_write_tuple))
+ parse_next (handle);
+ if (parse_integer ("infowin", & plugin->u.i.has_infowin))
+ parse_next (handle);
}
static gboolean plugin_parse (ModuleData * module, FILE * handle)
@@ -293,7 +388,11 @@ FOUND:;
if (parse_integer ("enabled", & plugin->enabled))
parse_next (handle);
- if (type == PLUGIN_TYPE_INPUT)
+ if (type == PLUGIN_TYPE_TRANSPORT)
+ transport_plugin_parse (plugin, handle);
+ else if (type == PLUGIN_TYPE_PLAYLIST)
+ playlist_plugin_parse (plugin, handle);
+ else if (type == PLUGIN_TYPE_INPUT)
input_plugin_parse (plugin, handle);
return TRUE;
@@ -333,14 +432,14 @@ void plugin_registry_load (void)
gint format;
if (! parse_integer ("format", & format) || format != FORMAT)
- goto ERROR;
+ goto ERR;
parse_next (handle);
while (module_parse (handle))
;
-ERROR:
+ERR:
fclose (handle);
UNLOCK:
registry_locked = FALSE;
@@ -450,7 +549,8 @@ static gint plugin_lookup_cb (PluginHandle * plugin, PluginLookupState * state)
: -1;
}
-static PluginHandle * plugin_lookup (ModuleData * module, gint type, gint number)
+static PluginHandle * plugin_lookup_real (ModuleData * module, gint type, gint
+ number)
{
PluginLookupState state = {type, number};
GList * node = g_list_find_custom (module->plugin_list, & state,
@@ -458,12 +558,13 @@ static PluginHandle * plugin_lookup (ModuleData * module, gint type, gint number
return (node != NULL) ? node->data : NULL;
}
-void plugin_register (const gchar * path, gint type, gint number, void * header)
+void plugin_register (gint type, const gchar * path, gint number, const void *
+ header)
{
ModuleData * module = module_lookup (path);
g_return_if_fail (module != NULL);
- PluginHandle * plugin = plugin_lookup (module, type, number);
+ PluginHandle * plugin = plugin_lookup_real (module, type, number);
if (plugin == NULL)
{
AUDDBG ("New plugin: %s %d:%d\n", path, type, number);
@@ -475,14 +576,33 @@ void plugin_register (const gchar * path, gint type, gint number, void * header)
plugin->confirmed = TRUE;
plugin->header = header;
- if (type == PLUGIN_TYPE_INPUT)
+ if (type != PLUGIN_TYPE_LOWLEVEL && type != PLUGIN_TYPE_IFACE)
{
- InputPlugin * ip = header;
+ Plugin * gp = header;
g_free (plugin->name);
- plugin->name = g_strdup (ip->description);
+ plugin->name = g_strdup (gp->description);
+ plugin->has_about = (gp->about != NULL);
+ plugin->has_configure = (gp->configure != NULL || gp->settings != NULL);
+ }
+
+ if (type == PLUGIN_TYPE_TRANSPORT)
+ {
+ TransportPlugin * tp = header;
+ for (gint i = 0; tp->schemes[i]; i ++)
+ plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, g_strdup
+ (tp->schemes[i]));
+ }
+ else if (type == PLUGIN_TYPE_PLAYLIST)
+ {
+ PlaylistPlugin * pp = header;
+ for (gint i = 0; pp->extensions[i]; i ++)
+ plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, g_strdup
+ (pp->extensions[i]));
+ }
+ else if (type == PLUGIN_TYPE_INPUT)
+ {
+ InputPlugin * ip = header;
plugin->priority = ip->priority;
- plugin->has_about = (ip->about != NULL);
- plugin->has_configure = (ip->configure != NULL);
for (gint key = 0; key < INPUT_KEYS; key ++)
{
@@ -498,67 +618,55 @@ void plugin_register (const gchar * path, gint type, gint number, void * header)
(plugin->u.i.keys[INPUT_KEY_EXTENSION], g_strdup
(ip->vfs_extensions[i]));
}
+
+ plugin->u.i.has_images = (ip->get_song_image != NULL);
+ plugin->u.i.has_subtunes = ip->have_subtune;
+ plugin->u.i.can_write_tuple = (ip->update_song_tuple != NULL);
+ plugin->u.i.has_infowin = (ip->file_info_box != NULL);
}
else if (type == PLUGIN_TYPE_OUTPUT)
{
OutputPlugin * op = header;
- g_free (plugin->name);
- plugin->name = g_strdup (op->description);
plugin->priority = 10 - op->probe_priority;
- plugin->has_about = (op->about != NULL);
- plugin->has_configure = (op->configure != NULL);
}
else if (type == PLUGIN_TYPE_EFFECT)
{
EffectPlugin * ep = header;
- g_free (plugin->name);
- plugin->name = g_strdup (ep->description);
plugin->priority = ep->order;
- plugin->has_about = (ep->about != NULL);
- plugin->has_configure = (ep->configure != NULL);
- }
- else if (type == PLUGIN_TYPE_VIS)
- {
- VisPlugin * vp = header;
- g_free (plugin->name);
- plugin->name = g_strdup (vp->description);
- plugin->has_about = (vp->about != NULL);
- plugin->has_configure = (vp->configure != NULL);
}
else if (type == PLUGIN_TYPE_IFACE)
{
- Interface * i = header;
+ Iface * i = (void *) header;
g_free (plugin->name);
plugin->name = g_strdup (i->desc);
}
- else if (type == PLUGIN_TYPE_GENERAL)
- {
- GeneralPlugin * gp = header;
- g_free (plugin->name);
- plugin->name = g_strdup (gp->description);
- plugin->has_about = (gp->about != NULL);
- plugin->has_configure = (gp->configure != NULL);
- }
}
-void plugin_get_path (PluginHandle * plugin, const gchar * * path, gint * type,
- gint * number)
+gint plugin_get_type (PluginHandle * plugin)
+{
+ return plugin->type;
+}
+
+const gchar * plugin_get_filename (PluginHandle * plugin)
+{
+ return plugin->module->path;
+}
+
+gint plugin_get_number (PluginHandle * plugin)
{
- * path = plugin->module->path;
- * type = plugin->type;
- * number = plugin->number;
+ return plugin->number;
}
-PluginHandle * plugin_by_path (const gchar * path, gint type, gint number)
+PluginHandle * plugin_lookup (gint type, const gchar * path, gint number)
{
ModuleData * module = module_lookup (path);
if (module == NULL)
return NULL;
- return plugin_lookup (module, type, number);
+ return plugin_lookup_real (module, type, number);
}
-void * plugin_get_header (PluginHandle * plugin)
+const void * plugin_get_header (PluginHandle * plugin)
{
if (! plugin->module->loaded)
{
@@ -569,12 +677,12 @@ void * plugin_get_header (PluginHandle * plugin)
return plugin->header;
}
-static gint plugin_by_header_cb (PluginHandle * plugin, void * header)
+static gint plugin_by_header_cb (PluginHandle * plugin, const void * header)
{
return (plugin->header == header) ? 0 : -1;
}
-PluginHandle * plugin_by_header (void * header)
+PluginHandle * plugin_by_header (const void * header)
{
GList * node = g_list_find_custom (plugin_list, header, (GCompareFunc)
plugin_by_header_cb);
@@ -612,9 +720,27 @@ gboolean plugin_get_enabled (PluginHandle * plugin)
return plugin->enabled;
}
+static void plugin_call_watches (PluginHandle * plugin)
+{
+ for (GList * node = plugin->watches; node != NULL; )
+ {
+ GList * next = node->next;
+ PluginWatch * watch = node->data;
+
+ if (! watch->func (plugin, watch->data))
+ {
+ g_free (watch);
+ plugin->watches = g_list_delete_link (plugin->watches, node);
+ }
+
+ node = next;
+ }
+}
+
void plugin_set_enabled (PluginHandle * plugin, gboolean enabled)
{
plugin->enabled = enabled;
+ plugin_call_watches (plugin);
}
typedef struct {
@@ -636,6 +762,82 @@ void plugin_for_enabled (gint type, PluginForEachFunc func, void * data)
plugin_for_each (type, (PluginForEachFunc) plugin_for_enabled_cb, & state);
}
+void plugin_add_watch (PluginHandle * plugin, PluginForEachFunc func, void *
+ data)
+{
+ PluginWatch * watch = g_malloc (sizeof (PluginWatch));
+ watch->func = func;
+ watch->data = data;
+ plugin->watches = g_list_prepend (plugin->watches, watch);
+}
+
+void plugin_remove_watch (PluginHandle * plugin, PluginForEachFunc func, void *
+ data)
+{
+ for (GList * node = plugin->watches; node != NULL; )
+ {
+ GList * next = node->next;
+ PluginWatch * watch = node->data;
+
+ if (watch->func == func && watch->data == data)
+ {
+ g_free (watch);
+ plugin->watches = g_list_delete_link (plugin->watches, node);
+ }
+
+ node = next;
+ }
+}
+
+
+typedef struct {
+ const gchar * scheme;
+ PluginHandle * plugin;
+} TransportPluginForSchemeState;
+
+static gboolean transport_plugin_for_scheme_cb (PluginHandle * plugin,
+ TransportPluginForSchemeState * state)
+{
+ if (! g_list_find_custom (plugin->u.t.schemes, state->scheme, (GCompareFunc)
+ strcasecmp))
+ return TRUE;
+
+ state->plugin = plugin;
+ return FALSE;
+}
+
+PluginHandle * transport_plugin_for_scheme (const gchar * scheme)
+{
+ TransportPluginForSchemeState state = {scheme, NULL};
+ plugin_for_enabled (PLUGIN_TYPE_TRANSPORT, (PluginForEachFunc)
+ transport_plugin_for_scheme_cb, & state);
+ return state.plugin;
+}
+
+typedef struct {
+ const gchar * ext;
+ PluginHandle * plugin;
+} PlaylistPluginForExtState;
+
+static gboolean playlist_plugin_for_ext_cb (PluginHandle * plugin,
+ PlaylistPluginForExtState * state)
+{
+ if (! g_list_find_custom (plugin->u.p.exts, state->ext, (GCompareFunc)
+ strcasecmp))
+ return TRUE;
+
+ state->plugin = plugin;
+ return FALSE;
+}
+
+PluginHandle * playlist_plugin_for_extension (const gchar * extension)
+{
+ PlaylistPluginForExtState state = {extension, NULL};
+ plugin_for_enabled (PLUGIN_TYPE_PLAYLIST, (PluginForEachFunc)
+ playlist_plugin_for_ext_cb, & state);
+ return state.plugin;
+}
+
typedef struct {
gint key;
const gchar * value;
@@ -679,3 +881,27 @@ void mime_set_plugin (const gchar * mime, InputPlugin * header)
{
input_plugin_add_key (header, INPUT_KEY_MIME, mime);
}
+
+gboolean input_plugin_has_images (PluginHandle * plugin)
+{
+ g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
+ return plugin->u.i.has_images;
+}
+
+gboolean input_plugin_has_subtunes (PluginHandle * plugin)
+{
+ g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
+ return plugin->u.i.has_subtunes;
+}
+
+gboolean input_plugin_can_write_tuple (PluginHandle * plugin)
+{
+ g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
+ return plugin->u.i.can_write_tuple;
+}
+
+gboolean input_plugin_has_infowin (PluginHandle * plugin)
+{
+ g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
+ return plugin->u.i.has_infowin;
+}
diff --git a/src/audacious/plugin-view.c b/src/audacious/plugin-view.c
new file mode 100644
index 0000000..818adc1
--- /dev/null
+++ b/src/audacious/plugin-view.c
@@ -0,0 +1,269 @@
+/*
+ * plugin-view.c
+ * Copyright 2010 John Lindgren
+ *
+ * This file is part of Audacious.
+ *
+ * Audacious 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, version 2 or version 3 of the License.
+ *
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
+ */
+
+#include <gtk/gtk.h>
+
+#include "plugin.h"
+#include "plugins.h"
+#include "ui_preferences.h"
+
+enum {
+ PVIEW_COL_NODE,
+ PVIEW_COL_ENABLED,
+ PVIEW_COL_NAME,
+ PVIEW_COL_PATH,
+ PVIEW_COLS
+};
+
+typedef struct {
+ PluginHandle * p;
+ GtkTreeModel * model;
+ GtkTreePath * path;
+} Node;
+
+static PluginHandle * get_selected_plugin (GtkTreeView * tree)
+{
+ Node * n = NULL;
+
+ GtkTreeSelection * sel = gtk_tree_view_get_selection (tree);
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (sel, & model, & iter))
+ gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1);
+
+ return n == NULL ? NULL : n->p;
+}
+
+static Plugin * get_selected_header (GtkTreeView * tree)
+{
+ PluginHandle * p = get_selected_plugin (tree);
+ g_return_val_if_fail (p != NULL, NULL);
+ g_return_val_if_fail (plugin_get_enabled (p), NULL);
+ return plugin_get_header (p);
+}
+
+static void do_enable (GtkCellRendererToggle * cell, const gchar * path_str,
+ GtkTreeModel * model)
+{
+ GtkTreePath * path = gtk_tree_path_new_from_string (path_str);
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (model, & iter, path);
+ gtk_tree_path_free (path);
+
+ Node * n = NULL;
+ gboolean enabled;
+ gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n,
+ PVIEW_COL_ENABLED, & enabled, -1);
+ g_return_if_fail (n != NULL);
+
+ plugin_enable (n->p, ! enabled);
+}
+
+static gboolean list_watcher (PluginHandle * p, Node * n)
+{
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (n->model, & iter, n->path);
+ gtk_list_store_set ((GtkListStore *) n->model, & iter, PVIEW_COL_ENABLED,
+ plugin_get_enabled (n->p), -1);
+ return TRUE;
+}
+
+static gboolean fill_cb (PluginHandle * p, GtkTreeModel * model)
+{
+ Node * n = g_slice_new (Node);
+
+ GtkTreeIter iter;
+ gtk_list_store_append ((GtkListStore *) model, & iter);
+ gtk_list_store_set ((GtkListStore *) model, & iter, PVIEW_COL_NODE, n,
+ PVIEW_COL_ENABLED, plugin_get_enabled (p), PVIEW_COL_NAME, plugin_get_name
+ (p), PVIEW_COL_PATH, plugin_get_filename (p), -1);
+
+ n->p = p;
+ n->model = model;
+ n->path = gtk_tree_model_get_path (model, & iter);
+
+ plugin_add_watch (p, (PluginForEachFunc) list_watcher, n);
+
+ return TRUE;
+}
+
+static void list_fill (GtkTreeView * tree, void * type)
+{
+ GtkTreeModel * model = (GtkTreeModel *) gtk_list_store_new (PVIEW_COLS,
+ G_TYPE_POINTER, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
+ gtk_tree_view_set_model (tree, model);
+
+ GtkTreeViewColumn * col = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+ gtk_tree_view_column_set_resizable (col, FALSE);
+ gtk_tree_view_append_column (tree, col);
+
+ GtkCellRenderer * rend = gtk_cell_renderer_toggle_new ();
+ g_signal_connect (rend, "toggled", (GCallback) do_enable, model);
+ gtk_tree_view_column_pack_start (col, rend, FALSE);
+ gtk_tree_view_column_set_attributes (col, rend, "active", PVIEW_COL_ENABLED,
+ NULL);
+
+ for (gint i = PVIEW_COL_NAME; i <= PVIEW_COL_PATH; i ++)
+ {
+ col = gtk_tree_view_column_new ();
+ gtk_tree_view_column_set_sizing (col, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+ gtk_tree_view_column_set_resizable (col, FALSE);
+ gtk_tree_view_append_column (tree, col);
+
+ rend = gtk_cell_renderer_text_new ();
+ gtk_tree_view_column_pack_start (col, rend, FALSE);
+ gtk_tree_view_column_set_attributes (col, rend, "text", i, NULL);
+ }
+
+ plugin_for_each (GPOINTER_TO_INT (type), (PluginForEachFunc) fill_cb, model);
+}
+
+static void list_destroy (GtkTreeView * tree)
+{
+ GtkTreeModel * model = gtk_tree_view_get_model (tree);
+ if (model == NULL)
+ return;
+
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter_first (model, & iter))
+ {
+ do
+ {
+ Node * n = NULL;
+ gtk_tree_model_get (model, & iter, PVIEW_COL_NODE, & n, -1);
+ g_return_if_fail (n != NULL);
+
+ plugin_remove_watch (n->p, (PluginForEachFunc) list_watcher, n);
+ gtk_tree_path_free (n->path);
+ g_slice_free (Node, n);
+ }
+ while (gtk_tree_model_iter_next (model, & iter));
+ }
+
+ g_object_unref ((GObject *) model);
+}
+
+static gboolean config_watcher (PluginHandle * p, GtkWidget * config)
+{
+ gtk_widget_set_sensitive (config, plugin_has_configure (p) &&
+ plugin_get_enabled (p));
+ return TRUE;
+}
+
+static gboolean about_watcher (PluginHandle * p, GtkWidget * about)
+{
+ gtk_widget_set_sensitive (about, plugin_has_about (p) && plugin_get_enabled
+ (p));
+ return TRUE;
+}
+
+static void button_update (GtkTreeView * tree, GtkWidget * b)
+{
+ PluginForEachFunc watcher = g_object_get_data ((GObject *) b, "watcher");
+ g_return_if_fail (watcher != NULL);
+
+ PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin");
+ if (p != NULL)
+ plugin_remove_watch (p, watcher, b);
+
+ p = get_selected_plugin (tree);
+ if (p != NULL)
+ {
+ g_object_set_data ((GObject *) b, "plugin", p);
+ watcher (p, b);
+ plugin_add_watch (p, watcher, b);
+ }
+ else
+ gtk_widget_set_sensitive (b, FALSE);
+}
+
+static void do_config (GtkTreeView * tree)
+{
+ Plugin * header = get_selected_header (tree);
+ g_return_if_fail (header != NULL);
+
+ if (header->configure != NULL)
+ header->configure ();
+ else if (header->settings != NULL)
+ plugin_preferences_show (header->settings);
+}
+
+static void do_about (GtkTreeView * tree)
+{
+ Plugin * header = get_selected_header (tree);
+ g_return_if_fail (header != NULL);
+
+ if (header->about != NULL)
+ header->about ();
+}
+
+static void button_destroy (GtkWidget * b)
+{
+ PluginForEachFunc watcher = g_object_get_data ((GObject *) b, "watcher");
+ g_return_if_fail (watcher != NULL);
+
+ PluginHandle * p = g_object_steal_data ((GObject *) b, "plugin");
+ if (p != NULL)
+ plugin_remove_watch (p, watcher, b);
+}
+
+GtkWidget * plugin_view_new (gint type)
+{
+ GtkWidget * vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_set_border_width ((GtkContainer *) vbox, 6);
+
+ GtkWidget * scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start ((GtkBox *) vbox, scrolled, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolled,
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolled,
+ GTK_SHADOW_IN);
+
+ GtkWidget * tree = gtk_tree_view_new ();
+ gtk_container_add ((GtkContainer *) scrolled, tree);
+ gtk_tree_view_set_headers_visible ((GtkTreeView *) tree, FALSE);
+ g_signal_connect (tree, "realize", (GCallback) list_fill, GINT_TO_POINTER
+ (type));
+ g_signal_connect (tree, "destroy", (GCallback) list_destroy, NULL);
+
+ GtkWidget * hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0);
+
+ GtkWidget * config = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
+ gtk_box_pack_start ((GtkBox *) hbox, config, FALSE, FALSE, 0);
+ gtk_widget_set_sensitive (config, FALSE);
+ g_object_set_data ((GObject *) config, "watcher", config_watcher);
+ g_signal_connect (tree, "cursor-changed", (GCallback) button_update, config);
+ g_signal_connect_swapped (config, "clicked", (GCallback)
+ do_config, tree);
+ g_signal_connect (config, "destroy", (GCallback) button_destroy, NULL);
+
+ GtkWidget * about = gtk_button_new_from_stock (GTK_STOCK_ABOUT);
+ gtk_box_pack_start ((GtkBox *) hbox, about, FALSE, FALSE, 0);
+ gtk_widget_set_sensitive (about, FALSE);
+ g_object_set_data ((GObject *) about, "watcher", about_watcher);
+ g_signal_connect (tree, "cursor-changed", (GCallback) button_update, about);
+ g_signal_connect_swapped (about, "clicked", (GCallback) do_about, tree);
+ g_signal_connect (about, "destroy", (GCallback) button_destroy, NULL);
+
+ return vbox;
+}
diff --git a/src/audacious/plugin.h b/src/audacious/plugin.h
index c5321f5..d8958c5 100644
--- a/src/audacious/plugin.h
+++ b/src/audacious/plugin.h
@@ -1,41 +1,24 @@
-/* Audacious
- * Copyright (C) 2005-2010 Audacious team.
+/*
+ * plugin.h
+ * Copyright 2005-2010 Audacious Development Team
*
- * BMP - Cross-platform multimedia player
- * Copyright (C) 2003-2004 BMP development team.
+ * This file is part of Audacious.
*
- * Based on XMMS:
- * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies
+ * Audacious 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, version 2 or version 3 of the License.
*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-/**
- * @file plugin.h
- * @brief Main Audacious plugin API header file.
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
*
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
*/
+
#ifndef AUDACIOUS_PLUGIN_H
#define AUDACIOUS_PLUGIN_H
@@ -48,132 +31,149 @@
#include <libaudcore/tuple.h>
#include <libaudcore/vfs.h>
-//@{
-/** Preprocessor defines for different API features */
-#define __AUDACIOUS_PLUGIN_API__ 17 /**< Current generic plugin API/ABI version, exact match is required for plugin to be loaded. */
-//@}
-
-typedef enum {
- PLUGIN_MESSAGE_ERROR = 0,
- PLUGIN_MESSAGE_OK = 1,
- PLUGIN_MESSAGE_DEFERRED = 2
-} PluginMessageResponse;
+/* "Magic" bytes identifying an Audacious plugin header. */
+#define _AUD_PLUGIN_MAGIC 0x8EAC8DE2
-typedef struct _InputPlayback InputPlayback;
+/* API version. Plugins are marked with this number at compile time.
+ *
+ * _AUD_PLUGIN_VERSION is the current version; _AUD_PLUGIN_VERSION_MIN is
+ * the oldest one we are backward compatible with. Plugins marked older than
+ * _AUD_PLUGIN_VERSION_MIN or newer than _AUD_PLUGIN_VERSION are not loaded.
+ *
+ * Before releases that add new pointers to the end of the API tables, increment
+ * _AUD_PLUGIN_VERSION but leave _AUD_PLUGIN_VERSION_MIN the same.
+ *
+ * Before releases that break backward compatibility (e.g. remove pointers from
+ * the API tables), increment _AUD_PLUGIN_VERSION *and* set
+ * _AUD_PLUGIN_VERSION_MIN to the same value. */
-/** ReplayGain information structure */
-typedef struct {
- gfloat track_gain; /**< Track gain in decibels (dB) */
- gfloat track_peak;
- gfloat album_gain;
- gfloat album_peak;
-} ReplayGainInfo;
+#define _AUD_PLUGIN_VERSION_MIN 18 /* 2.5-alpha1 */
+#define _AUD_PLUGIN_VERSION 20 /* 2.5-beta2 */
/**
* The plugin module header. Each module can contain several plugins,
* of any supported type.
*/
-typedef struct {
- gint magic; /**< Audacious plugin module magic ID */
- gint api_version; /**< API version plugin has been compiled for,
- this is checked against __AUDACIOUS_PLUGIN_API__ */
- gchar *name; /**< Module name */
+typedef const struct {
+ gint magic; /* checked against _AUD_PLUGIN_MAGIC */
+ gint version; /* checked against _AUD_PLUGIN_VERSION */
+ const gchar * name;
void (* init) (void);
void (* fini) (void);
- Plugin *priv_assoc;
- InputPlugin **ip_list; /**< List of InputPlugin(s) in this module */
- OutputPlugin **op_list;
- EffectPlugin **ep_list;
- GeneralPlugin **gp_list;
- VisPlugin **vp_list;
- Interface *interface;
-} PluginHeader;
-
-#define PLUGIN_MAGIC 0x8EAC8DE2
-
-#define DECLARE_PLUGIN(name, init, fini, ...) \
- G_BEGIN_DECLS \
- static PluginHeader _pluginInfo = { PLUGIN_MAGIC, __AUDACIOUS_PLUGIN_API__, \
- (gchar *)#name, init, fini, NULL, __VA_ARGS__ }; \
- AudAPITable * _aud_api_table = NULL; \
- G_MODULE_EXPORT PluginHeader * get_plugin_info (AudAPITable * table) { \
- _aud_api_table = table; \
- return &_pluginInfo; \
- } \
- G_END_DECLS
-
-#define SIMPLE_INPUT_PLUGIN(name, ip_list) \
- DECLARE_PLUGIN(name, NULL, NULL, ip_list)
-#define SIMPLE_OUTPUT_PLUGIN(name, op_list) \
- DECLARE_PLUGIN(name, NULL, NULL, NULL, op_list)
+ /* These are arrays of pointers, ending with NULL: */
+ InputPlugin * const * ip_list;
+ OutputPlugin * const * op_list;
+ EffectPlugin * const * ep_list;
+ GeneralPlugin * const * gp_list;
+ VisPlugin * const * vp_list;
+ TransportPlugin * const * tp_list;
+ PlaylistPlugin * const * pp_list;
-#define SIMPLE_EFFECT_PLUGIN(name, ep_list) \
- DECLARE_PLUGIN(name, NULL, NULL, NULL, NULL, ep_list)
-
-#define SIMPLE_GENERAL_PLUGIN(name, gp_list) \
- DECLARE_PLUGIN(name, NULL, NULL, NULL, NULL, NULL, gp_list)
-
-#define SIMPLE_VISUAL_PLUGIN(name, vp_list) \
- DECLARE_PLUGIN(name, NULL, NULL, NULL, NULL, NULL, NULL, vp_list)
-
-#define SIMPLE_INTERFACE_PLUGIN(name, interface) \
- DECLARE_PLUGIN(name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, interface)
+ Iface * iface;
+} PluginHeader;
+#define DECLARE_PLUGIN(name, ...) \
+ AudAPITable * _aud_api_table = NULL; \
+ G_MODULE_EXPORT PluginHeader * get_plugin_info (AudAPITable * table) { \
+ static PluginHeader h = {_AUD_PLUGIN_MAGIC, _AUD_PLUGIN_VERSION, #name, \
+ __VA_ARGS__}; \
+ _aud_api_table = table; \
+ return & h; \
+ }
+
+#define SIMPLE_TRANSPORT_PLUGIN(name, t) DECLARE_PLUGIN(name, .tp_list = t)
+#define SIMPLE_PLAYLIST_PLUGIN(name, p) DECLARE_PLUGIN(name, .pp_list = p)
+#define SIMPLE_INPUT_PLUGIN(name, i) DECLARE_PLUGIN (name, .ip_list = i)
+#define SIMPLE_EFFECT_PLUGIN(name, e) DECLARE_PLUGIN (name, .ep_list = e)
+#define SIMPLE_OUTPUT_PLUGIN(name, o) DECLARE_PLUGIN (name, .op_list = o)
+#define SIMPLE_VIS_PLUGIN(name, v) DECLARE_PLUGIN(name, .vp_list = v)
+#define SIMPLE_GENERAL_PLUGIN(name, g) DECLARE_PLUGIN (name, .gp_list = g)
+#define SIMPLE_IFACE_PLUGIN(name, i) DECLARE_PLUGIN(name, .iface = i)
+
+#define SIMPLE_VISUAL_PLUGIN SIMPLE_VIS_PLUGIN /* deprecated */
#define PLUGIN_COMMON_FIELDS \
- gpointer handle; \
- gchar *filename; \
gchar *description; \
- void (*init) (void); \
+ gboolean (* init) (void); \
void (*cleanup) (void); \
void (*about) (void); \
void (*configure) (void); \
- PluginPreferences *settings; \
- PluginMessageResponse (*sendmsg)(gint msgtype, gpointer msgdata);
+ PluginPreferences *settings;
-/* Sadly, this is the most we can generalize out of the disparate
- plugin structs usable with typecasts - descender */
struct _Plugin {
PLUGIN_COMMON_FIELDS
};
-typedef enum {
- OUTPUT_PLUGIN_INIT_FAIL,
- OUTPUT_PLUGIN_INIT_NO_DEVICES,
- OUTPUT_PLUGIN_INIT_FOUND_DEVICES,
-} OutputPluginInitStatus;
+struct _TransportPlugin {
+ PLUGIN_COMMON_FIELDS
+ const gchar * const * schemes; /* array ending with NULL */
+ const VFSConstructor * vtable;
+};
-struct _OutputPlugin {
- gpointer handle;
- gchar *filename;
- gchar *description;
+struct _PlaylistPlugin {
+ PLUGIN_COMMON_FIELDS
+ const gchar * const * extensions; /* array ending with NULL */
+ gboolean (* load) (const gchar * filename, gint list, gint at);
+ gboolean (* save) (const gchar * filename, gint list);
+};
- OutputPluginInitStatus (*init) (void);
- void (*cleanup) (void);
- void (*about) (void);
- void (*configure) (void);
+struct _OutputPlugin {
+ PLUGIN_COMMON_FIELDS
+ /* During probing, plugins with higher priority (10 to 0) are tried first. */
gint probe_priority;
- void (*get_volume) (gint * l, gint * r);
- void (*set_volume) (gint l, gint r);
+ /* Returns current volume for left and right channels (0 to 100). */
+ void (* get_volume) (gint * l, gint * r);
- gint (*open_audio) (gint fmt, gint rate, gint nch);
- void (*write_audio) (gpointer ptr, gint length);
- void (*close_audio) (void);
+ /* Changes volume for left and right channels (0 to 100). */
+ void (* set_volume) (gint l, gint r);
- void (* set_written_time) (gint time);
- void (*flush) (gint time);
- void (*pause) (gshort paused);
+ /* Begins playback of a PCM stream. <format> is one of the FMT_*
+ * enumeration values defined in libaudcore/audio.h. Returns nonzero on
+ * success. */
+ gboolean (* open_audio) (gint format, gint rate, gint chans);
+
+ /* Ends playback. Any buffered audio data is discarded. */
+ void (* close_audio) (void);
+
+ /* Returns how many bytes of data may be passed to a following write_audio()
+ * call. NULL if the plugin supports only blocking writes (not recommended). */
gint (* buffer_free) (void);
- gint (*buffer_playing) (void); /* obsolete */
- gint (*output_time) (void);
- gint (*written_time) (void);
- void (*tell_audio) (gint * fmt, gint * rate, gint * nch); /* obsolete */
- void (* drain) (void);
+ /* Waits until buffer_free() will return a size greater than zero.
+ * output_time(), pause(), and flush() may be called meanwhile; if flush()
+ * is called, period_wait() should return immediately. NULL if the plugin
+ * supports only blocking writes (not recommended). */
void (* period_wait) (void);
+
+ /* Buffers <size> bytes of data, in the format given to open_audio(). */
+ void (* write_audio) (void * data, gint size);
+
+ /* Waits until all buffered data has been heard by the user. */
+ void (* drain) (void);
+
+ /* Returns time count (in milliseconds) of how much data has been written. */
+ gint (* written_time) (void);
+
+ /* Returns time count (in milliseconds) of how much data has been heard by
+ * the user. */
+ gint (* output_time) (void);
+
+ /* Pauses the stream if <p> is nonzero; otherwise unpauses it.
+ * write_audio() will not be called while the stream is paused. */
+ void (* pause) (gboolean p);
+
+ /* Discards any buffered audio data and sets the time counter (in
+ * milliseconds) of data written. */
+ void (* flush) (gint time);
+
+ /* Sets the time counter (in milliseconds) of data written without
+ * discarding any buffered audio data. If <time> is less than the amount of
+ * buffered data, following calls to output_time() will return negative
+ * values. */
+ void (* set_written_time) (gint time);
};
struct _EffectPlugin {
@@ -279,36 +279,26 @@ struct OutputAPI
void (* abort_write) (void);
};
+typedef const struct _InputPlayback InputPlayback;
+
struct _InputPlayback {
- gchar *filename; /**< Filename URI */
- void *data;
+ /* Pointer to the output API functions. */
+ const struct OutputAPI * output;
- gint playing; /**< 1 = Playing, 0 = Stopped. */
- gboolean error; /**< TRUE if there has been an error. */
- gboolean eof; /**< TRUE if end of file has been reached- */
+ /* Allows the plugin to associate data with a playback instance. */
+ void (* set_data) (InputPlayback * p, void * data);
- InputPlugin *plugin;
- struct OutputAPI * output;
- GThread *thread;
+ /* Returns the pointer passed to set_data. */
+ void * (* get_data) (InputPlayback * p);
- GMutex *pb_ready_mutex;
- GCond *pb_ready_cond;
- gint pb_ready_val;
- gint (*set_pb_ready) (InputPlayback*);
+ /* Signifies that the plugin has started playback is ready to accept mseek,
+ * pause, and stop calls. */
+ void (* set_pb_ready) (InputPlayback * p);
- gint nch; /**< */
- gint rate; /**< */
- gint freq; /**< */
- gint length;
- gchar *title;
-
- /**
- * Set playback parameters. Title should be NULL and length should be 0.
- * @deprecated Use of this function to set title or length is deprecated,
- * please use #set_tuple() for information other than bitrate/samplerate/channels.
- */
- void (*set_params) (InputPlayback * playback, const gchar * title, gint
- length, gint bitrate, gint samplerate, gint channels);
+ /* Updates attributes of the stream. "bitrate" is in bits per second.
+ * "samplerate" is in hertz. */
+ void (* set_params) (InputPlayback * p, gint bitrate, gint samplerate,
+ gint channels);
/**
* Sets / updates playback entry #Tuple.
@@ -322,15 +312,8 @@ struct _InputPlayback {
* those settings. If the settings are changed in a call to set_tuple, this
* function must be called again to apply the updated settings. */
void (* set_gain_from_playlist) (InputPlayback * playback);
-
- /* deprecated */
- void (*pass_audio) (InputPlayback *, gint, gint, gint, gpointer, gint *);
- void (*set_replaygain_info) (InputPlayback *, ReplayGainInfo *);
};
-/**
- * Input plugin structure.
- */
struct _InputPlugin {
PLUGIN_COMMON_FIELDS
@@ -365,11 +348,7 @@ struct _InputPlugin {
/* Must return nonzero if the plugin can handle this file. If the file
* could not be opened, "file" will be NULL. (This is normal in the case of
* special URI schemes like cdda:// that do not represent actual files.) */
- /* Bug: The return value should be a gboolean, not a gint. */
- gint (* is_our_file_from_vfs) (const gchar * filename, VFSFile * file);
-
- /* Deprecated. */
- Tuple * (* get_song_tuple) (const gchar * filename); /* Use probe_for_tuple. */
+ gboolean (* is_our_file_from_vfs) (const gchar * filename, VFSFile * file);
/* Must return a tuple containing metadata for this file, or NULL if no
* metadata could be read. If the file could not be opened, "file" will be
@@ -414,17 +393,13 @@ struct _InputPlugin {
/* Must pause or unpause a file currently being played. This function will
* be called from a different thread than play, but it will not be called
* before the plugin calls set_pb_ready or after stop is called. */
- /* Bug: paused should be a gboolean, not a gshort. */
- /* Bug: There is no way to indicate success or failure. */
- void (* pause) (InputPlayback * playback, gshort paused);
+ void (* pause) (InputPlayback * playback, gboolean paused);
/* Optional. Must seek to the given position in milliseconds within a file
* currently being played. This function will be called from a different
* thread than play, but it will not be called before the plugin calls
* set_pb_ready or after stop is called. */
- /* Bug: time should be a gint, not a gulong. */
- /* Bug: There is no way to indicate success or failure. */
- void (* mseek) (InputPlayback * playback, gulong time);
+ void (* mseek) (InputPlayback * playback, gint time);
/* Must signal a currently playing song to stop and cause play to return.
* This function will be called from a different thread than play. It will
@@ -437,15 +412,13 @@ struct _InputPlugin {
gint (* get_time) (InputPlayback * playback);
gint (* get_volume) (gint * l, gint * r);
gint (* set_volume) (gint l, gint r);
-
- /* Deprecated. */
- gint (* is_our_file) (const gchar * filename); /* Use is_our_file_from_vfs. */
- void (* play_file) (InputPlayback * playback); /* Use play. */
- void (* seek) (InputPlayback * playback, gint time); /* Use mseek. */
};
struct _GeneralPlugin {
PLUGIN_COMMON_FIELDS
+
+ /* GtkWidget * (* get_widget) (void); */
+ void * (* get_widget) (void);
};
struct _VisPlugin {
@@ -454,7 +427,6 @@ struct _VisPlugin {
gint num_pcm_chs_wanted;
gint num_freq_chs_wanted;
- void (*disable_plugin) (struct _VisPlugin *);
void (*playback_start) (void);
void (*playback_stop) (void);
void (*render_pcm) (gint16 pcm_data[2][512]);
@@ -471,7 +443,6 @@ struct _VisPlugin {
void * (* get_widget) (void);
};
-/* undefine the macro -- struct Plugin should be used instead. */
#undef PLUGIN_COMMON_FIELDS
#endif /* AUDACIOUS_PLUGIN_H */
diff --git a/src/audacious/pluginenum.c b/src/audacious/pluginenum.c
index efec570..e4b8641 100644
--- a/src/audacious/pluginenum.c
+++ b/src/audacious/pluginenum.c
@@ -23,36 +23,25 @@
* Audacious or using our public API to be a derived work.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#ifndef SHARED_SUFFIX
-# define SHARED_SUFFIX G_MODULE_SUFFIX
-#endif
+#include <assert.h>
#include <glib.h>
#include <gmodule.h>
-#include <gtk/gtk.h>
-#include <string.h>
#include <libaudcore/audstrings.h>
#include <libaudgui/init.h>
-#include "pluginenum.h"
-#include "plugins.h"
+#include "config.h"
+
+#ifndef SHARED_SUFFIX
+# define SHARED_SUFFIX G_MODULE_SUFFIX
+#endif
#include "audconfig.h"
#include "debug.h"
-#include "effect.h"
-#include "general.h"
-#include "i18n.h"
-#include "interface.h"
-#include "main.h"
-#include "output.h"
-#include "playback.h"
+#include "plugin.h"
+#include "ui_preferences.h"
#include "util.h"
-#include "visualization.h"
#define AUD_API_DECLARE
#include "configdb.h"
@@ -62,10 +51,7 @@
#include "plugins.h"
#undef AUD_API_DECLARE
-const gchar *plugin_dir_list[] = {
- PLUGINSUBS,
- NULL
-};
+static const gchar * plugin_dir_list[] = {PLUGINSUBS, NULL};
static AudAPITable api_table = {
.configdb_api = & configdb_api,
@@ -75,200 +61,166 @@ static AudAPITable api_table = {
.plugins_api = & plugins_api,
.cfg = & cfg};
-extern GList *vfs_transports;
-static mowgli_list_t *headers_list = NULL;
-
-static void input_plugin_init(Plugin * plugin)
-{
- InputPlugin *p = INPUT_PLUGIN(plugin);
-
- if (p->init != NULL)
- p->init ();
-}
-
-static void effect_plugin_init(Plugin * plugin)
-{
- EffectPlugin *p = EFFECT_PLUGIN(plugin);
-
- if (p->init != NULL)
- p->init ();
-}
-
-static void vis_plugin_disable_by_header (VisPlugin * header)
-{
- vis_plugin_enable (plugin_by_header (header), FALSE);
-}
-
-static void vis_plugin_init(Plugin * plugin)
-{
- ((VisPlugin *) plugin)->disable_plugin = vis_plugin_disable_by_header;
-}
-
-/*******************************************************************/
-
-static void plugin2_dispose(GModule * module, const gchar * str, ...)
-{
- gchar *buf;
- va_list va;
-
- va_start(va, str);
- buf = g_strdup_vprintf(str, va);
- va_end(va);
+typedef struct {
+ PluginHeader * header;
+ GModule * module;
+} LoadedModule;
- AUDDBG ("*** %s\n", buf);
- g_free(buf);
+static GList * loaded_modules = NULL;
- g_module_close(module);
-}
-
-void plugin2_process(PluginHeader * header, GModule * module, const gchar * filename)
+static void plugin2_process (PluginHeader * header, GModule * module, const gchar * filename)
{
- gint i, n;
- mowgli_node_t *hlist_node;
-
- if (header->magic != PLUGIN_MAGIC)
+ if (header->magic != _AUD_PLUGIN_MAGIC)
{
- plugin2_dispose (module, "plugin <%s> discarded, invalid module magic",
- filename);
+ fprintf (stderr, " *** ERROR: %s is not a valid Audacious plugin.\n", filename);
+ g_module_close (module);
return;
}
- if (header->api_version != __AUDACIOUS_PLUGIN_API__)
+ if (header->version < _AUD_PLUGIN_VERSION_MIN || header->version > _AUD_PLUGIN_VERSION)
{
- plugin2_dispose (module, "plugin <%s> discarded, wanting API version "
- "%d, we implement API version %d", filename, header->api_version,
- __AUDACIOUS_PLUGIN_API__);
+ fprintf (stderr, " *** ERROR: %s is not compatible with this version of Audacious.\n", filename);
+ g_module_close (module);
return;
}
- hlist_node = mowgli_node_create();
- mowgli_node_add(header, hlist_node, headers_list);
+ LoadedModule * loaded = g_slice_new (LoadedModule);
+ loaded->header = header;
+ loaded->module = module;
+ loaded_modules = g_list_prepend (loaded_modules, loaded);
- if (header->init)
+ if (header->init != NULL)
{
- plugin_register (filename, PLUGIN_TYPE_BASIC, 0, NULL);
- header->init();
+ plugin_register (PLUGIN_TYPE_LOWLEVEL, filename, 0, NULL);
+ header->init ();
}
- header->priv_assoc = g_new0(Plugin, 1);
- header->priv_assoc->handle = module;
- header->priv_assoc->filename = g_strdup(filename);
-
- n = 0;
-
- if (header->ip_list)
+ if (header->tp_list)
{
- for (i = 0; (header->ip_list)[i] != NULL; i++, n++)
+ TransportPlugin * tp;
+ for (gint i = 0; (tp = header->tp_list[i]); i ++)
{
- plugin_register (filename, PLUGIN_TYPE_INPUT, i, header->ip_list[i]);
- PLUGIN((header->ip_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
- input_plugin_init(PLUGIN((header->ip_list)[i]));
+ plugin_register (PLUGIN_TYPE_TRANSPORT, filename, i, tp);
+ if (tp->init != NULL)
+ tp->init (); /* FIXME: Pay attention to the return value. */
}
}
- if (header->op_list)
+ if (header->pp_list)
{
- for (i = 0; (header->op_list)[i] != NULL; i++, n++)
+ PlaylistPlugin * pp;
+ for (gint i = 0; (pp = header->pp_list[i]); i ++)
{
- OutputPlugin * plugin = header->op_list[i];
-
- plugin->filename = g_strdup_printf ("%s (#%d)", filename, n);
- plugin_register (filename, PLUGIN_TYPE_OUTPUT, i, plugin);
+ plugin_register (PLUGIN_TYPE_PLAYLIST, filename, i, pp);
+ if (pp->init != NULL)
+ pp->init (); /* FIXME: Pay attention to the return value. */
}
}
- if (header->ep_list)
+ if (header->ip_list != NULL)
{
- for (i = 0; (header->ep_list)[i] != NULL; i++, n++)
+ InputPlugin * ip;
+ for (gint i = 0; (ip = header->ip_list[i]) != NULL; i ++)
{
- plugin_register (filename, PLUGIN_TYPE_EFFECT, i, header->ep_list[i]);
- PLUGIN((header->ep_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
- effect_plugin_init(PLUGIN((header->ep_list)[i]));
+ plugin_register (PLUGIN_TYPE_INPUT, filename, i, ip);
+ if (ip->init != NULL)
+ ip->init (); /* FIXME: Pay attention to the return value. */
}
}
-
- if (header->gp_list)
+ if (header->ep_list != NULL)
{
- for (i = 0; (header->gp_list)[i] != NULL; i++, n++)
+ EffectPlugin * ep;
+ for (gint i = 0; (ep = header->ep_list[i]) != NULL; i ++)
{
- plugin_register (filename, PLUGIN_TYPE_GENERAL, i, header->gp_list[i]);
- PLUGIN((header->gp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
+ plugin_register (PLUGIN_TYPE_EFFECT, filename, i, ep);
+ if (ep->init != NULL)
+ ep->init (); /* FIXME: Pay attention to the return value. */
}
}
- if (header->vp_list)
+ if (header->op_list != NULL)
+ {
+ OutputPlugin * op;
+ for (gint i = 0; (op = header->op_list[i]) != NULL; i ++)
+ plugin_register (PLUGIN_TYPE_OUTPUT, filename, i, op);
+ }
+
+ if (header->vp_list != NULL)
{
- for (i = 0; (header->vp_list)[i] != NULL; i++, n++)
- {
- plugin_register (filename, PLUGIN_TYPE_VIS, i, header->vp_list[i]);
- PLUGIN((header->vp_list)[i])->filename = g_strdup_printf("%s (#%d)", filename, n);
- vis_plugin_init(PLUGIN((header->vp_list)[i]));
- }
+ VisPlugin * vp;
+ for (gint i = 0; (vp = header->vp_list[i]) != NULL; i ++)
+ plugin_register (PLUGIN_TYPE_VIS, filename, i, vp);
}
- if (header->interface)
- plugin_register (filename, PLUGIN_TYPE_IFACE, 0, header->interface);
+ if (header->gp_list != NULL)
+ {
+ GeneralPlugin * gp;
+ for (gint i = 0; (gp = header->gp_list[i]) != NULL; i ++)
+ plugin_register (PLUGIN_TYPE_GENERAL, filename, i, gp);
+ }
+
+ if (header->iface != NULL)
+ plugin_register (PLUGIN_TYPE_IFACE, filename, 0, header->iface);
}
-void plugin2_unload(PluginHeader * header, mowgli_node_t * hlist_node)
+static void plugin2_unload (LoadedModule * loaded)
{
- GModule *module;
-
- g_return_if_fail(header->priv_assoc != NULL);
+ PluginHeader * header = loaded->header;
if (header->ip_list != NULL)
{
- for (gint i = 0; header->ip_list[i] != NULL; i ++)
+ InputPlugin * ip;
+ for (gint i = 0; (ip = header->ip_list[i]) != NULL; i ++)
{
- if (header->ip_list[i]->cleanup != NULL)
- header->ip_list[i]->cleanup ();
-
- g_free (header->ip_list[i]->filename);
+ if (ip->settings != NULL)
+ plugin_preferences_cleanup (ip->settings);
+ if (ip->cleanup != NULL)
+ ip->cleanup ();
}
}
- if (header->op_list != NULL)
- {
- for (gint i = 0; header->op_list[i] != NULL; i ++)
- g_free (header->op_list[i]->filename);
- }
-
if (header->ep_list != NULL)
{
- for (gint i = 0; header->ep_list[i] != NULL; i ++)
+ EffectPlugin * ep;
+ for (gint i = 0; (ep = header->ep_list[i]) != NULL; i ++)
{
- if (header->ep_list[i]->cleanup != NULL)
- header->ep_list[i]->cleanup ();
-
- g_free (header->ep_list[i]->filename);
+ if (ep->settings != NULL)
+ plugin_preferences_cleanup (ep->settings);
+ if (ep->cleanup != NULL)
+ ep->cleanup ();
}
}
- if (header->vp_list != NULL)
+ if (header->pp_list != NULL)
{
- for (gint i = 0; header->vp_list[i] != NULL; i ++)
- g_free (header->vp_list[i]->filename);
+ PlaylistPlugin * pp;
+ for (gint i = 0; (pp = header->pp_list[i]) != NULL; i ++)
+ {
+ if (pp->settings != NULL)
+ plugin_preferences_cleanup (pp->settings);
+ if (pp->cleanup != NULL)
+ pp->cleanup ();
+ }
}
- if (header->gp_list != NULL)
+ if (header->tp_list != NULL)
{
- for (gint i = 0; header->gp_list[i] != NULL; i ++)
- g_free (header->gp_list[i]->filename);
+ TransportPlugin * tp;
+ for (gint i = 0; (tp = header->tp_list[i]) != NULL; i ++)
+ {
+ if (tp->settings != NULL)
+ plugin_preferences_cleanup (tp->settings);
+ if (tp->cleanup != NULL)
+ tp->cleanup ();
+ }
}
- module = header->priv_assoc->handle;
-
- g_free(header->priv_assoc->filename);
- g_free(header->priv_assoc);
-
- if (header->fini)
- header->fini();
+ if (header->fini != NULL)
+ header->fini ();
- mowgli_node_delete(hlist_node, headers_list);
- mowgli_node_free(hlist_node);
-
- g_module_close(module);
+ g_module_close (loaded->module);
+ g_slice_free (LoadedModule, loaded);
}
/******************************************************************/
@@ -317,70 +269,19 @@ static void scan_plugins(const gchar * path)
dir_foreach(path, scan_plugin_func, NULL, NULL);
}
-static OutputPlugin * output_load_selected (void)
-{
- if (cfg.output_path == NULL)
- return NULL;
-
- PluginHandle * handle = plugin_by_path (cfg.output_path, PLUGIN_TYPE_OUTPUT,
- cfg.output_number);
- if (handle == NULL)
- return NULL;
-
- OutputPlugin * plugin = plugin_get_header (handle);
- if (plugin == NULL || plugin->init () != OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
- return NULL;
-
- return plugin;
-}
-
-static gboolean output_probe_func (PluginHandle * handle, OutputPlugin * * result)
-{
- AUDDBG ("Probing output plugin %s.\n", plugin_get_name (handle));
- OutputPlugin * plugin = plugin_get_header (handle);
-
- if (plugin == NULL || plugin->init == NULL || plugin->init () !=
- OUTPUT_PLUGIN_INIT_FOUND_DEVICES)
- return TRUE;
-
- * result = plugin;
- return FALSE;
-}
-
-static OutputPlugin * output_probe (void)
-{
- OutputPlugin * plugin = NULL;
- plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_probe_func,
- & plugin);
-
- if (plugin == NULL)
- fprintf (stderr, "ALL OUTPUT PLUGINS FAILED TO INITIALIZE.\n");
-
- return plugin;
-}
-
void plugin_system_init(void)
{
+ assert (g_module_supported ());
+
gchar *dir;
- GtkWidget *dialog;
gint dirsel = 0;
audgui_init (& api_table);
- if (!g_module_supported())
- {
- dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Module loading not supported! Plugins will not be loaded.\n"));
- gtk_dialog_run(GTK_DIALOG(dialog));
- gtk_widget_destroy(dialog);
- return;
- }
-
plugin_registry_load ();
- headers_list = mowgli_list_create();
-
#ifndef DISABLE_USER_PLUGIN_DIR
- scan_plugins(aud_paths[BMP_PATH_USER_PLUGIN_DIR]);
+ scan_plugins (get_path (AUD_PATH_USER_PLUGIN_DIR));
/*
* This is in a separate loop so if the user puts them in the
* wrong dir we'll still get them in the right order (home dir
@@ -388,7 +289,8 @@ void plugin_system_init(void)
*/
while (plugin_dir_list[dirsel])
{
- dir = g_build_filename(aud_paths[BMP_PATH_USER_PLUGIN_DIR], plugin_dir_list[dirsel++], NULL);
+ dir = g_build_filename (get_path (AUD_PATH_USER_PLUGIN_DIR),
+ plugin_dir_list[dirsel ++], NULL);
scan_plugins(dir);
g_free(dir);
}
@@ -397,47 +299,22 @@ void plugin_system_init(void)
while (plugin_dir_list[dirsel])
{
- dir = g_build_filename(PLUGIN_DIR, plugin_dir_list[dirsel++], NULL);
+ dir = g_build_filename (get_path (AUD_PATH_PLUGIN_DIR),
+ plugin_dir_list[dirsel ++], NULL);
scan_plugins(dir);
g_free(dir);
}
plugin_registry_prune ();
-
- current_output_plugin = output_load_selected ();
-
- if (current_output_plugin == NULL)
- current_output_plugin = output_probe ();
-
- general_init ();
}
void plugin_system_cleanup(void)
{
- mowgli_node_t *hlist_node;
-
- AUDDBG ("Shutting down plugin system.\n");
-
- if (current_output_plugin != NULL)
- {
- if (current_output_plugin->cleanup != NULL)
- current_output_plugin->cleanup ();
-
- current_output_plugin = NULL;
- }
-
- general_cleanup ();
-
plugin_registry_save ();
- /* XXX: vfs will crash otherwise. -nenolod */
- if (vfs_transports != NULL)
- {
- g_list_free(vfs_transports);
- vfs_transports = NULL;
- }
-
- MOWGLI_LIST_FOREACH(hlist_node, headers_list->head) plugin2_unload(hlist_node->data, hlist_node);
+ for (GList * node = loaded_modules; node != NULL; node = node->next)
+ plugin2_unload (node->data);
- mowgli_list_free(headers_list);
+ g_list_free (loaded_modules);
+ loaded_modules = NULL;
}
diff --git a/src/audacious/pluginenum.h b/src/audacious/pluginenum.h
deleted file mode 100644
index 3883ca0..0000000
--- a/src/audacious/pluginenum.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2007 Audacious development team
- *
- * Based on BMP:
- * Copyright (C) 2003-2004 BMP development team
- *
- * Based on XMMS:
- * Copyright (C) 1998-2003 XMMS development team
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-#ifndef AUDACIOUS_PLUGINENUM_H
-#define AUDACIOUS_PLUGINENUM_H
-
-#include "config.h"
-
-#include <glib.h>
-
-#define PLUGIN_FILENAME(name) (name SHARED_SUFFIX)
-
-void plugin_system_init(void);
-void plugin_system_cleanup(void);
-
-void module_load (const gchar * path);
-
-extern const gchar *plugin_dir_list[];
-extern GHashTable *plugin_matrix;
-
-#endif /* AUDACIOUS_PLUGINENUM_H */
diff --git a/src/audacious/plugins-api.h b/src/audacious/plugins-api.h
index 79bb5a8..6d0d875 100644
--- a/src/audacious/plugins-api.h
+++ b/src/audacious/plugins-api.h
@@ -23,33 +23,36 @@
/* CAUTION: These functions are not thread safe. */
-/* effect.c */
-AUD_FUNC2 (void, effect_plugin_enable, PluginHandle *, plugin, gboolean, enable)
-
-/* general.c */
-AUD_FUNC2 (void, general_plugin_enable, PluginHandle *, plugin, gboolean, enable)
-
-/* main.c */
-AUD_FUNC0 (PluginHandle *, iface_plugin_get_active)
-AUD_FUNC1 (void, iface_plugin_set_active, PluginHandle *, plugin)
+/* plugin-init.c */
+AUD_FUNC1 (PluginHandle *, plugin_get_current, gint, type)
+AUD_FUNC2 (gboolean, plugin_enable, PluginHandle *, plugin, gboolean, enable)
/* plugin-registry.c */
-AUD_FUNC4 (void, plugin_get_path, PluginHandle *, plugin, const gchar * *, path,
- gint *, type, gint *, number)
-AUD_FUNC3 (PluginHandle *, plugin_by_path, const gchar *, path, gint, type,
+AUD_FUNC1 (gint, plugin_get_type, PluginHandle *, plugin)
+AUD_FUNC1 (const gchar *, plugin_get_filename, PluginHandle *, plugin)
+AUD_FUNC1 (gint, plugin_get_number, PluginHandle *, plugin)
+AUD_FUNC3 (PluginHandle *, plugin_lookup, gint, type, const gchar *, filename,
gint, number)
-AUD_FUNC1 (void *, plugin_get_header, PluginHandle *, plugin)
-AUD_FUNC1 (PluginHandle *, plugin_by_header, void *, header)
+
+AUD_FUNC1 (const void *, plugin_get_header, PluginHandle *, plugin)
+AUD_FUNC1 (PluginHandle *, plugin_by_header, const void *, header)
+
AUD_FUNC2 (gint, plugin_compare, PluginHandle *, a, PluginHandle *, b)
AUD_FUNC3 (void, plugin_for_each, gint, type, PluginForEachFunc, func, void *,
data)
-AUD_FUNC1 (const gchar *, plugin_get_name, PluginHandle *, plugin)
-AUD_FUNC1 (gboolean, plugin_has_about, PluginHandle *, plugin)
-AUD_FUNC1 (gboolean, plugin_has_configure, PluginHandle *, plugin)
+
AUD_FUNC1 (gboolean, plugin_get_enabled, PluginHandle *, plugin)
-AUD_FUNC2 (void, plugin_set_enabled, PluginHandle *, plugin, gboolean, enabled)
AUD_FUNC3 (void, plugin_for_enabled, gint, type, PluginForEachFunc, func,
void *, data)
-/* visualization.c */
-AUD_FUNC2 (void, vis_plugin_enable, PluginHandle *, plugin, gboolean, enable)
+AUD_FUNC1 (const gchar *, plugin_get_name, PluginHandle *, plugin)
+AUD_FUNC1 (gboolean, plugin_has_about, PluginHandle *, plugin)
+AUD_FUNC1 (gboolean, plugin_has_configure, PluginHandle *, plugin)
+
+AUD_FUNC3 (void, plugin_add_watch, PluginHandle *, plugin, PluginForEachFunc,
+ func, void *, data)
+AUD_FUNC3 (void, plugin_remove_watch, PluginHandle *, plugin, PluginForEachFunc,
+ func, void *, data)
+
+/* New in 2.5-alpha2 */
+AUD_FUNC1 (PluginHandle *, plugin_by_widget, /* GtkWidget * */ void *, widget)
diff --git a/src/audacious/plugins.h b/src/audacious/plugins.h
index 6612d11..01dc6b5 100644
--- a/src/audacious/plugins.h
+++ b/src/audacious/plugins.h
@@ -23,19 +23,22 @@
#define AUDACIOUS_PLUGINS_H
#include <glib.h>
+
#include <audacious/api.h>
+#include <audacious/types.h>
enum {
- PLUGIN_TYPE_BASIC,
+ PLUGIN_TYPE_LOWLEVEL,
+ PLUGIN_TYPE_TRANSPORT,
+ PLUGIN_TYPE_PLAYLIST,
PLUGIN_TYPE_INPUT,
- PLUGIN_TYPE_OUTPUT,
PLUGIN_TYPE_EFFECT,
+ PLUGIN_TYPE_OUTPUT,
PLUGIN_TYPE_VIS,
- PLUGIN_TYPE_IFACE,
PLUGIN_TYPE_GENERAL,
+ PLUGIN_TYPE_IFACE,
PLUGIN_TYPES};
-typedef struct PluginHandle PluginHandle;
typedef gboolean (* PluginForEachFunc) (PluginHandle * plugin, void * data);
#define AUD_API_NAME PluginsAPI
@@ -53,15 +56,36 @@ enum {
INPUT_KEY_MIME,
INPUT_KEYS};
+/* plugin-init.c */
+void start_plugins_one (void);
+void start_plugins_two (void);
+void stop_plugins_two (void);
+void stop_plugins_one (void);
+
+/* plugin-registry.c */
void plugin_registry_load (void);
void plugin_registry_prune (void);
void plugin_registry_save (void);
void module_register (const gchar * path);
-void plugin_register (const gchar * path, gint type, gint number, void * header);
+void plugin_register (gint type, const gchar * path, gint number, const void *
+ header);
+
+void plugin_set_enabled (PluginHandle * plugin, gboolean enabled);
+PluginHandle * transport_plugin_for_scheme (const gchar * scheme);
+PluginHandle * playlist_plugin_for_extension (const gchar * extension);
void input_plugin_for_key (gint key, const gchar * value, PluginForEachFunc
func, void * data);
+gboolean input_plugin_has_images (PluginHandle * plugin);
+gboolean input_plugin_has_subtunes (PluginHandle * plugin);
+gboolean input_plugin_can_write_tuple (PluginHandle * plugin);
+gboolean input_plugin_has_infowin (PluginHandle * plugin);
+
+/* pluginenum.c */
+void plugin_system_init (void);
+void plugin_system_cleanup (void);
+void module_load (const gchar * path);
#else
diff --git a/src/audacious/preferences.h b/src/audacious/preferences.h
index 0df7b0a..f82bbf0 100644
--- a/src/audacious/preferences.h
+++ b/src/audacious/preferences.h
@@ -125,7 +125,6 @@ typedef struct _NotebookTab {
typedef enum {
PREFERENCES_WINDOW, /* displayed in seperate window */
- PREFERENCES_PAGE, /* added as new page in main preferences window */
} PreferencesType;
struct _PluginPreferences {
diff --git a/src/audacious/probe-buffer.c b/src/audacious/probe-buffer.c
index ee70daf..e9621e1 100644
--- a/src/audacious/probe-buffer.c
+++ b/src/audacious/probe-buffer.c
@@ -59,7 +59,8 @@ static void increase_buffer (ProbeBuffer * p, gint64 size)
}
if (p->filled < size)
- p->filled += vfs_fread (p->buffer + p->at, 1, size - p->filled, p->file);
+ p->filled += vfs_fread (p->buffer + p->filled, 1, size - p->filled,
+ p->file);
}
static gint64 probe_buffer_fread (void * buffer, gint64 size, gint64 count,
@@ -156,7 +157,6 @@ static gchar * probe_buffer_get_metadata (VFSFile * file, const gchar * field)
static VFSConstructor probe_buffer_table =
{
- .uri_id = NULL,
.vfs_fopen_impl = NULL,
.vfs_fclose_impl = probe_buffer_fclose,
.vfs_fread_impl = probe_buffer_fread,
@@ -193,6 +193,7 @@ VFSFile * probe_buffer_new (const gchar * filename)
file2->handle = p;
file2->uri = g_strdup (filename);
file2->ref = 1;
+ file2->sig = VFS_SIG;
return file2;
}
diff --git a/src/audacious/probe.c b/src/audacious/probe.c
index 703a10c..9c15789 100644
--- a/src/audacious/probe.c
+++ b/src/audacious/probe.c
@@ -82,14 +82,6 @@ static gboolean probe_func (PluginHandle * plugin, ProbeState * state)
if (vfs_fseek (state->handle, 0, SEEK_SET) < 0)
return FALSE;
}
- else if (decoder->is_our_file != NULL)
- {
- if (decoder->is_our_file (state->filename))
- {
- state->plugin = plugin;
- return FALSE;
- }
- }
return TRUE;
}
@@ -176,10 +168,10 @@ static void probe_by_mime (ProbeState * state)
static void probe_by_content (ProbeState * state)
{
AUDDBG ("Probing by content.\n");
- plugin_for_each (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state);
+ plugin_for_enabled (PLUGIN_TYPE_INPUT, (PluginForEachFunc) probe_func, state);
}
-InputPlugin * file_find_decoder (const gchar * filename, gboolean fast)
+PluginHandle * file_find_decoder (const gchar * filename, gboolean fast)
{
ProbeState state;
@@ -211,69 +203,72 @@ DONE:
if (state.handle != NULL)
vfs_fclose (state.handle);
- return (state.plugin != NULL) ? plugin_get_header (state.plugin) : NULL;
+ return state.plugin;
}
-Tuple * file_read_tuple (const gchar * filename, InputPlugin * decoder)
+Tuple * file_read_tuple (const gchar * filename, PluginHandle * decoder)
{
- if (decoder->get_song_tuple != NULL)
- return decoder->get_song_tuple (filename);
+ InputPlugin * ip = plugin_get_header (decoder);
+ g_return_val_if_fail (ip, NULL);
+ g_return_val_if_fail (ip->probe_for_tuple, NULL);
- if (decoder->probe_for_tuple != NULL)
- {
- VFSFile * handle = vfs_fopen (filename, "r");
- Tuple * tuple;
+ gchar * real = filename_split_subtune (filename, NULL);
+ VFSFile * handle = vfs_fopen (real, "r");
+ g_free (real);
- if (handle == NULL)
- return NULL;
+ Tuple * tuple = ip->probe_for_tuple (filename, handle);
- tuple = decoder->probe_for_tuple (filename, handle);
+ if (handle)
vfs_fclose (handle);
- return tuple;
- }
- return NULL;
+ return tuple;
}
-gboolean file_read_image (const gchar * filename, InputPlugin * decoder,
+gboolean file_read_image (const gchar * filename, PluginHandle * decoder,
void * * data, gint * size)
{
- VFSFile * handle;
- gboolean success;
-
- if (decoder->get_song_image == NULL)
+ if (! input_plugin_has_images (decoder))
return FALSE;
- handle = vfs_fopen (filename, "r");
- success = decoder->get_song_image (filename, handle, data, size);
+ InputPlugin * ip = plugin_get_header (decoder);
+ g_return_val_if_fail (ip, FALSE);
+ g_return_val_if_fail (ip->get_song_image, FALSE);
+
+ gchar * real = filename_split_subtune (filename, NULL);
+ VFSFile * handle = vfs_fopen (real, "r");
+ g_free (real);
+
+ gboolean success = ip->get_song_image (filename, handle, data, size);
- if (handle != NULL)
+ if (handle)
vfs_fclose (handle);
return success;
}
-gboolean file_can_write_tuple (const gchar * filename, InputPlugin * decoder)
+gboolean file_can_write_tuple (const gchar * filename, PluginHandle * decoder)
{
- return (decoder->update_song_tuple != NULL);
+ return input_plugin_can_write_tuple (decoder);
}
-gboolean file_write_tuple (const gchar * filename, InputPlugin * decoder,
+gboolean file_write_tuple (const gchar * filename, PluginHandle * decoder,
const Tuple * tuple)
{
- VFSFile * handle;
- gboolean success;
+ InputPlugin * ip = plugin_get_header (decoder);
+ g_return_val_if_fail (ip, FALSE);
+ g_return_val_if_fail (ip->update_song_tuple, FALSE);
- if (decoder->update_song_tuple == NULL)
- return FALSE;
+ gchar * real = filename_split_subtune (filename, NULL);
+ VFSFile * handle = vfs_fopen (real, "r+");
+ g_free (real);
- handle = vfs_fopen (filename, "r+");
-
- if (handle == NULL)
+ if (! handle)
return FALSE;
- success = decoder->update_song_tuple (tuple, handle);
- vfs_fclose (handle);
+ gboolean success = ip->update_song_tuple (tuple, handle);
+
+ if (handle)
+ vfs_fclose (handle);
if (success)
playlist_rescan_file (filename);
@@ -281,11 +276,15 @@ gboolean file_write_tuple (const gchar * filename, InputPlugin * decoder,
return success;
}
-gboolean custom_infowin (const gchar * filename, InputPlugin * decoder)
+gboolean custom_infowin (const gchar * filename, PluginHandle * decoder)
{
- if (decoder->file_info_box == NULL)
+ if (! input_plugin_has_infowin (decoder))
return FALSE;
- decoder->file_info_box (filename);
+ InputPlugin * ip = plugin_get_header (decoder);
+ g_return_val_if_fail (ip, FALSE);
+ g_return_val_if_fail (ip->file_info_box, FALSE);
+
+ ip->file_info_box (filename);
return TRUE;
}
diff --git a/src/audacious/signals.c b/src/audacious/signals.c
index 6b8a30d..99fbbc5 100644
--- a/src/audacious/signals.c
+++ b/src/audacious/signals.c
@@ -1,100 +1,48 @@
/*
- * Audacious
- * Copyright (c) 2005-2007 Yoshiki Yazawa
- * Copyright 2009 John Lindgren (POSIX threaded signal handling)
+ * signals.c
+ * Copyright 2009 John Lindgren
*
- * 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; under version 3 of the License.
+ * This file is part of Audacious.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Audacious 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, version 2 or version 3 of the License.
*
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
*/
#include <signal.h>
-
#include <glib.h>
-#include <gtk/gtk.h>
-
#include <libaudcore/eventqueue.h>
-#include "audconfig.h"
#include "config.h"
-#include "main.h"
-#include "signals.h"
-
-#ifdef USE_EGGSM
-#include "eggsmclient.h"
-#endif
+#ifdef HAVE_SIGWAIT
static sigset_t signal_set;
-#ifdef USE_EGGSM
-static void
-signal_session_quit_cb(EggSMClient *client, gpointer user_data)
-{
- const gchar * argv[2];
-
- g_print("Session quit requested. Saving state and shutting down.\n");
-
- argv[0] = "audacious";
- argv[1] = g_strdup_printf ("--display=%s", gdk_display_get_name (gdk_display_get_default()));
- egg_sm_client_set_restart_command (client, 2, argv);
-
- aud_quit();
-}
-
-static void
-signal_session_save_cb(EggSMClient *client, GKeyFile *state_file, gpointer user_data)
-{
- const gchar * argv[2];
-
- g_print("Session save requested. Saving state.\n");
-
- argv[0] = "audacious";
- argv[1] = g_strdup_printf ("--display=%s", gdk_display_get_name (gdk_display_get_default()));
- egg_sm_client_set_restart_command (client, 2, argv);
-
- aud_config_save();
-}
-#endif
-
static void * signal_thread (void * data)
{
gint signal;
while (! sigwait (& signal_set, & signal))
- event_queue ("quit", 0);
+ event_queue ("quit", NULL);
return NULL;
}
+#endif
/* Must be called before any threads are created. */
-void signal_handlers_init (void)
+void signals_init (void)
{
-#ifdef USE_EGGSM
- EggSMClient *client;
-
- client = egg_sm_client_get ();
- if (client != NULL)
- {
- egg_sm_client_set_mode (EGG_SM_CLIENT_MODE_NORMAL);
- g_signal_connect (client, "quit",
- G_CALLBACK (signal_session_quit_cb), NULL);
- g_signal_connect (client, "save-state",
- G_CALLBACK (signal_session_save_cb), NULL);
-
- }
-#endif
-
+#ifdef HAVE_SIGWAIT
sigemptyset (& signal_set);
sigaddset (& signal_set, SIGHUP);
sigaddset (& signal_set, SIGINT);
@@ -103,4 +51,5 @@ void signal_handlers_init (void)
sigprocmask (SIG_BLOCK, & signal_set, NULL);
g_thread_create (signal_thread, NULL, FALSE, NULL);
+#endif
}
diff --git a/src/audacious/signals.h b/src/audacious/signals.h
deleted file mode 100644
index c9fcbe6..0000000
--- a/src/audacious/signals.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Audacious
- * Copyright (c) 2005-2007 Audacious development team
- *
- * BMP - Cross-platform multimedia player
- * Copyright (C) 2003-2005 BMP development team.
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_SIGNALS_H
-#define AUDACIOUS_SIGNALS_H
-
-void signal_handlers_init(void);
-
-#endif /* AUDACIOUS_SIGNALS_H */
diff --git a/src/audacious/smclient.c b/src/audacious/smclient.c
new file mode 100644
index 0000000..bb5e2ff
--- /dev/null
+++ b/src/audacious/smclient.c
@@ -0,0 +1,75 @@
+/*
+ * Audacious
+ * Copyright (c) 2005-2007 Yoshiki Yazawa
+ *
+ * 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; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#include <gdk/gdk.h>
+#include <libaudcore/hook.h>
+
+#include "audconfig.h"
+#include "config.h"
+
+#ifdef USE_EGGSM
+
+#include "eggsmclient.h"
+
+static void
+signal_session_quit_cb(EggSMClient *client, gpointer user_data)
+{
+ const gchar * argv[2];
+
+ g_print("Session quit requested. Saving state and shutting down.\n");
+
+ argv[0] = "audacious";
+ argv[1] = g_strdup_printf ("--display=%s", gdk_display_get_name (gdk_display_get_default()));
+ egg_sm_client_set_restart_command (client, 2, argv);
+
+ hook_call ("quit", NULL);
+}
+
+static void
+signal_session_save_cb(EggSMClient *client, GKeyFile *state_file, gpointer user_data)
+{
+ const gchar * argv[2];
+
+ g_print("Session save requested. Saving state.\n");
+
+ argv[0] = "audacious";
+ argv[1] = g_strdup_printf ("--display=%s", gdk_display_get_name (gdk_display_get_default()));
+ egg_sm_client_set_restart_command (client, 2, argv);
+
+ aud_config_save();
+}
+#endif
+
+void smclient_init (void)
+{
+#ifdef USE_EGGSM
+ EggSMClient *client;
+
+ client = egg_sm_client_get ();
+ if (client != NULL)
+ {
+ g_signal_connect (client, "quit",
+ G_CALLBACK (signal_session_quit_cb), NULL);
+ g_signal_connect (client, "save-state",
+ G_CALLBACK (signal_session_save_cb), NULL);
+
+ }
+#endif
+}
diff --git a/src/audacious/types.h b/src/audacious/types.h
index 7766828..50faaba 100644
--- a/src/audacious/types.h
+++ b/src/audacious/types.h
@@ -27,22 +27,29 @@
#define AUD_EQUALIZER_NBANDS 10
#define EQUALIZER_MAX_GAIN 12
-typedef struct _Plugin Plugin;
-typedef struct _InputPlugin InputPlugin;
-typedef struct _OutputPlugin OutputPlugin;
-typedef struct _EffectPlugin EffectPlugin;
-typedef struct _GeneralPlugin GeneralPlugin;
-typedef struct _VisPlugin VisPlugin;
-
-#define PLUGIN(x) ((Plugin *) (x))
-#define INPUT_PLUGIN(x) ((InputPlugin *) (x))
-#define OUTPUT_PLUGIN(x) ((OutputPlugin *) (x))
-#define EFFECT_PLUGIN(x) ((EffectPlugin *) (x))
-#define GENERAL_PLUGIN(x) ((GeneralPlugin *) (x))
-#define VIS_PLUGIN(x) ((VisPlugin *) (x))
-
-typedef struct _Interface Interface;
+typedef struct PluginHandle PluginHandle;
+
+#ifdef _AUDACIOUS_CORE
+typedef const struct _Plugin Plugin;
+#endif
+
+typedef const struct _InputPlugin InputPlugin;
+typedef const struct _OutputPlugin OutputPlugin;
+typedef const struct _EffectPlugin EffectPlugin;
+typedef const struct _GeneralPlugin GeneralPlugin;
+typedef const struct _VisPlugin VisPlugin;
+typedef const struct _TransportPlugin TransportPlugin;
+typedef const struct _PlaylistPlugin PlaylistPlugin;
+
+typedef struct _Iface Iface;
typedef struct _PluginPreferences PluginPreferences;
typedef struct _PreferencesWidget PreferencesWidget;
+typedef struct {
+ gfloat track_gain; /* dB */
+ gfloat track_peak; /* 0-1 */
+ gfloat album_gain; /* dB */
+ gfloat album_peak; /* 0-1 */
+} ReplayGainInfo;
+
#endif
diff --git a/src/audacious/ui_preferences.c b/src/audacious/ui_preferences.c
index 4d69b0b..7dbc2f9 100644
--- a/src/audacious/ui_preferences.c
+++ b/src/audacious/ui_preferences.c
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2007 Audacious development team.
+ * Copyright (C) 2005-2010 Audacious development team.
*
* 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
@@ -17,44 +17,29 @@
* Audacious or using our public API to be a derived work.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <glib.h>
-#include <gtk/gtk.h>
#include <string.h>
-#include <stddef.h>
#include <stdio.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
+
#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
#include <libaudcore/hook.h>
#include "audconfig.h"
-#include "compatibility.h"
+#include "config.h"
+#include "configdb.h"
#include "debug.h"
+#include "glib-compat.h"
+#include "gtk-compat.h"
#include "i18n.h"
#include "misc.h"
-#include "playback.h"
-#include "plugin.h"
-#include "pluginenum.h"
-#include "plugins.h"
-#include "effect.h"
-#include "general.h"
#include "output.h"
+#include "playback.h"
#include "playlist.h"
#include "playlist-utils.h"
-#include "visualization.h"
-#include "util.h"
-#include "configdb.h"
+#include "plugin.h"
+#include "plugins.h"
#include "preferences.h"
-
#include "ui_preferences.h"
#define TITLESTRING_UPDATE_TIMEOUT 3
@@ -68,22 +53,6 @@ enum CategoryViewCols {
CATEGORY_VIEW_N_COLS
};
-enum PluginViewCols {
- PLUGIN_VIEW_COL_ACTIVE,
- PLUGIN_VIEW_COL_DESC,
- PLUGIN_VIEW_COL_FILENAME,
- PLUGIN_VIEW_COL_ID,
- PLUGIN_VIEW_COL_PLUGIN_PTR,
- PLUGIN_VIEW_N_COLS
-};
-
-enum PluginViewType {
- PLUGIN_VIEW_TYPE_INPUT,
- PLUGIN_VIEW_TYPE_GENERAL,
- PLUGIN_VIEW_TYPE_VIS,
- PLUGIN_VIEW_TYPE_EFFECT
-};
-
typedef struct {
const gchar *icon_path;
const gchar *name;
@@ -94,11 +63,6 @@ typedef struct {
const gchar *tag;
} TitleFieldTag;
-typedef struct {
- gint x;
- gint y;
-} MenuPos;
-
static /* GtkWidget * */ void * prefswin = NULL;
static GtkWidget *filepopup_settings = NULL;
static GtkWidget *category_treeview = NULL;
@@ -121,12 +85,11 @@ GtkWidget *filepopup_for_tuple_settings_button;
static gint titlestring_timeout_counter = 0;
static Category categories[] = {
- {DATA_DIR "/images/audio.png", N_("Audio")},
- {DATA_DIR "/images/replay_gain.png", N_("Replay Gain")},
- {DATA_DIR "/images/connectivity.png", N_("Network")},
- {DATA_DIR "/images/playback.png", N_("Playback")},
- {DATA_DIR "/images/playlist.png", N_("Playlist")},
- {DATA_DIR "/images/plugins.png", N_("Plugins")},
+ {"audio.png", N_("Audio")},
+ {"replay_gain.png", N_("Replay Gain")},
+ {"connectivity.png", N_("Network")},
+ {"playlist.png", N_("Playlist")},
+ {"plugins.png", N_("Plugins")},
};
static gint n_categories = G_N_ELEMENTS(categories);
@@ -191,23 +154,27 @@ static PreferencesWidget audio_page_widgets[] = {
N_("Use software volume control. This may be useful for situations where your audio system does not support controlling the playback volume."), FALSE},
};
-static PreferencesWidget rg_params_elements[] = {
- {WIDGET_SPIN_BTN, N_("Preamp:"), &cfg.replay_gain_preamp, NULL, NULL, FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT},
- {WIDGET_SPIN_BTN, N_("Default gain:"), &cfg.default_gain, NULL, N_("This gain will be used if file doesn't contain Replay Gain metadata."), FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT},
- {WIDGET_LABEL, N_("<span size=\"small\">Please remember that the most efficient way to prevent signal clipping is not to use positive values above.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-info"}}},
-};
-
-static PreferencesWidget replay_gain_page_widgets[] = {
- {WIDGET_LABEL, N_("<b>Replay Gain configuration</b>"), NULL, NULL, NULL, FALSE},
- {WIDGET_CHK_BTN, N_("Enable Replay Gain"), &cfg.enable_replay_gain, NULL, NULL, FALSE},
- {WIDGET_LABEL, N_("<b>Replay Gain mode</b>"), NULL, NULL, NULL, TRUE},
- {WIDGET_RADIO_BTN, N_("Track gain/peak"), &cfg.replay_gain_track, NULL, NULL, TRUE},
- {WIDGET_RADIO_BTN, N_("Album gain/peak"), &cfg.replay_gain_album, NULL, NULL, TRUE},
- {WIDGET_LABEL, N_("<b>Miscellaneous</b>"), NULL, NULL, NULL, TRUE},
- {WIDGET_CHK_BTN, N_("Enable peak info clipping prevention"), &cfg.enable_clipping_prevention, NULL,
- N_("Use peak value from Replay Gain info for clipping prevention"), TRUE},
- {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {rg_params_elements, G_N_ELEMENTS(rg_params_elements)}}},
-};
+static PreferencesWidget rg_params_elements[] =
+{{WIDGET_SPIN_BTN, N_("Amplify all files:"), & cfg.replay_gain_preamp, NULL,
+ NULL, FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT},
+{WIDGET_SPIN_BTN, N_("Amplify untagged files:"), & cfg.default_gain, NULL,
+ NULL, FALSE, {.spin_btn = {-15, 15, 0.01, N_("dB")}}, VALUE_FLOAT}};
+
+static PreferencesWidget replay_gain_page_widgets[] =
+ {{WIDGET_LABEL, N_("<b>Replay Gain</b>"), NULL, NULL, NULL, FALSE},
+ {WIDGET_CHK_BTN, N_("Enable Replay Gain"), &cfg.enable_replay_gain, NULL,
+ NULL, FALSE},
+ {WIDGET_LABEL, N_("<b>Mode</b>"), NULL, NULL, NULL, TRUE},
+ {WIDGET_RADIO_BTN, N_("Single track mode"), &cfg.replay_gain_track, NULL,
+ NULL, TRUE},
+ {WIDGET_RADIO_BTN, N_("Album mode"), &cfg.replay_gain_album, NULL, NULL,
+ TRUE},
+ {WIDGET_LABEL, N_("<b>Adjust Levels</b>"), NULL, NULL, NULL, TRUE},
+ {WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {rg_params_elements,
+ G_N_ELEMENTS (rg_params_elements)}}},
+ {WIDGET_LABEL, N_("<b>Clipping Prevention</b>"), NULL, NULL, NULL, TRUE},
+ {WIDGET_CHK_BTN, N_("Enable clipping prevention"),
+ & cfg.enable_clipping_prevention, NULL, NULL, TRUE}};
static PreferencesWidget proxy_host_port_elements[] = {
{WIDGET_ENTRY, N_("Proxy hostname:"), "proxy_host", NULL, NULL, FALSE, {.entry = {FALSE}}, VALUE_CFG_STRING},
@@ -230,16 +197,6 @@ static PreferencesWidget connectivity_page_widgets[] = {
{WIDGET_LABEL, N_("<span size=\"small\">Changing these settings will require a restart of Audacious.</span>"), NULL, NULL, NULL, FALSE, {.label = {"gtk-dialog-warning"}}},
};
-static PreferencesWidget playback_page_widgets[] = {
- {WIDGET_LABEL, N_("<b>Playback</b>"), NULL, NULL, NULL, FALSE},
- {WIDGET_CHK_BTN, N_("Continue playback on startup"), &cfg.resume_playback_on_startup, NULL,
- N_("When Audacious starts, automatically begin playing from the point where we stopped before."), FALSE},
- {WIDGET_CHK_BTN, N_("Don't advance in the playlist"), &cfg.no_playlist_advance, NULL,
- N_("When finished playing a song, don't automatically advance to the next."), FALSE},
- {WIDGET_CHK_BTN, N_("Clear current playlist when opening new files"),
- & cfg.clear_playlist, NULL, NULL, FALSE},
-};
-
static PreferencesWidget chardet_elements[] = {
{WIDGET_COMBO_BOX, N_("Auto character encoding detector for:"), &cfg.chardet_detector, NULL, NULL, TRUE,
{.combo = {chardet_detector_presets, G_N_ELEMENTS(chardet_detector_presets),
@@ -253,25 +210,20 @@ static PreferencesWidget chardet_elements[] = {
};
static PreferencesWidget playlist_page_widgets[] = {
+ {WIDGET_LABEL, N_("<b>Behavior</b>"), NULL, NULL, NULL, FALSE},
+ {WIDGET_CHK_BTN, N_("Continue playback on startup"),
+ & cfg.resume_playback_on_startup, NULL, NULL, FALSE},
+ {WIDGET_CHK_BTN, N_("Advance when the current song is deleted"),
+ & cfg.advance_on_delete, NULL, NULL, FALSE},
+ {WIDGET_CHK_BTN, N_("Clear the playlist when opening files"),
+ & cfg.clear_playlist, NULL, NULL, FALSE},
+ {WIDGET_CHK_BTN, N_("Open files in a temporary playlist"),
+ & cfg.open_to_temporary, NULL, NULL, FALSE},
{WIDGET_LABEL, N_("<b>Metadata</b>"), NULL, NULL, NULL, FALSE},
{WIDGET_TABLE, NULL, NULL, NULL, NULL, TRUE, {.table = {chardet_elements, G_N_ELEMENTS(chardet_elements)}}},
};
static void prefswin_page_queue_destroy(CategoryQueueEntry *ent);
-void create_plugin_preferences_page(PluginPreferences *settings);
-void destroy_plugin_preferences_page(PluginPreferences *settings);
-
-static void output_about (OutputPlugin * plugin)
-{
- if (plugin->about != NULL)
- plugin->about ();
-}
-
-static void output_configure (OutputPlugin * plugin)
-{
- if (plugin->configure != NULL)
- plugin->configure ();
-}
static void
change_category(GtkNotebook * notebook,
@@ -288,218 +240,6 @@ change_category(GtkNotebook * notebook,
gtk_notebook_set_current_page(notebook, index);
}
-static void output_plugin_open_prefs (GtkComboBox * combo, void * unused)
-{
- output_configure (g_list_nth_data (get_output_list (),
- gtk_combo_box_get_active (combo)));
-}
-
-static void output_plugin_open_info (GtkComboBox * combo, void * unused)
-{
- output_about (g_list_nth_data (get_output_list (), gtk_combo_box_get_active
- (combo)));
-}
-
-static void
-plugin_toggle(GtkCellRendererToggle * cell,
- const gchar * path_str,
- gpointer data)
-{
- GtkTreeModel *model = GTK_TREE_MODEL(data);
- GtkTreeIter iter;
- GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
- Plugin *plugin = NULL;
- gint plugin_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(data), "plugin_type"));
- gboolean enabled;
-
- /* get toggled iter */
- gtk_tree_model_get_iter(model, &iter, path);
-
- gtk_tree_model_get (model, & iter, PLUGIN_VIEW_COL_ACTIVE, & enabled,
- PLUGIN_VIEW_COL_PLUGIN_PTR, & plugin, -1);
- enabled = ! enabled;
-
- switch (plugin_type)
- {
- case PLUGIN_VIEW_TYPE_INPUT:
- plugin_set_enabled (plugin_by_header (plugin), enabled);
- break;
- case PLUGIN_VIEW_TYPE_GENERAL:
- general_plugin_enable (plugin_by_header (plugin), enabled);
- break;
- case PLUGIN_VIEW_TYPE_VIS:
- vis_plugin_enable (plugin_by_header (plugin), enabled);
- break;
- case PLUGIN_VIEW_TYPE_EFFECT:
- effect_plugin_enable (plugin_by_header (plugin), enabled);
- break;
- }
-
- gtk_list_store_set ((GtkListStore *) model, & iter, PLUGIN_VIEW_COL_ACTIVE,
- enabled, -1);
-
- if (plugin && plugin->settings && plugin->settings->type == PREFERENCES_PAGE) {
- if (enabled)
- create_plugin_preferences_page(plugin->settings);
- else
- destroy_plugin_preferences_page(plugin->settings);
- }
- /* clean up */
- gtk_tree_path_free(path);
-}
-
-static void on_output_plugin_cbox_changed (GtkComboBox * combo, void * unused)
-{
- set_current_output_plugin (g_list_nth_data (get_output_list (),
- gtk_combo_box_get_active (combo)));
-}
-
-static void
-on_output_plugin_cbox_realize(GtkComboBox * cbox,
- gpointer data)
-{
- GList *olist = get_output_list();
- OutputPlugin * op;
- gint i = 0, selected = 0;
-
- if (olist == NULL) {
- gtk_widget_set_sensitive(GTK_WIDGET(cbox), FALSE);
- return;
- }
-
- for (i = 0; olist != NULL; i++, olist = g_list_next(olist)) {
- op = OUTPUT_PLUGIN(olist->data);
-
- if (olist->data == current_output_plugin)
- selected = i;
-
- gtk_combo_box_append_text(cbox, op->description);
- }
-
- gtk_combo_box_set_active(cbox, selected);
- g_signal_connect(cbox, "changed",
- G_CALLBACK(on_output_plugin_cbox_changed), NULL);
-}
-
-static void
-on_plugin_view_realize(GtkTreeView * treeview,
- GCallback callback,
- gpointer data,
- gint plugin_type)
-{
- GtkListStore *store;
- GtkTreeIter iter;
-
- GtkCellRenderer *renderer;
- GtkTreeViewColumn *column;
-
- GList *ilist;
- gchar *description[2];
- gint id = 0;
-
- GList *list = (GList *) data;
-
- store = gtk_list_store_new(PLUGIN_VIEW_N_COLS,
- G_TYPE_BOOLEAN, G_TYPE_STRING,
- G_TYPE_STRING, G_TYPE_INT, G_TYPE_POINTER);
- g_object_set_data(G_OBJECT(store), "plugin_type" , GINT_TO_POINTER(plugin_type));
-
- column = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(column, _("Enabled"));
- gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
- gtk_tree_view_column_set_spacing(column, 4);
- gtk_tree_view_column_set_resizable(column, FALSE);
- gtk_tree_view_column_set_fixed_width(column, 50);
-
- renderer = gtk_cell_renderer_toggle_new();
- g_signal_connect(renderer, "toggled",
- G_CALLBACK(callback), store);
- gtk_tree_view_column_pack_start(column, renderer, TRUE);
- gtk_tree_view_column_set_attributes(column, renderer, "active",
- PLUGIN_VIEW_COL_ACTIVE, NULL);
-
- gtk_tree_view_append_column(treeview, column);
-
- column = gtk_tree_view_column_new();
- gtk_tree_view_column_set_title(column, _("Description"));
- gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
- gtk_tree_view_column_set_spacing(column, 4);
- gtk_tree_view_column_set_resizable(column, TRUE);
-
-
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(column, renderer, FALSE);
- gtk_tree_view_column_set_attributes(column, renderer,
- "text", PLUGIN_VIEW_COL_DESC, NULL);
- gtk_tree_view_append_column(treeview, column);
-
- column = gtk_tree_view_column_new();
-
- gtk_tree_view_column_set_title(column, _("Filename"));
- gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
- gtk_tree_view_column_set_spacing(column, 4);
- gtk_tree_view_column_set_resizable(column, TRUE);
-
- renderer = gtk_cell_renderer_text_new();
- gtk_tree_view_column_pack_start(column, renderer, TRUE);
- gtk_tree_view_column_set_attributes(column, renderer, "text",
- PLUGIN_VIEW_COL_FILENAME, NULL);
-
- gtk_tree_view_append_column(treeview, column);
-
- MOWGLI_ITER_FOREACH(ilist, list)
- {
- Plugin *plugin = PLUGIN(ilist->data);
- gboolean enabled = plugin_get_enabled (plugin_by_header (plugin));
-
- description[0] = g_strdup(plugin->description);
- description[1] = g_strdup(plugin->filename);
-
- gtk_list_store_append(store, &iter);
- gtk_list_store_set(store, &iter,
- PLUGIN_VIEW_COL_ACTIVE, enabled,
- PLUGIN_VIEW_COL_DESC, description[0],
- PLUGIN_VIEW_COL_FILENAME, description[1],
- PLUGIN_VIEW_COL_ID, id++,
- PLUGIN_VIEW_COL_PLUGIN_PTR, plugin, -1);
-
- g_free(description[1]);
- g_free(description[0]);
- }
-
- gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
-}
-
-static void
-on_input_plugin_view_realize(GtkTreeView * treeview,
- gpointer data)
-{
- on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list(PLUGIN_TYPE_INPUT), PLUGIN_VIEW_TYPE_INPUT);
-}
-
-static void
-on_effect_plugin_view_realize(GtkTreeView * treeview,
- gpointer data)
-{
- on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list
- (PLUGIN_TYPE_EFFECT), PLUGIN_VIEW_TYPE_EFFECT);
-}
-
-static void
-on_general_plugin_view_realize(GtkTreeView * treeview,
- gpointer data)
-{
- on_plugin_view_realize (treeview, (GCallback) plugin_toggle, plugin_get_list
- (PLUGIN_TYPE_GENERAL), PLUGIN_VIEW_TYPE_GENERAL);
-}
-
-static void
-on_vis_plugin_view_realize(GtkTreeView * treeview,
- gpointer data)
-{
- on_plugin_view_realize(treeview, G_CALLBACK(plugin_toggle), plugin_get_list(PLUGIN_TYPE_VIS), PLUGIN_VIEW_TYPE_VIS);
-}
-
static void
editable_insert_text(GtkEditable * editable,
const gchar * text,
@@ -529,51 +269,11 @@ titlestring_tag_menu_callback(GtkMenuItem * menuitem,
}
static void
-util_menu_position(GtkMenu * menu, gint * x, gint * y,
- gboolean * push_in, gpointer data)
-{
- GtkRequisition requisition;
- gint screen_width;
- gint screen_height;
- MenuPos *pos = data;
-
- gtk_widget_size_request(GTK_WIDGET(menu), &requisition);
-
- screen_width = gdk_screen_width();
- screen_height = gdk_screen_height();
-
- *x = CLAMP(pos->x - 2, 0, MAX(0, screen_width - requisition.width));
- *y = CLAMP(pos->y - 2, 0, MAX(0, screen_height - requisition.height));
-}
-
-static void
on_titlestring_help_button_clicked(GtkButton * button,
gpointer data)
{
- GtkMenu *menu;
- MenuPos *pos = g_newa(MenuPos, 1);
- GdkWindow *parent, *window;
-
- gint x_ro, y_ro;
- gint x_widget, y_widget;
- gint x_size, y_size;
-
- g_return_if_fail (button != NULL);
- g_return_if_fail (GTK_IS_MENU (data));
-
- parent = gtk_widget_get_parent_window(GTK_WIDGET(button));
- window = gtk_widget_get_window(GTK_WIDGET(button));
-
- gdk_drawable_get_size(parent, &x_size, &y_size);
- gdk_window_get_root_origin(window, &x_ro, &y_ro);
- gdk_window_get_position(window, &x_widget, &y_widget);
-
- pos->x = x_size + x_ro;
- pos->y = y_size + y_ro - 100;
-
- menu = GTK_MENU(data);
- gtk_menu_popup (menu, NULL, NULL, util_menu_position, pos,
- 0, GDK_CURRENT_TIME);
+ GtkMenu * menu = data;
+ gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 0, GDK_CURRENT_TIME);
}
@@ -674,8 +374,7 @@ plugin_preferences_cancel(GtkWidget *widget, PluginPreferences *settings)
gtk_widget_destroy(GTK_WIDGET(settings->data));
}
-static void
-plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings)
+static void plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings)
{
gtk_widget_destroy(widget);
@@ -685,8 +384,7 @@ plugin_preferences_destroy(GtkWidget *widget, PluginPreferences *settings)
settings->data = NULL;
}
-static void
-create_plugin_preferences(PluginPreferences *settings)
+void plugin_preferences_show (PluginPreferences * settings)
{
GtkWidget *window;
GtkWidget *vbox, *bbox, *ok, *apply, *cancel;
@@ -738,112 +436,13 @@ create_plugin_preferences(PluginPreferences *settings)
settings->data = (gpointer)window;
}
-static void
-plugin_treeview_open_prefs(GtkTreeView *treeview)
-{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
- GtkTreeIter iter;
- Plugin *plugin = NULL;
-
- selection = gtk_tree_view_get_selection(treeview);
- if (!gtk_tree_selection_get_selected(selection, &model, &iter))
- return;
- gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
-
- g_return_if_fail(plugin != NULL);
- g_return_if_fail((plugin->configure != NULL) ||
- ((plugin->settings != NULL) && (plugin->settings->type == PREFERENCES_WINDOW)));
-
- if (plugin->configure != NULL)
- plugin->configure();
- else
- create_plugin_preferences(plugin->settings);
-}
-
-static void
-plugin_treeview_open_info(GtkTreeView *treeview)
-{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
- GtkTreeIter iter;
- Plugin *plugin = NULL;
-
- selection = gtk_tree_view_get_selection(treeview);
- if (!gtk_tree_selection_get_selected(selection, &model, &iter))
- return;
- gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
-
- g_return_if_fail(plugin != NULL);
- plugin->about();
-}
-
-static void
-plugin_treeview_enable_prefs(GtkTreeView * treeview, GtkButton * button)
-{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
- GtkTreeIter iter;
- Plugin *plugin = NULL;
-
- selection = gtk_tree_view_get_selection(treeview);
- if (!gtk_tree_selection_get_selected(selection, &model, &iter))
- return;
-
- gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
-
- g_return_if_fail(plugin != NULL);
-
- gtk_widget_set_sensitive(GTK_WIDGET(button),
- ((plugin->configure != NULL) ||
- (plugin->settings ? (plugin->settings->type == PREFERENCES_WINDOW) : FALSE)));
-}
-
-static void
-plugin_treeview_enable_info(GtkTreeView * treeview, GtkButton * button)
+void plugin_preferences_cleanup (PluginPreferences * p)
{
- GtkTreeSelection *selection;
- GtkTreeModel *model;
- GtkTreeIter iter;
- Plugin *plugin = NULL;
-
- selection = gtk_tree_view_get_selection(treeview);
- if (!gtk_tree_selection_get_selected(selection, &model, &iter))
- return;
-
- gtk_tree_model_get(model, &iter, PLUGIN_VIEW_COL_PLUGIN_PTR, &plugin, -1);
-
- g_return_if_fail(plugin != NULL);
-
- gtk_widget_set_sensitive(GTK_WIDGET(button), plugin->about != NULL);
-}
-
-
-static void
-output_plugin_enable_info(GtkComboBox * cbox, GtkButton * button)
-{
- GList *plist;
-
- gint id = gtk_combo_box_get_active(cbox);
-
- plist = get_output_list();
- plist = g_list_nth(plist, id);
-
- gtk_widget_set_sensitive(GTK_WIDGET(button),
- OUTPUT_PLUGIN(plist->data)->about != NULL);
-}
-
-static void
-output_plugin_enable_prefs(GtkComboBox * cbox, GtkButton * button)
-{
- GList *plist;
- gint id = gtk_combo_box_get_active(cbox);
-
- plist = get_output_list();
- plist = g_list_nth(plist, id);
-
- gtk_widget_set_sensitive(GTK_WIDGET(button),
- OUTPUT_PLUGIN(plist->data)->configure != NULL);
+ if (p->data != NULL)
+ {
+ gtk_widget_destroy (p->data);
+ p->data = NULL;
+ }
}
static void
@@ -920,8 +519,13 @@ on_category_treeview_realize(GtkTreeView * treeview,
GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_INT);
gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
- for (i = 0; i < n_categories; i++) {
- img = gdk_pixbuf_new_from_file(categories[i].icon_path, NULL);
+ for (i = 0; i < n_categories; i ++)
+ {
+ gchar * path = g_strdup_printf ("%s/images/%s",
+ get_path (AUD_PATH_DATA_DIR), categories[i].icon_path);
+ img = gdk_pixbuf_new_from_file (path, NULL);
+ g_free (path);
+
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter,
CATEGORY_VIEW_COL_ICON, img,
@@ -1134,20 +738,19 @@ on_cbox_changed_string(GtkComboBox * combobox, PreferencesWidget *widget)
gint position = 0;
position = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox));
-
+
g_free(*((gchar **)widget->cfg));
-
+
*((gchar **)widget->cfg) = g_strdup(widget->data.combo.elements[position].value);
}
-static void
-on_cbox_realize(GtkComboBox *combobox, PreferencesWidget * widget)
+static void on_cbox_realize (GtkWidget * combobox, PreferencesWidget * widget)
{
guint i=0,index=0;
- for(i=0; i<widget->data.combo.n_elements; i++) {
- gtk_combo_box_append_text(combobox, _(widget->data.combo.elements[i].label));
- }
+ for (i = 0; i < widget->data.combo.n_elements; i ++)
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) combobox,
+ _(widget->data.combo.elements[i].label));
if (widget->data.combo.enabled) {
switch (widget->cfg_type) {
@@ -1198,8 +801,8 @@ create_filepopup_settings(void)
GtkWidget *label_misc;
GtkWidget *label_delay;
- GtkObject *recurse_for_cover_depth_adj;
- GtkObject *delay_adj;
+ GtkAdjustment *recurse_for_cover_depth_adj;
+ GtkAdjustment *delay_adj;
GtkWidget *alignment;
GtkWidget *hbox;
@@ -1278,7 +881,8 @@ create_filepopup_settings(void)
gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), label_search_depth, TRUE, TRUE, 0);
gtk_misc_set_padding(GTK_MISC(label_search_depth), 4, 0);
- recurse_for_cover_depth_adj = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
+ recurse_for_cover_depth_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0,
+ 100, 1, 10, 0);
filepopup_settings_recurse_for_cover_depth = gtk_spin_button_new(GTK_ADJUSTMENT(recurse_for_cover_depth_adj), 1, 0);
gtk_box_pack_start(GTK_BOX(filepopup_settings_recurse_for_cover_depth_box), filepopup_settings_recurse_for_cover_depth, TRUE, TRUE, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_recurse_for_cover_depth), TRUE);
@@ -1314,7 +918,7 @@ create_filepopup_settings(void)
gtk_misc_set_alignment(GTK_MISC(label_delay), 0, 0.5);
gtk_misc_set_padding(GTK_MISC(label_delay), 12, 0);
- delay_adj = gtk_adjustment_new(0, 0, 100, 1, 10, 0);
+ delay_adj = (GtkAdjustment *) gtk_adjustment_new (0, 0, 100, 1, 10, 0);
filepopup_settings_delay = gtk_spin_button_new(GTK_ADJUSTMENT(delay_adj), 1, 0);
gtk_box_pack_start(GTK_BOX(hbox), filepopup_settings_delay, TRUE, TRUE, 0);
gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(filepopup_settings_delay), TRUE);
@@ -1482,7 +1086,7 @@ static void create_label (PreferencesWidget * widget, GtkWidget * * label,
static void create_cbox (PreferencesWidget * widget, GtkWidget * * label,
GtkWidget * * combobox, const gchar * domain)
{
- *combobox = gtk_combo_box_new_text();
+ * combobox = gtk_combo_box_text_new ();
if (widget->label) {
* label = gtk_label_new (dgettext (domain, widget->label));
@@ -1783,20 +1387,6 @@ create_titlestring_tag_menu(void)
}
static void
-create_playback_category(void)
-{
- GtkWidget *playback_page_vbox;
- GtkWidget *widgets_vbox;
-
- playback_page_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (category_notebook), playback_page_vbox);
-
- widgets_vbox = gtk_vbox_new (FALSE, 0);
- create_widgets(GTK_BOX(widgets_vbox), playback_page_widgets, G_N_ELEMENTS(playback_page_widgets));
- gtk_box_pack_start (GTK_BOX (playback_page_vbox), widgets_vbox, TRUE, TRUE, 0);
-}
-
-static void
create_replay_gain_category(void)
{
GtkWidget *rg_page_vbox;
@@ -1814,14 +1404,29 @@ static void show_numbers_cb (GtkToggleButton * numbers, void * unused)
{
cfg.show_numbers_in_pl = gtk_toggle_button_get_active (numbers);
- hook_call ("playlist update", NULL);
hook_call ("title change", NULL);
+
+ /* trigger playlist update */
+ gchar * t = g_strdup (playlist_get_title (playlist_get_active ()));
+ playlist_set_title (playlist_get_active (), t);
+ g_free (t);
+}
+
+static void leading_zero_cb (GtkToggleButton * leading)
+{
+ cfg.leading_zero = gtk_toggle_button_get_active (leading);
+
+ hook_call ("title change", NULL);
+
+ /* trigger playlist update */
+ gchar * t = g_strdup (playlist_get_title (playlist_get_active ()));
+ playlist_set_title (playlist_get_active (), t);
+ g_free (t);
}
static void
create_playlist_category(void)
{
- GtkWidget *playlist_page_vbox;
GtkWidget *vbox5;
GtkWidget *alignment55;
GtkWidget *label60;
@@ -1842,11 +1447,8 @@ create_playlist_category(void)
GtkWidget *titlestring_tag_menu = create_titlestring_tag_menu();
GtkWidget * numbers_alignment, * numbers;
- playlist_page_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (category_notebook), playlist_page_vbox);
-
vbox5 = gtk_vbox_new (FALSE, 0);
- gtk_box_pack_start (GTK_BOX (playlist_page_vbox), vbox5, TRUE, TRUE, 0);
+ gtk_container_add ((GtkContainer *) category_notebook, vbox5);
create_widgets(GTK_BOX(vbox5), playlist_page_widgets, G_N_ELEMENTS(playlist_page_widgets));
@@ -1870,6 +1472,17 @@ create_playlist_category(void)
show_numbers_cb, 0);
gtk_container_add ((GtkContainer *) numbers_alignment, numbers);
+ numbers_alignment = gtk_alignment_new (0, 0, 0, 0);
+ gtk_alignment_set_padding ((GtkAlignment *) numbers_alignment, 0, 0, 12, 0);
+ gtk_box_pack_start ((GtkBox *) vbox5, numbers_alignment, 0, 0, 3);
+
+ numbers = gtk_check_button_new_with_label (_("Show leading zeroes (02:00 "
+ "instead of 2:00)"));
+ gtk_toggle_button_set_active ((GtkToggleButton *) numbers, cfg.leading_zero);
+ g_signal_connect ((GObject *) numbers, "toggled", (GCallback)
+ leading_zero_cb, 0);
+ gtk_container_add ((GtkContainer *) numbers_alignment, numbers);
+
alignment56 = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_box_pack_start (GTK_BOX (vbox5), alignment56, FALSE, FALSE, 0);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment56), 0, 0, 12, 0);
@@ -1892,17 +1505,19 @@ create_playlist_category(void)
image1 = gtk_image_new_from_stock ("gtk-index", GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (titlestring_help_button), image1);
- titlestring_cbox = gtk_combo_box_new_text ();
+ titlestring_cbox = gtk_combo_box_text_new ();
+
gtk_table_attach (GTK_TABLE (table6), titlestring_cbox, 1, 3, 0, 1,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - ALBUM - TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST - ALBUM - TRACK. TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ARTIST [ ALBUM ] - TRACK. TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("ALBUM - TITLE"));
- gtk_combo_box_append_text (GTK_COMBO_BOX (titlestring_cbox), _("Custom"));
+
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST - ALBUM - TRACK. TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ARTIST [ ALBUM ] - TRACK. TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("ALBUM - TITLE"));
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) titlestring_cbox, _("Custom"));
titlestring_entry = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table6), titlestring_entry, 1, 2, 1, 2,
@@ -1995,6 +1610,68 @@ create_playlist_category(void)
create_filepopup_settings();
}
+static GtkWidget * output_config_button, * output_about_button;
+
+static gboolean output_enum_cb (PluginHandle * plugin, GList * * list)
+{
+ * list = g_list_prepend (* list, plugin);
+ return TRUE;
+}
+
+static GList * output_get_list (void)
+{
+ static GList * list = NULL;
+
+ if (list == NULL)
+ {
+ plugin_for_each (PLUGIN_TYPE_OUTPUT, (PluginForEachFunc) output_enum_cb,
+ & list);
+ list = g_list_reverse (list);
+ }
+
+ return list;
+}
+
+static void output_combo_update (GtkComboBox * combo)
+{
+ PluginHandle * plugin = plugin_get_current (PLUGIN_TYPE_OUTPUT);
+ gtk_combo_box_set_active (combo, g_list_index (output_get_list (), plugin));
+ gtk_widget_set_sensitive (output_config_button, plugin_has_configure (plugin));
+ gtk_widget_set_sensitive (output_about_button, plugin_has_about (plugin));
+}
+
+static void output_combo_changed (GtkComboBox * combo)
+{
+ PluginHandle * plugin = g_list_nth_data (output_get_list (),
+ gtk_combo_box_get_active (combo));
+ g_return_if_fail (plugin != NULL);
+
+ plugin_enable (plugin, TRUE);
+ output_combo_update (combo);
+}
+
+static void output_combo_fill (GtkComboBox * combo)
+{
+ for (GList * node = output_get_list (); node != NULL; node = node->next)
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
+ plugin_get_name (node->data));
+}
+
+static void output_do_config (void)
+{
+ OutputPlugin * op = plugin_get_header (output_plugin_get_current ());
+ g_return_if_fail (op != NULL);
+ if (op->configure != NULL)
+ op->configure ();
+}
+
+static void output_do_about (void)
+{
+ OutputPlugin * op = plugin_get_header (output_plugin_get_current ());
+ g_return_if_fail (op != NULL);
+ if (op->about != NULL)
+ op->about ();
+}
static void
create_audio_category(void)
@@ -2006,22 +1683,10 @@ create_audio_category(void)
GtkWidget *vbox33;
GtkWidget *table11;
GtkWidget *label79;
- GtkObject *output_plugin_bufsize_adj;
+ GtkAdjustment * output_plugin_bufsize_adj;
GtkWidget *output_plugin_bufsize;
GtkWidget *output_plugin_cbox;
GtkWidget *label78;
- GtkWidget *alignment82;
- GtkWidget *output_plugin_button_box;
- GtkWidget *output_plugin_prefs;
- GtkWidget *alignment76;
- GtkWidget *hbox7;
- GtkWidget *image5;
- GtkWidget *label80;
- GtkWidget *output_plugin_info;
- GtkWidget *alignment77;
- GtkWidget *hbox8;
- GtkWidget *image6;
- GtkWidget *label81;
audio_page_vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (category_notebook), audio_page_vbox);
@@ -2053,14 +1718,15 @@ create_audio_category(void)
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment (GTK_MISC (label79), 1, 0.5);
- output_plugin_bufsize_adj =
- gtk_adjustment_new (0, 100, 10000, 100, 1000, 0);
+ output_plugin_bufsize_adj = (GtkAdjustment *) gtk_adjustment_new (0, 100,
+ 10000, 100, 1000, 0);
output_plugin_bufsize = gtk_spin_button_new (GTK_ADJUSTMENT (output_plugin_bufsize_adj), 100, 0);
gtk_table_attach (GTK_TABLE (table11), output_plugin_bufsize, 1, 2, 1, 2,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
- output_plugin_cbox = gtk_combo_box_new_text ();
+ output_plugin_cbox = gtk_combo_box_text_new ();
+
gtk_table_attach (GTK_TABLE (table11), output_plugin_cbox, 1, 2, 0, 1,
(GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
(GtkAttachOptions) (0), 0, 0);
@@ -2071,77 +1737,32 @@ create_audio_category(void)
(GtkAttachOptions) (0), 0, 0);
gtk_misc_set_alignment (GTK_MISC (label78), 0, 0.5);
- alignment82 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start (GTK_BOX (audio_page_vbox), alignment82, FALSE, FALSE, 0);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment82), 0, 0, 12, 0);
-
- output_plugin_button_box = gtk_hbutton_box_new ();
- gtk_container_add (GTK_CONTAINER (alignment82), output_plugin_button_box);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (output_plugin_button_box), GTK_BUTTONBOX_START);
- gtk_box_set_spacing (GTK_BOX (output_plugin_button_box), 8);
-
- output_plugin_prefs = gtk_button_new ();
- gtk_container_add (GTK_CONTAINER (output_plugin_button_box), output_plugin_prefs);
- gtk_widget_set_sensitive (output_plugin_prefs, FALSE);
- gtk_widget_set_can_default(output_plugin_prefs, TRUE);
-
- alignment76 = gtk_alignment_new (0.5, 0.5, 0, 0);
- gtk_container_add (GTK_CONTAINER (output_plugin_prefs), alignment76);
+ GtkWidget * hbox = gtk_hbox_new (FALSE, 6);
+ gtk_box_pack_start ((GtkBox *) audio_page_vbox, hbox, FALSE, FALSE, 0);
- hbox7 = gtk_hbox_new (FALSE, 2);
- gtk_container_add (GTK_CONTAINER (alignment76), hbox7);
+ output_config_button = gtk_button_new_from_stock (GTK_STOCK_PREFERENCES);
+ output_about_button = gtk_button_new_from_stock (GTK_STOCK_ABOUT);
- image5 = gtk_image_new_from_stock ("gtk-preferences", GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start (GTK_BOX (hbox7), image5, FALSE, FALSE, 0);
-
- label80 = gtk_label_new_with_mnemonic (_("Output Plugin Preferences"));
- gtk_box_pack_start (GTK_BOX (hbox7), label80, FALSE, FALSE, 0);
-
- output_plugin_info = gtk_button_new ();
- gtk_container_add (GTK_CONTAINER (output_plugin_button_box), output_plugin_info);
- gtk_widget_set_sensitive (output_plugin_info, FALSE);
- gtk_widget_set_can_default(output_plugin_info, TRUE);
-
- alignment77 = gtk_alignment_new (0.5, 0.5, 0, 0);
- gtk_container_add (GTK_CONTAINER (output_plugin_info), alignment77);
-
- hbox8 = gtk_hbox_new (FALSE, 2);
- gtk_container_add (GTK_CONTAINER (alignment77), hbox8);
-
- image6 = gtk_image_new_from_stock ("gtk-about", GTK_ICON_SIZE_BUTTON);
- gtk_box_pack_start (GTK_BOX (hbox8), image6, FALSE, FALSE, 0);
-
- label81 = gtk_label_new_with_mnemonic (_("Output Plugin Information"));
- gtk_box_pack_start (GTK_BOX (hbox8), label81, FALSE, FALSE, 0);
+ gtk_box_pack_end ((GtkBox *) hbox, output_about_button, FALSE, FALSE, 0);
+ gtk_box_pack_end ((GtkBox *) hbox, output_config_button, FALSE, FALSE, 0);
create_widgets(GTK_BOX(audio_page_vbox), audio_page_widgets, G_N_ELEMENTS(audio_page_widgets));
+ output_combo_fill ((GtkComboBox *) output_plugin_cbox);
+ output_combo_update ((GtkComboBox *) output_plugin_cbox);
+ g_signal_connect (output_plugin_cbox, "changed", (GCallback)
+ output_combo_changed, NULL);
+ g_signal_connect (output_config_button, "clicked", (GCallback)
+ output_do_config, NULL);
+ g_signal_connect (output_about_button, "clicked", (GCallback)
+ output_do_about, NULL);
+
g_signal_connect(G_OBJECT(output_plugin_bufsize), "value_changed",
G_CALLBACK(on_output_plugin_bufsize_value_changed),
NULL);
g_signal_connect_after(G_OBJECT(output_plugin_bufsize), "realize",
G_CALLBACK(on_output_plugin_bufsize_realize),
NULL);
- g_signal_connect_after(G_OBJECT(output_plugin_cbox), "realize",
- G_CALLBACK(on_output_plugin_cbox_realize),
- NULL);
-
- /* plugin->output page */
-
- g_signal_connect(G_OBJECT(output_plugin_cbox), "changed",
- G_CALLBACK(output_plugin_enable_prefs),
- output_plugin_prefs);
- g_signal_connect_swapped(G_OBJECT(output_plugin_prefs), "clicked",
- G_CALLBACK(output_plugin_open_prefs),
- output_plugin_cbox);
-
- g_signal_connect(G_OBJECT(output_plugin_cbox), "changed",
- G_CALLBACK(output_plugin_enable_info),
- output_plugin_info);
- g_signal_connect_swapped(G_OBJECT(output_plugin_info), "clicked",
- G_CALLBACK(output_plugin_open_info),
- output_plugin_cbox);
-
}
static void
@@ -2159,361 +1780,24 @@ create_connectivity_category(void)
create_widgets(GTK_BOX(vbox29), connectivity_page_widgets, G_N_ELEMENTS(connectivity_page_widgets));
}
-static void
-create_plugin_category(void)
-{
- GtkWidget *plugin_page_vbox;
- GtkWidget *plugin_notebook;
- GtkWidget *plugin_input_vbox;
- GtkWidget *alignment43;
- GtkWidget *input_plugin_list_label;
- GtkWidget *scrolledwindow3;
- GtkWidget *input_plugin_view;
- GtkWidget *input_plugin_button_box;
- GtkWidget *input_plugin_prefs;
- GtkWidget *input_plugin_info;
- GtkWidget *plugin_input_label;
- GtkWidget *plugin_general_vbox;
- GtkWidget *alignment45;
- GtkWidget *label11;
- GtkWidget *scrolledwindow5;
- GtkWidget *general_plugin_view;
- GtkWidget *general_plugin_button_box;
- GtkWidget *general_plugin_prefs;
- GtkWidget *general_plugin_info;
- GtkWidget *plugin_general_label;
- GtkWidget *vbox21;
- GtkWidget *alignment46;
- GtkWidget *label53;
- GtkWidget *scrolledwindow7;
- GtkWidget *vis_plugin_view;
- GtkWidget *hbuttonbox6;
- GtkWidget *vis_plugin_prefs;
- GtkWidget *vis_plugin_info;
- GtkWidget *vis_label;
- GtkWidget *vbox25;
- GtkWidget *alignment58;
- GtkWidget *label64;
- GtkWidget *scrolledwindow9;
- GtkWidget *effect_plugin_view;
- GtkWidget *hbuttonbox9;
- GtkWidget *effect_plugin_prefs;
- GtkWidget *effect_plugin_info;
- GtkWidget *effects_label;
-
- plugin_page_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (category_notebook), plugin_page_vbox);
-
- plugin_notebook = gtk_notebook_new ();
- gtk_box_pack_start (GTK_BOX (plugin_page_vbox), plugin_notebook, TRUE, TRUE, 0);
- gtk_notebook_set_show_border (GTK_NOTEBOOK (plugin_notebook), FALSE);
-
- plugin_input_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (plugin_notebook), plugin_input_vbox);
- gtk_container_set_border_width (GTK_CONTAINER (plugin_input_vbox), 12);
-
- alignment43 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start (GTK_BOX (plugin_input_vbox), alignment43, FALSE, FALSE, 4);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment43), 0, 6, 0, 0);
-
- input_plugin_list_label = gtk_label_new_with_mnemonic (_("_Decoder list:"));
- gtk_container_add (GTK_CONTAINER (alignment43), input_plugin_list_label);
- gtk_label_set_use_markup (GTK_LABEL (input_plugin_list_label), TRUE);
- gtk_misc_set_alignment (GTK_MISC (input_plugin_list_label), 0, 0.5);
-
- scrolledwindow3 = gtk_scrolled_window_new (NULL, NULL);
- gtk_box_pack_start (GTK_BOX (plugin_input_vbox), scrolledwindow3, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow3), GTK_SHADOW_IN);
-
- input_plugin_view = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (scrolledwindow3), input_plugin_view);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (input_plugin_view), TRUE);
- gtk_tree_view_set_reorderable (GTK_TREE_VIEW (input_plugin_view), TRUE);
-
- input_plugin_button_box = gtk_hbutton_box_new ();
- gtk_box_pack_start (GTK_BOX (plugin_input_vbox), input_plugin_button_box, FALSE, FALSE, 8);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (input_plugin_button_box), GTK_BUTTONBOX_START);
- gtk_box_set_spacing (GTK_BOX (input_plugin_button_box), 8);
-
- input_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
- gtk_container_add (GTK_CONTAINER (input_plugin_button_box), input_plugin_prefs);
- gtk_widget_set_sensitive (input_plugin_prefs, FALSE);
- gtk_widget_set_can_default(input_plugin_prefs, TRUE);
-
- input_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
- gtk_container_add (GTK_CONTAINER (input_plugin_button_box), input_plugin_info);
- gtk_widget_set_sensitive (input_plugin_info, FALSE);
- gtk_widget_set_can_default(input_plugin_info, TRUE);
-
- plugin_input_label = gtk_label_new (_("<span size=\"medium\"><b>Decoders</b></span>"));
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 0), plugin_input_label);
- gtk_label_set_use_markup (GTK_LABEL (plugin_input_label), TRUE);
- gtk_misc_set_alignment (GTK_MISC (plugin_input_label), 0, 0);
-
- plugin_general_vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (plugin_notebook), plugin_general_vbox);
- gtk_container_set_border_width (GTK_CONTAINER (plugin_general_vbox), 12);
-
- alignment45 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start (GTK_BOX (plugin_general_vbox), alignment45, FALSE, FALSE, 4);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment45), 0, 6, 0, 0);
-
- label11 = gtk_label_new_with_mnemonic (_("_General plugin list:"));
- gtk_container_add (GTK_CONTAINER (alignment45), label11);
- gtk_label_set_use_markup (GTK_LABEL (label11), TRUE);
- gtk_misc_set_alignment (GTK_MISC (label11), 0, 0.5);
-
- scrolledwindow5 = gtk_scrolled_window_new (NULL, NULL);
- gtk_box_pack_start (GTK_BOX (plugin_general_vbox), scrolledwindow5, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow5), GTK_SHADOW_IN);
-
- general_plugin_view = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (scrolledwindow5), general_plugin_view);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (general_plugin_view), TRUE);
- gtk_tree_view_set_reorderable (GTK_TREE_VIEW (general_plugin_view), TRUE);
-
- general_plugin_button_box = gtk_hbutton_box_new ();
- gtk_box_pack_start (GTK_BOX (plugin_general_vbox), general_plugin_button_box, FALSE, FALSE, 8);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (general_plugin_button_box), GTK_BUTTONBOX_START);
- gtk_box_set_spacing (GTK_BOX (general_plugin_button_box), 8);
-
- general_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
- gtk_container_add (GTK_CONTAINER (general_plugin_button_box), general_plugin_prefs);
- gtk_widget_set_sensitive (general_plugin_prefs, FALSE);
- gtk_widget_set_can_default(general_plugin_prefs, TRUE);
-
- general_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
- gtk_container_add (GTK_CONTAINER (general_plugin_button_box), general_plugin_info);
- gtk_widget_set_sensitive (general_plugin_info, FALSE);
- gtk_widget_set_can_default(general_plugin_info, TRUE);
-
- plugin_general_label = gtk_label_new (_("<span size=\"medium\"><b>General</b></span>"));
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 1), plugin_general_label);
- gtk_label_set_use_markup (GTK_LABEL (plugin_general_label), TRUE);
-
- vbox21 = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (plugin_notebook), vbox21);
- gtk_container_set_border_width (GTK_CONTAINER (vbox21), 12);
-
- alignment46 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start (GTK_BOX (vbox21), alignment46, FALSE, FALSE, 4);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment46), 0, 6, 0, 0);
-
- label53 = gtk_label_new_with_mnemonic (_("_Visualization plugin list:"));
- gtk_container_add (GTK_CONTAINER (alignment46), label53);
- gtk_label_set_use_markup (GTK_LABEL (label53), TRUE);
- gtk_misc_set_alignment (GTK_MISC (label53), 0, 0.5);
-
- scrolledwindow7 = gtk_scrolled_window_new (NULL, NULL);
- gtk_box_pack_start (GTK_BOX (vbox21), scrolledwindow7, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow7), GTK_SHADOW_IN);
-
- vis_plugin_view = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (scrolledwindow7), vis_plugin_view);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (vis_plugin_view), TRUE);
- gtk_tree_view_set_reorderable (GTK_TREE_VIEW (vis_plugin_view), TRUE);
-
- hbuttonbox6 = gtk_hbutton_box_new ();
- gtk_box_pack_start (GTK_BOX (vbox21), hbuttonbox6, FALSE, FALSE, 8);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox6), GTK_BUTTONBOX_START);
- gtk_box_set_spacing (GTK_BOX (hbuttonbox6), 8);
-
- vis_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
- gtk_container_add (GTK_CONTAINER (hbuttonbox6), vis_plugin_prefs);
- gtk_widget_set_sensitive (vis_plugin_prefs, FALSE);
- gtk_widget_set_can_default(vis_plugin_prefs, TRUE);
-
- vis_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
- gtk_container_add (GTK_CONTAINER (hbuttonbox6), vis_plugin_info);
- gtk_widget_set_sensitive (vis_plugin_info, FALSE);
- gtk_widget_set_can_default(vis_plugin_info, TRUE);
-
- vis_label = gtk_label_new (_("<b>Visualization</b>"));
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 2), vis_label);
- gtk_label_set_use_markup (GTK_LABEL (vis_label), TRUE);
-
- vbox25 = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (plugin_notebook), vbox25);
- gtk_container_set_border_width (GTK_CONTAINER (vbox25), 12);
-
- alignment58 = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start (GTK_BOX (vbox25), alignment58, FALSE, FALSE, 4);
- gtk_alignment_set_padding (GTK_ALIGNMENT (alignment58), 0, 6, 0, 0);
-
- label64 = gtk_label_new (_("Effect plugins:"));
- gtk_container_add (GTK_CONTAINER (alignment58), label64);
- gtk_misc_set_alignment (GTK_MISC (label64), 0, 0.5);
-
- scrolledwindow9 = gtk_scrolled_window_new (NULL, NULL);
- gtk_box_pack_start (GTK_BOX (vbox25), scrolledwindow9, TRUE, TRUE, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow9), GTK_SHADOW_IN);
-
- effect_plugin_view = gtk_tree_view_new ();
- gtk_container_add (GTK_CONTAINER (scrolledwindow9), effect_plugin_view);
- gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (effect_plugin_view), TRUE);
- gtk_tree_view_set_reorderable (GTK_TREE_VIEW (effect_plugin_view), TRUE);
-
- hbuttonbox9 = gtk_hbutton_box_new ();
- gtk_box_pack_start (GTK_BOX (vbox25), hbuttonbox9, FALSE, FALSE, 8);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox9), GTK_BUTTONBOX_START);
- gtk_box_set_spacing (GTK_BOX (hbuttonbox9), 8);
-
- effect_plugin_prefs = gtk_button_new_from_stock ("gtk-preferences");
- gtk_container_add (GTK_CONTAINER (hbuttonbox9), effect_plugin_prefs);
- gtk_widget_set_sensitive (effect_plugin_prefs, FALSE);
- gtk_widget_set_can_default(effect_plugin_prefs, TRUE);
-
- effect_plugin_info = gtk_button_new_from_stock ("gtk-dialog-info");
- gtk_container_add (GTK_CONTAINER (hbuttonbox9), effect_plugin_info);
- gtk_widget_set_sensitive (effect_plugin_info, FALSE);
- gtk_widget_set_can_default(effect_plugin_info, TRUE);
-
- effects_label = gtk_label_new (_("<b>Effects</b>"));
- gtk_notebook_set_tab_label (GTK_NOTEBOOK (plugin_notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (plugin_notebook), 3), effects_label);
- gtk_label_set_use_markup (GTK_LABEL (effects_label), TRUE);
-
-
-
- gtk_label_set_mnemonic_widget (GTK_LABEL (input_plugin_list_label), category_notebook);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label11), category_notebook);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label53), category_notebook);
- gtk_label_set_mnemonic_widget (GTK_LABEL (label64), category_notebook);
-
-
-
- g_signal_connect_after(G_OBJECT(input_plugin_view), "realize",
- G_CALLBACK(on_input_plugin_view_realize),
- NULL);
- g_signal_connect_after(G_OBJECT(general_plugin_view), "realize",
- G_CALLBACK(on_general_plugin_view_realize),
- NULL);
- g_signal_connect_after(G_OBJECT(vis_plugin_view), "realize",
- G_CALLBACK(on_vis_plugin_view_realize),
- NULL);
- g_signal_connect_after(G_OBJECT(effect_plugin_view), "realize",
- G_CALLBACK(on_effect_plugin_view_realize),
- NULL);
-
-
-
- /* plugin->input page */
- g_object_set_data(G_OBJECT(input_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_INPUT));
- g_signal_connect(G_OBJECT(input_plugin_view), "row-activated",
- G_CALLBACK(plugin_treeview_open_prefs),
- NULL);
- g_signal_connect(G_OBJECT(input_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_prefs),
- input_plugin_prefs);
-
- g_signal_connect_swapped(G_OBJECT(input_plugin_prefs), "clicked",
- G_CALLBACK(plugin_treeview_open_prefs),
- input_plugin_view);
-
- g_signal_connect(G_OBJECT(input_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_info),
- input_plugin_info);
- g_signal_connect_swapped(G_OBJECT(input_plugin_info), "clicked",
- G_CALLBACK(plugin_treeview_open_info),
- input_plugin_view);
-
-
- /* plugin->general page */
-
- g_object_set_data(G_OBJECT(general_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_GENERAL));
- g_signal_connect(G_OBJECT(general_plugin_view), "row-activated",
- G_CALLBACK(plugin_treeview_open_prefs),
- NULL);
-
- g_signal_connect(G_OBJECT(general_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_prefs),
- general_plugin_prefs);
-
- g_signal_connect_swapped(G_OBJECT(general_plugin_prefs), "clicked",
- G_CALLBACK(plugin_treeview_open_prefs),
- general_plugin_view);
-
- g_signal_connect(G_OBJECT(general_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_info),
- general_plugin_info);
- g_signal_connect_swapped(G_OBJECT(general_plugin_info), "clicked",
- G_CALLBACK(plugin_treeview_open_info),
- general_plugin_view);
-
-
- /* plugin->vis page */
-
- g_object_set_data(G_OBJECT(vis_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_VIS));
- g_signal_connect(G_OBJECT(vis_plugin_view), "row-activated",
- G_CALLBACK(plugin_treeview_open_prefs),
- NULL);
- g_signal_connect_swapped(G_OBJECT(vis_plugin_prefs), "clicked",
- G_CALLBACK(plugin_treeview_open_prefs),
- vis_plugin_view);
- g_signal_connect(G_OBJECT(vis_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_prefs), vis_plugin_prefs);
-
- g_signal_connect(G_OBJECT(vis_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_info), vis_plugin_info);
- g_signal_connect_swapped(G_OBJECT(vis_plugin_info), "clicked",
- G_CALLBACK(plugin_treeview_open_info),
- vis_plugin_view);
-
-
- /* plugin->effects page */
-
- g_object_set_data(G_OBJECT(effect_plugin_view), "plugin_type" , GINT_TO_POINTER(PLUGIN_VIEW_TYPE_EFFECT));
- g_signal_connect(G_OBJECT(effect_plugin_view), "row-activated",
- G_CALLBACK(plugin_treeview_open_prefs),
- NULL);
- g_signal_connect_swapped(G_OBJECT(effect_plugin_prefs), "clicked",
- G_CALLBACK(plugin_treeview_open_prefs),
- effect_plugin_view);
- g_signal_connect(G_OBJECT(effect_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_prefs), effect_plugin_prefs);
-
- g_signal_connect(G_OBJECT(effect_plugin_view), "cursor-changed",
- G_CALLBACK(plugin_treeview_enable_info), effect_plugin_info);
- g_signal_connect_swapped(G_OBJECT(effect_plugin_info), "clicked",
- G_CALLBACK(plugin_treeview_open_info),
- effect_plugin_view);
-
-}
-
-static void
-destroy_plugin_page(GList *list)
+static void create_plugin_category (void)
{
- GList *iter;
+ GtkWidget * notebook = gtk_notebook_new ();
+ gtk_container_add ((GtkContainer *) category_notebook, notebook);
- MOWGLI_ITER_FOREACH(iter, list)
- {
- Plugin *plugin = PLUGIN(iter->data);
- if (plugin->settings && plugin->settings->data) {
- plugin->settings->data = NULL;
- if (plugin->settings->apply)
- plugin->settings->apply();
- if (plugin->settings->cleanup)
- plugin->settings->cleanup();
- }
- }
-}
+ gint types[] = {PLUGIN_TYPE_TRANSPORT, PLUGIN_TYPE_PLAYLIST,
+ PLUGIN_TYPE_INPUT, PLUGIN_TYPE_EFFECT, PLUGIN_TYPE_VIS, PLUGIN_TYPE_GENERAL};
+ const gchar * names[] = {N_("Transport"), N_("Playlist"), N_("Input"),
+ N_("Effect"), N_("Visualization"), N_("General")};
-static void
-destroy_plugin_pages(void)
-{
- destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_INPUT));
- destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_GENERAL));
- destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_VIS));
- destroy_plugin_page(plugin_get_list(PLUGIN_TYPE_EFFECT));
+ for (gint i = 0; i < G_N_ELEMENTS (types); i ++)
+ gtk_notebook_append_page ((GtkNotebook *) notebook, plugin_view_new
+ (types[i]), gtk_label_new (_(names[i])));
}
static gboolean
prefswin_destroy(GtkWidget *window, GdkEvent *event, gpointer data)
{
- destroy_plugin_pages();
prefswin = NULL;
category_notebook = NULL;
gtk_widget_destroy(filepopup_settings);
@@ -2522,29 +1806,6 @@ prefswin_destroy(GtkWidget *window, GdkEvent *event, gpointer data)
return TRUE;
}
-static void
-create_plugin_page(GList *list)
-{
- GList *iter;
-
- MOWGLI_ITER_FOREACH(iter, list)
- {
- Plugin *plugin = PLUGIN(iter->data);
- if (plugin->settings && plugin->settings->type == PREFERENCES_PAGE) {
- create_plugin_preferences_page(plugin->settings);
- }
- }
-}
-
-static void
-create_plugin_pages(void)
-{
- create_plugin_page(plugin_get_list(PLUGIN_TYPE_INPUT));
- create_plugin_page(plugin_get_list(PLUGIN_TYPE_GENERAL));
- create_plugin_page(plugin_get_list(PLUGIN_TYPE_VIS));
- create_plugin_page(plugin_get_list(PLUGIN_TYPE_EFFECT));
-}
-
/* GtkWidget * * create_prefs_window (void) */
void * * create_prefs_window (void)
{
@@ -2600,10 +1861,8 @@ void * * create_prefs_window (void)
create_audio_category();
create_replay_gain_category();
create_connectivity_category();
- create_playback_category();
create_playlist_category();
create_plugin_category();
- create_plugin_pages();
hseparator1 = gtk_hseparator_new ();
gtk_box_pack_start (GTK_BOX (vbox), hseparator1, FALSE, FALSE, 6);
@@ -2641,7 +1900,7 @@ void * * create_prefs_window (void)
NULL);
g_signal_connect_swapped(G_OBJECT(close), "clicked",
G_CALLBACK(prefswin_destroy),
- GTK_OBJECT (prefswin));
+ prefswin);
/* create category view */
on_category_treeview_realize ((GtkTreeView *) category_treeview,
@@ -2667,42 +1926,6 @@ destroy_prefs_window(void)
}
void
-create_plugin_preferences_page(PluginPreferences *settings)
-{
- g_return_if_fail(settings->type == PREFERENCES_PAGE);
-
- if (settings->data != NULL)
- return;
-
- if (settings->init)
- settings->init();
-
- GtkWidget *vbox;
- vbox = gtk_vbox_new(FALSE, 5);
-
- create_widgets(GTK_BOX(vbox), settings->prefs, settings->n_prefs);
- gtk_widget_show_all(vbox);
- prefswin_page_new(vbox, settings->title, settings->imgurl);
-
- settings->data = (gpointer) vbox;
-}
-
-void
-destroy_plugin_preferences_page(PluginPreferences *settings)
-{
- if (settings->data) {
- if (settings->apply)
- settings->apply();
-
- prefswin_page_destroy(GTK_WIDGET(settings->data));
- settings->data = NULL;
-
- if (settings->cleanup)
- settings->cleanup();
- }
-}
-
-void
show_prefs_window(void)
{
gtk_window_present(GTK_WINDOW(prefswin)); /* show or raise prefs window */
@@ -2853,7 +2076,7 @@ static void sw_volume_toggled (void)
vol[1] = cfg.sw_volume_right;
}
else
- input_get_volume (& vol[0], & vol[1]);
+ playback_get_volume (& vol[0], & vol[1]);
hook_call ("volume set", vol);
}
diff --git a/src/audacious/ui_preferences.h b/src/audacious/ui_preferences.h
index 38fd677..c41a62f 100644
--- a/src/audacious/ui_preferences.h
+++ b/src/audacious/ui_preferences.h
@@ -21,6 +21,9 @@
#define AUDACIOUS_UI_PREFERENCES_H
#include <glib.h>
+#include <gtk/gtk.h>
+
+#include "preferences.h"
/* GtkWidget * * create_prefs_window (void); */
void * * create_prefs_window (void);
@@ -34,4 +37,10 @@ gint prefswin_page_new (void * container, const gchar * name, const gchar *
imgurl);
void prefswin_page_destroy(GtkWidget *container);
+void plugin_preferences_show (PluginPreferences * p);
+void plugin_preferences_cleanup (PluginPreferences * p);
+
+/* plugin-view.c */
+GtkWidget * plugin_view_new (gint type);
+
#endif /* AUDACIOUS_UI_PREFERENCES_H */
diff --git a/src/audacious/util.c b/src/audacious/util.c
index 750dfd1..2c2445b 100644
--- a/src/audacious/util.c
+++ b/src/audacious/util.c
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2008 Audacious development team
+ * Copyright (C) 2005-2011 Audacious development team
*
* Based on BMP:
* Copyright (C) 2003-2004 BMP development team.
@@ -23,11 +23,17 @@
* Audacious or using our public API to be a derived work.
*/
+#include <limits.h>
+#include <unistd.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-
#include <glib.h>
#include <stdlib.h>
#include <string.h>
@@ -42,6 +48,7 @@
#endif
#include <libaudcore/audstrings.h>
+#include <libaudcore/stringpool.h>
#include "audconfig.h"
#include "debug.h"
@@ -106,7 +113,6 @@ util_get_localdir(void)
gchar * construct_uri (const gchar * string, const gchar * playlist_name)
{
gchar *filename = g_strdup(string);
- gchar *tmp, *path;
gchar *uri = NULL;
/* try to translate dos path */
@@ -118,28 +124,20 @@ gchar * construct_uri (const gchar * string, const gchar * playlist_name)
uri = g_filename_to_uri(filename, NULL, NULL);
if(!uri)
uri = g_strdup(filename);
- g_free(filename);
}
- // case 2: filename is not raw full path nor uri, playlist path is full path
- // make full path by replacing last part of playlist path with filename. (using g_build_filename)
- else if (playlist_name[0] == '/' || strstr(playlist_name, "://")) {
- path = g_filename_from_uri(playlist_name, NULL, NULL);
- if (!path)
- path = g_strdup(playlist_name);
- tmp = strrchr(path, '/'); *tmp = '\0';
- tmp = g_build_filename(path, filename, NULL);
- g_free(path); g_free(filename);
- uri = g_filename_to_uri(tmp, NULL, NULL);
- g_free(tmp);
- }
- // case 3: filename is not raw full path nor uri, playlist path is not full path
- // just abort.
- else {
- g_free(filename);
- uri = NULL;
+ // case 2: filename is not raw full path nor uri
+ // make full path by replacing last part of playlist path with filename.
+ else
+ {
+ const gchar * fslash = strrchr (filename, '/');
+ const gchar * pslash = strrchr (playlist_name, '/');
+
+ if (pslash)
+ uri = g_strdup_printf ("%.*s/%s", (gint) (pslash - playlist_name),
+ playlist_name, fslash ? fslash + 1 : filename);
}
- AUDDBG("uri=%s\n", uri);
+ g_free (filename);
return uri;
}
@@ -164,6 +162,28 @@ make_directory(const gchar * path, mode_t mode)
g_strerror(errno));
}
+gchar * get_path_to_self (void)
+{
+ gchar buf[PATH_MAX];
+ gint len;
+
+#ifdef _WIN32
+ if (! (len = GetModuleFileName (NULL, buf, sizeof buf)) || len == sizeof buf)
+ {
+ fprintf (stderr, "GetModuleFileName failed.\n");
+ return NULL;
+ }
+#else
+ if ((len = readlink ("/proc/self/exe", buf, sizeof buf)) < 0)
+ {
+ fprintf (stderr, "Cannot access /proc/self/exe: %s.\n", strerror (errno));
+ return NULL;
+ }
+#endif
+
+ return g_strndup (buf, len);
+}
+
#define URL_HISTORY_MAX_SIZE 30
void
@@ -181,24 +201,186 @@ util_add_url_history_entry(const gchar * url)
}
}
-static gboolean plugin_list_func (PluginHandle * plugin, GList * * list)
+/* Strips various common top-level folders from a file name (not URI). The
+ * string passed will not be modified, but the string returned will share the
+ * same memory. Examples:
+ * "/home/john/folder/file.mp3" -> "folder/file.mp3"
+ * "/folder/file.mp3" -> "folder/file.mp3"
+ * "C:\Users\John\folder\file.mp3" -> "folder\file.mp3"
+ * "E:\folder\file.mp3" -> "folder\file.mp3" */
+
+static gchar * skip_top_folders (gchar * name)
{
- gpointer p_hdr = plugin_get_header(plugin);
- g_return_val_if_fail(p_hdr != NULL, TRUE);
- *list = g_list_prepend (*list, p_hdr);
- return TRUE;
+ const gchar * home = getenv ("HOME");
+ if (! home)
+ goto NO_HOME;
+
+ gint len = strlen (home);
+ if (len > 0 && home[len - 1] == G_DIR_SEPARATOR)
+ len --;
+
+#ifdef _WIN32
+ if (! strncasecmp (name, home, len) && name[len] == '\\')
+#else
+ if (! strncmp (name, home, len) && name[len] == '/')
+#endif
+ return name + len + 1;
+
+NO_HOME:
+#ifdef _WIN32
+ return (name[0] && name[1] == ':' && name[2] == '\\') ? name + 3 : name;
+#else
+ return (name[0] == '/') ? name + 1 : name;
+#endif
}
-/* Deprecated: This loads all the plugins at once, causing a major slowdown. */
-GList * plugin_get_list (gint type)
+/* Divides a file name (not URI) into the base name, the lowest folder, and the
+ * second lowest folder. The string passed will be modified, and the strings
+ * returned will use the same memory. May return NULL for <first> and <second>.
+ * Examples:
+ * "a/b/c/d/e.mp3" -> "e", "d", "c"
+ * "d/e.mp3" -> "e", "d", NULL
+ * "e.mp3" -> "e", NULL, NULL */
+
+static void split_filename (gchar * name, gchar * * base, gchar * * first,
+ gchar * * second)
{
- static GList *list[PLUGIN_TYPES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
+ * first = * second = NULL;
- if (list[type] == NULL)
+ gchar * c;
+
+ if ((c = strrchr (name, G_DIR_SEPARATOR)))
{
- plugin_for_each (type, (PluginForEachFunc) plugin_list_func, & list[type]);
- list[type] = g_list_reverse (list[type]);
+ * base = c + 1;
+ * c = 0;
}
+ else
+ {
+ * base = name;
+ goto DONE;
+ }
+
+ if ((c = strrchr (name, G_DIR_SEPARATOR)))
+ {
+ * first = c + 1;
+ * c = 0;
+ }
+ else
+ {
+ * first = name;
+ goto DONE;
+ }
+
+ if ((c = strrchr (name, G_DIR_SEPARATOR)))
+ * second = c + 1;
+ else
+ * second = name;
+
+DONE:
+ if ((c = strrchr (* base, '.')))
+ * c = 0;
+}
+
+/* Separates the domain name from an internet URI. The string passed will be
+ * modified, and the string returned will share the same memory. May return
+ * NULL. Examples:
+ * "http://some.domain.org/folder/file.mp3" -> "some.domain.org"
+ * "http://some.stream.fm:8000" -> "some.stream.fm" */
+
+static gchar * stream_name (gchar * name)
+{
+ if (! strncmp (name, "http://", 7))
+ name += 7;
+ else if (! strncmp (name, "https://", 8))
+ name += 8;
+ else if (! strncmp (name, "mms://", 6))
+ name += 6;
+ else
+ return NULL;
+
+ gchar * c;
+
+ if ((c = strchr (name, '/')))
+ * c = 0;
+ if ((c = strchr (name, ':')))
+ * c = 0;
+ if ((c = strchr (name, '?')))
+ * c = 0;
+
+ return name;
+}
+
+/* Derives best guesses of title, artist, and album from a file name (URI) and
+ * tuple. The returned strings are stringpooled or NULL. */
+
+void describe_song (const gchar * name, const Tuple * tuple, gchar * * _title,
+ gchar * * _artist, gchar * * _album)
+{
+ /* Common folder names to skip */
+ static const gchar * const skip[] = {"music"};
+
+ const gchar * title = tuple_get_string (tuple, FIELD_TITLE, NULL);
+ const gchar * artist = tuple_get_string (tuple, FIELD_ARTIST, NULL);
+ const gchar * album = tuple_get_string (tuple, FIELD_ALBUM, NULL);
+
+ if (title && ! title[0])
+ title = NULL;
+ if (artist && ! artist[0])
+ artist = NULL;
+ if (album && ! album[0])
+ album = NULL;
+
+ gchar * copy = NULL;
+
+ if (title && artist && album)
+ goto DONE;
+
+ copy = uri_to_display (name);
+
+ if (! strncmp (name, "file://", 7))
+ {
+ gchar * base, * first, * second;
+ split_filename (skip_top_folders (copy), & base, & first,
+ & second);
+
+ if (! title)
+ title = base;
+
+ for (gint i = 0; i < G_N_ELEMENTS (skip); i ++)
+ {
+ if (first && ! strcasecmp (first, skip[i]))
+ first = NULL;
+ if (second && ! strcasecmp (second, skip[i]))
+ second = NULL;
+ }
+
+ if (first)
+ {
+ if (second && ! artist && ! album)
+ {
+ artist = second;
+ album = first;
+ }
+ else if (! artist)
+ artist = first;
+ else if (! album)
+ album = first;
+ }
+ }
+ else
+ {
+ if (! title)
+ title = stream_name (copy);
+ else if (! artist)
+ artist = stream_name (copy);
+ else if (! album)
+ album = stream_name (copy);
+ }
+
+DONE:
+ * _title = title ? stringpool_get ((gchar *) title, FALSE) : NULL;
+ * _artist = artist ? stringpool_get ((gchar *) artist, FALSE) : NULL;
+ * _album = album ? stringpool_get ((gchar *) album, FALSE) : NULL;
- return list[type];
+ g_free (copy);
}
diff --git a/src/audacious/util.h b/src/audacious/util.h
index 89a54f2..f5edf24 100644
--- a/src/audacious/util.h
+++ b/src/audacious/util.h
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2008 Audacious development team
+ * Copyright (C) 2005-2011 Audacious development team
*
* Based on BMP:
* Copyright (C) 2003-2004 BMP development team
@@ -39,6 +39,9 @@ gboolean dir_foreach(const gchar * path, DirForeachFunc function,
gint file_get_mtime (const gchar * filename);
void make_directory(const gchar * path, mode_t mode);
-GList * plugin_get_list (gint type);
+gchar * get_path_to_self (void);
+
+void describe_song (const gchar * filename, const Tuple * tuple,
+ gchar * * title, gchar * * artist, gchar * * album);
#endif /* AUDACIOUS_UTIL_H */
diff --git a/src/audacious/vis_runner.c b/src/audacious/vis_runner.c
index 8e3505a..a82e5f7 100644
--- a/src/audacious/vis_runner.c
+++ b/src/audacious/vis_runner.c
@@ -22,7 +22,7 @@
#include <glib.h>
#include <libaudcore/hook.h>
-#include "compatibility.h"
+#include "glib-compat.h"
#include "misc.h"
#include "output.h"
#include "vis_runner.h"
@@ -51,8 +51,7 @@ static gboolean send_audio (void * unused)
return FALSE;
}
- /* We need raw time, not changed for effects and gapless playback. */
- gint outputted = current_output_plugin->output_time ();
+ gint outputted = get_raw_output_time ();
VisNode * vis_node = NULL;
VisNode * next;
@@ -95,7 +94,26 @@ static gboolean send_clear (void * unused)
return FALSE;
}
-static void flush_locked (void)
+static gboolean locked = FALSE;
+
+void vis_runner_lock (void)
+{
+ G_LOCK (mutex);
+ locked = TRUE;
+}
+
+void vis_runner_unlock (void)
+{
+ locked = FALSE;
+ G_UNLOCK (mutex);
+}
+
+gboolean vis_runner_locked (void)
+{
+ return locked;
+}
+
+void vis_runner_flush (void)
{
g_free (current_node);
current_node = NULL;
@@ -107,8 +125,6 @@ static void flush_locked (void)
void vis_runner_start_stop (gboolean new_playing, gboolean new_paused)
{
- G_LOCK (mutex);
-
playing = new_playing;
paused = new_paused;
active = playing && hooks;
@@ -126,20 +142,16 @@ void vis_runner_start_stop (gboolean new_playing, gboolean new_paused)
}
if (! active)
- flush_locked ();
+ vis_runner_flush ();
else if (! paused)
send_source = g_timeout_add (INTERVAL, send_audio, NULL);
-
- G_UNLOCK (mutex);
}
void vis_runner_pass_audio (gint time, gfloat * data, gint samples, gint
channels, gint rate)
{
- G_LOCK (mutex);
-
if (! active)
- goto UNLOCK;
+ return;
if (current_node && current_node->nch != MIN (channels, 2))
{
@@ -196,9 +208,6 @@ void vis_runner_pass_audio (gint time, gfloat * data, gint samples, gint
g_queue_push_tail (& vis_list, current_node);
current_node = NULL;
}
-
-UNLOCK:
- G_UNLOCK (mutex);
}
static void time_offset_cb (VisNode * vis_node, void * offset)
@@ -208,21 +217,10 @@ static void time_offset_cb (VisNode * vis_node, void * offset)
void vis_runner_time_offset (gint offset)
{
- G_LOCK (mutex);
-
if (current_node)
current_node->time += offset;
g_queue_foreach (& vis_list, (GFunc) time_offset_cb, GINT_TO_POINTER (offset));
-
- G_UNLOCK (mutex);
-}
-
-void vis_runner_flush (void)
-{
- G_LOCK (mutex);
- flush_locked ();
- G_UNLOCK (mutex);
}
void vis_runner_add_hook (VisHookFunc func, void * user)
@@ -234,8 +232,8 @@ void vis_runner_add_hook (VisHookFunc func, void * user)
item->user = user;
hooks = g_list_prepend (hooks, item);
- G_UNLOCK (mutex);
vis_runner_start_stop (playing, paused);
+ G_UNLOCK (mutex);
}
void vis_runner_remove_hook (VisHookFunc func)
@@ -252,6 +250,6 @@ void vis_runner_remove_hook (VisHookFunc func)
}
}
- G_UNLOCK (mutex);
vis_runner_start_stop (playing, paused);
+ G_UNLOCK (mutex);
}
diff --git a/src/audacious/vis_runner.h b/src/audacious/vis_runner.h
index 7599f25..30d4e58 100644
--- a/src/audacious/vis_runner.h
+++ b/src/audacious/vis_runner.h
@@ -22,6 +22,14 @@
#ifndef AUD_VIS_RUNNER_H
#define AUD_VIS_RUNNER_H
+/* When the decoder thread wants to send data to the vis runner, it must block
+ * the vis timeout before blocking output functions; otherwise, the vis timeout
+ * will hang up waiting for those output functions to be unblocked while the
+ * decoder thread hangs up waiting for the vis timeout to finish. */
+void vis_runner_lock (void);
+void vis_runner_unlock (void);
+gboolean vis_runner_locked (void);
+
void vis_runner_start_stop (gboolean playing, gboolean paused);
void vis_runner_pass_audio (gint time, gfloat * data, gint samples, gint
channels, gint rate);
diff --git a/src/audacious/visualization.c b/src/audacious/visualization.c
index 30a821b..9310e8b 100644
--- a/src/audacious/visualization.c
+++ b/src/audacious/visualization.c
@@ -37,6 +37,7 @@
#include "playback.h"
#include "plugin.h"
#include "plugins.h"
+#include "ui_preferences.h"
#include "visualization.h"
typedef struct {
@@ -46,6 +47,7 @@ typedef struct {
gboolean started;
} LoadedVis;
+static gint running = FALSE;
static GList * loaded_vis_plugins = NULL;
void calc_stereo_pcm (VisPCMData dest, const VisPCMData src, gint nch)
@@ -211,9 +213,6 @@ static void vis_load (PluginHandle * plugin)
VisPlugin * header = plugin_get_header (plugin);
g_return_if_fail (header != NULL);
- if (header->init != NULL)
- header->init ();
-
LoadedVis * vis = g_slice_new (LoadedVis);
vis->plugin = plugin;
vis->header = header;
@@ -261,9 +260,6 @@ static void vis_unload (PluginHandle * plugin)
g_return_if_fail (vis->widget == NULL); /* not destroyed? */
}
- if (vis->header->cleanup != NULL)
- vis->header->cleanup ();
-
g_slice_free (LoadedVis, vis);
}
@@ -275,6 +271,9 @@ static gboolean vis_init_cb (PluginHandle * plugin)
void vis_init (void)
{
+ g_return_if_fail (! running);
+ running = TRUE;
+
plugin_for_enabled (PLUGIN_TYPE_VIS, (PluginForEachFunc) vis_init_cb, NULL);
hook_associate ("playback begin", (HookFunction) vis_start_all, NULL);
@@ -288,18 +287,53 @@ static void vis_cleanup_cb (LoadedVis * vis)
void vis_cleanup (void)
{
+ g_return_if_fail (running);
+ running = FALSE;
+
hook_dissociate ("playback begin", (HookFunction) vis_start_all);
hook_dissociate ("playback stop", (HookFunction) vis_stop_all);
g_list_foreach (loaded_vis_plugins, (GFunc) vis_cleanup_cb, NULL);
}
-void vis_plugin_enable (PluginHandle * plugin, gboolean enable)
+gboolean vis_plugin_start (PluginHandle * plugin)
{
- plugin_set_enabled (plugin, enable);
+ VisPlugin * vp = plugin_get_header (plugin);
+ g_return_val_if_fail (vp != NULL, FALSE);
+
+ if (vp->init != NULL && ! vp->init ())
+ return FALSE;
- if (enable)
+ if (running)
vis_load (plugin);
- else
+
+ return TRUE;
+}
+
+void vis_plugin_stop (PluginHandle * plugin)
+{
+ VisPlugin * vp = plugin_get_header (plugin);
+ g_return_if_fail (vp != NULL);
+
+ if (running)
vis_unload (plugin);
+
+ if (vp->settings != NULL)
+ plugin_preferences_cleanup (vp->settings);
+ if (vp->cleanup != NULL)
+ vp->cleanup ();
+}
+
+PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget)
+{
+ g_return_val_if_fail (widget, NULL);
+
+ for (GList * node = loaded_vis_plugins; node; node = node->next)
+ {
+ LoadedVis * vis = node->data;
+ if (vis->widget == widget)
+ return vis->plugin;
+ }
+
+ return NULL;
}
diff --git a/src/audacious/visualization.h b/src/audacious/visualization.h
index c4ff618..f84cb10 100644
--- a/src/audacious/visualization.h
+++ b/src/audacious/visualization.h
@@ -22,7 +22,16 @@
#ifndef AUDACIOUS_VISUALIZATION_H
#define AUDACIOUS_VISUALIZATION_H
+#include <glib.h>
+
+#include "plugins.h"
+
void vis_init (void);
void vis_cleanup (void);
+gboolean vis_plugin_start (PluginHandle * plugin);
+void vis_plugin_stop (PluginHandle * plugin);
+
+PluginHandle * vis_plugin_by_widget (/* GtkWidget * */ void * widget);
+
#endif
diff --git a/src/audtool/Makefile b/src/audtool/Makefile
index df743a1..dbc3c94 100644
--- a/src/audtool/Makefile
+++ b/src/audtool/Makefile
@@ -1,4 +1,4 @@
-PROG = audtool2
+PROG = audtool
SRCS = main.c \
handlers_general.c \
handlers_playback.c \
@@ -25,11 +25,3 @@ LIBS += ${DBUS_LIBS} \
${GTK_LIBS} \
${MOWGLI_LIBS} \
${LIBMCS_LIBS}
-
-install-extra:
- if test -h "${DESTDIR}${bindir}/audtool" ; then ${RM} "${DESTDIR}${bindir}/audtool" ; fi
- mkdir -p "${DESTDIR}${bindir}"
- ${LN_S} audtool2 "${DESTDIR}${bindir}/audtool"
-
-uninstall-extra:
- if test -h "${DESTDIR}${bindir}/audtool" ; then ${RM} "${DESTDIR}${bindir}/audtool" ; fi
diff --git a/src/audtool/main.c b/src/audtool/main.c
index 1666d41..18612fe 100644
--- a/src/audtool/main.c
+++ b/src/audtool/main.c
@@ -1,5 +1,5 @@
/*
- * Audtool2
+ * Audtool
* Copyright (c) 2007 Audacious development team
*
* Redistribution and use in source and binary forms, with or without
@@ -84,7 +84,7 @@ struct commandhandler handlers[] = {
{"playqueue-add", playqueue_add, "adds a song to the playqueue", 1},
{"playqueue-remove", playqueue_remove, "removes a song from the playqueue", 1},
{"playqueue-is-queued", playqueue_is_queued, "returns OK if a song is queued", 1},
- {"playqueue-get-queue-position", playqueue_get_queue_position, "returns the playqueue position of a song in the given poition in the playlist", 1},
+ {"playqueue-get-queue-position", playqueue_get_queue_position, "returns the playqueue position of a song in the given position in the playlist", 1},
{"playqueue-get-list-position", playqueue_get_list_position, "returns the playlist position of a song in the given position in the playqueue", 1},
{"playqueue-length", playqueue_length, "returns the length of the playqueue", 0},
{"playqueue-display", playqueue_display, "returns a list of currently-queued songs", 0},
@@ -190,7 +190,7 @@ main(gint argc, gchar **argv)
if (argc < 2)
mowgli_error_context_display_with_error (e, ":\n * ", "not enough "
- "parameters, use \'audtool2 help\' for more information.");
+ "parameters, use \'audtool help\' for more information.");
for (j = 1; j < argc; j++)
{
@@ -212,7 +212,7 @@ main(gint argc, gchar **argv)
if (k == 0)
mowgli_error_context_display_with_error (e, ":\n * ", g_strdup_printf
- ("Unknown command '%s' encountered, use \'audtool2 help\' for a "
+ ("Unknown command '%s' encountered, use \'audtool help\' for a "
"command list.", argv[1]));
audtool_disconnect();
diff --git a/src/libaudclient/Makefile b/src/libaudclient/Makefile
index 0ce223b..e5c74da 100644
--- a/src/libaudclient/Makefile
+++ b/src/libaudclient/Makefile
@@ -12,7 +12,7 @@ include ../../extra.mk
pre-depend:
cd ../audacious; ${MAKE} ${MFLAGS} dbus-client-bindings.h
-CPPFLAGS = ${LIB_CPPFLAGS} ${CFLAGS} -D_AUDACIOUS_CORE -I.. -I../..
+CPPFLAGS = ${CFLAGS} -D_AUDACIOUS_CORE -I.. -I../..
CFLAGS += ${LIB_CFLAGS} \
${GLIB_CFLAGS} \
${MOWGLI_CFLAGS} \
diff --git a/src/libaudcore/Makefile b/src/libaudcore/Makefile
index 2ddd5fd..39815f9 100644
--- a/src/libaudcore/Makefile
+++ b/src/libaudcore/Makefile
@@ -16,8 +16,7 @@ SRCS = audio.c \
vfs_buffer.c \
vfs_buffered_file.c \
vfs_common.c \
- md5.c \
- log.c
+ md5.c
INCLUDES = audio.h \
audstrings.h \
@@ -30,17 +29,16 @@ INCLUDES = audio.h \
tuple_formatter.h \
vfs.h \
vfs_async.h \
- vfs_buffer.h \
- vfs_buffered_file.h \
- md5.h \
- log.h
+ vfs_buffer.h \
+ vfs_buffered_file.h \
+ md5.h
include ../../buildsys.mk
include ../../extra.mk
includesubdir = libaudcore
-CPPFLAGS += -DHAVE_CONFIG_H ${LIB_CPPFLAGS} ${CFLAGS} -I.. -I../..
+CPPFLAGS += -DHAVE_CONFIG_H ${CFLAGS} -I.. -I../..
CFLAGS += ${LIB_CFLAGS} ${GLIB_CFLAGS} ${MOWGLI_CFLAGS}
LIBS += ${GLIB_LIBS} ${MOWGLI_LIBS}
diff --git a/src/libaudcore/audstrings.c b/src/libaudcore/audstrings.c
index 71f99af..b3ef5ff 100644
--- a/src/libaudcore/audstrings.c
+++ b/src/libaudcore/audstrings.c
@@ -36,39 +36,6 @@
#include <ctype.h>
/**
- * Escapes characters that are special to the shell inside double quotes.
- *
- * @param string String to be escaped.
- * @return Given string with special characters escaped. Must be freed with g_free().
- */
-gchar *
-escape_shell_chars(const gchar * string)
-{
- const gchar *special = "$`\"\\"; /* Characters to escape */
- const gchar *in = string;
- gchar *out, *escaped;
- gint num = 0;
-
- while (*in != '\0')
- if (strchr(special, *in++))
- num++;
-
- escaped = g_malloc(strlen(string) + num + 1);
-
- in = string;
- out = escaped;
-
- while (*in != '\0') {
- if (strchr(special, *in))
- *out++ = '\\';
- *out++ = *in++;
- }
- *out = '\0';
-
- return escaped;
-}
-
-/**
* Performs in place replacement of Windows-style drive letter with '/' (slash).
*
* @param str String to be manipulated.
@@ -119,10 +86,10 @@ str_has_prefix_nocase(const gchar * str, const gchar * prefix)
return (str != NULL && (strncasecmp(str, prefix, strlen(prefix)) == 0));
}
-gboolean
-str_has_suffix_nocase(const gchar * str, const gchar * suffix)
+gboolean str_has_suffix_nocase (const gchar * str, const gchar * suffix)
{
- return (str != NULL && strcasecmp(str + strlen(str) - strlen(suffix), suffix) == 0);
+ return (str && strlen (str) >= strlen (suffix) && ! strcasecmp (str + strlen
+ (str) - strlen (suffix), suffix));
}
gboolean
@@ -140,24 +107,15 @@ str_has_suffixes_nocase(const gchar * str, gchar * const *suffixes)
return FALSE;
}
-gchar *
-str_to_utf8_fallback(const gchar * str)
-{
- gchar *out_str, *convert_str, *chr;
-
- if (!str)
- return NULL;
-
- convert_str = g_strdup(str);
- for (chr = convert_str; *chr; chr++) {
- if (*chr & 0x80)
- *chr = '?';
- }
-
- out_str = g_strconcat(convert_str, _(" (invalid UTF-8)"), NULL);
- g_free(convert_str);
+static gchar * (* str_to_utf8_impl) (const gchar *) = NULL;
+static gchar * (* str_to_utf8_full_impl) (const gchar *, gssize, gsize *,
+ gsize *, GError * *) = NULL;
- return out_str;
+void str_set_utf8_impl (gchar * (* stu_impl) (const gchar *),
+ gchar * (* stuf_impl) (const gchar *, gssize, gsize *, gsize *, GError * *))
+{
+ str_to_utf8_impl = stu_impl;
+ str_to_utf8_full_impl = stuf_impl;
}
/**
@@ -166,11 +124,19 @@ str_to_utf8_fallback(const gchar * str)
* @param str Local filename/path to convert.
* @return String in UTF-8 encoding. Must be freed with g_free().
*/
-gchar *(*str_to_utf8)(const gchar * str) = str_to_utf8_fallback;
-gchar *(*chardet_to_utf8)(const gchar *str, gssize len,
- gsize *arg_bytes_read, gsize *arg_bytes_write,
- GError **arg_error) = NULL;
+gchar * str_to_utf8 (const gchar * str)
+{
+ g_return_val_if_fail (str_to_utf8_impl, NULL);
+ return str_to_utf8_impl (str);
+}
+
+gchar * str_to_utf8_full (const gchar * str, gssize len, gsize * bytes_read,
+ gsize * bytes_written, GError * * err)
+{
+ g_return_val_if_fail (str_to_utf8_full_impl, NULL);
+ return str_to_utf8_full_impl (str, len, bytes_read, bytes_written, err);
+}
#ifdef HAVE_EXECINFO_H
# include <execinfo.h>
@@ -230,31 +196,6 @@ str_skip_chars(const gchar * str, const gchar * chars)
return str;
}
-const void * memfind (const void * mem, gint size, const void * token, gint
- length)
-{
- if (! length)
- return mem;
-
- size -= length - 1;
-
- while (size > 0)
- {
- const void * maybe = memchr (mem, * (guchar *) token, size);
-
- if (maybe == NULL)
- return NULL;
-
- if (! memcmp (maybe, token, length))
- return maybe;
-
- size -= (guchar *) maybe + 1 - (guchar *) mem;
- mem = (guchar *) maybe + 1;
- }
-
- return NULL;
-}
-
gchar *
convert_dos_path(gchar * path)
{
@@ -372,12 +313,18 @@ void string_decode_percent (gchar * s)
string_decode_percent_2 (s, s);
}
-/* we encode any character except the "unreserved" characters of RFC 3986 and
- * (optionally) the forward slash */
+/* We encode any character except the "unreserved" characters of RFC 3986 and
+ * (optionally) the forward slash. On Windows, we also (optionally) do not
+ * encode the colon. */
static gboolean is_legal_char (gchar c, gboolean is_filename)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <=
- '9') || (strchr ("-_.~", c) != NULL) || (is_filename && c == '/');
+ '9') || (strchr ("-_.~", c) != NULL) ||
+#ifdef _WIN32
+ (is_filename && strchr ("/:", c) != NULL);
+#else
+ (is_filename && c == '/');
+#endif
}
static gchar make_hex_digit (gint i)
@@ -490,30 +437,91 @@ void uri_check_utf8 (gchar * * uri, gboolean warn)
}
/* Like g_filename_to_uri, but converts the filename from the system locale to
- * UTF-8 before percent-encoding. */
+ * UTF-8 before percent-encoding. On Windows, replaces '\' with '/' and adds a
+ * leading '/'. */
gchar * filename_to_uri (const gchar * name)
{
gchar * utf8 = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
+#ifdef _WIN32
+ string_replace_char (utf8, '\\', '/');
+#endif
gchar * enc = string_encode_percent (utf8 ? utf8 : name, TRUE);
g_free (utf8);
+#ifdef _WIN32
+ gchar * uri = g_strdup_printf ("file:///%s", enc);
+#else
gchar * uri = g_strdup_printf ("file://%s", enc);
+#endif
g_free (enc);
return uri;
}
/* Like g_filename_from_uri, but converts the filename from UTF-8 to the system
- * locale after percent-decoding. */
+ * locale after percent-decoding. On Windows, strips the leading '/' and
+ * replaces '/' with '\'. */
gchar * uri_to_filename (const gchar * uri)
{
+#ifdef _WIN32
+ g_return_val_if_fail (! strncmp (uri, "file:///", 8), NULL);
+ gchar buf[strlen (uri + 8) + 1];
+ string_decode_percent_2 (uri + 8, buf);
+#else
g_return_val_if_fail (! strncmp (uri, "file://", 7), NULL);
gchar buf[strlen (uri + 7) + 1];
string_decode_percent_2 (uri + 7, buf);
+#endif
+#ifdef _WIN32
+ string_replace_char (buf, '/', '\\');
+#endif
gchar * name = g_locale_from_utf8 (buf, -1, NULL, NULL, NULL);
return name ? name : g_strdup (buf);
}
+/* Formats a URI for human-readable display. Percent-decodes and converts to
+ * UTF-8 (more aggressively than uri_to_utf8). For file:// URI's, converts to
+ * filename format (but in UTF-8). */
+
+gchar * uri_to_display (const gchar * uri)
+{
+ gchar buf[strlen (uri) + 1];
+
+#ifdef _WIN32
+ if (! strncmp (uri, "file:///", 8))
+ {
+ string_decode_percent_2 (uri + 8, buf);
+ string_replace_char (buf, '/', '\\');
+ }
+#else
+ if (! strncmp (uri, "file://", 7))
+ string_decode_percent_2 (uri + 7, buf);
+#endif
+ else
+ string_decode_percent_2 (uri, buf);
+
+ return str_to_utf8 (buf);
+}
+
+gchar * uri_get_extension (const gchar * uri)
+{
+ const gchar * slash = strrchr (uri, '/');
+ if (! slash)
+ return NULL;
+
+ gchar * lower = g_ascii_strdown (slash + 1, -1);
+
+ gchar * qmark = strchr (lower, '?');
+ if (qmark)
+ * qmark = 0;
+
+ gchar * dot = strrchr (lower, '.');
+ gchar * ext = dot ? g_strdup (dot + 1) : NULL;
+
+ g_free (lower);
+ return ext;
+}
+
void string_cut_extension(gchar *string)
{
gchar *period = strrchr(string, '.');
@@ -616,3 +624,71 @@ gint string_compare_encoded (const gchar * ap, const gchar * bp)
return 0;
}
+
+const void * memfind (const void * mem, gint size, const void * token, gint
+ length)
+{
+ if (! length)
+ return mem;
+
+ size -= length - 1;
+
+ while (size > 0)
+ {
+ const void * maybe = memchr (mem, * (guchar *) token, size);
+
+ if (maybe == NULL)
+ return NULL;
+
+ if (! memcmp (maybe, token, length))
+ return maybe;
+
+ size -= (guchar *) maybe + 1 - (guchar *) mem;
+ mem = (guchar *) maybe + 1;
+ }
+
+ return NULL;
+}
+
+gchar *
+str_replace_fragment(gchar *s, gint size, const gchar *old, const gchar *new)
+{
+ gchar *ptr = s;
+ gint left = strlen(s);
+ gint avail = size - (left + 1);
+ gint oldlen = strlen(old);
+ gint newlen = strlen(new);
+ gint diff = newlen - oldlen;
+
+ while (left >= oldlen)
+ {
+ if (strncmp(ptr, old, oldlen))
+ {
+ left--;
+ ptr++;
+ continue;
+ }
+
+ if (diff > avail)
+ break;
+
+ if (diff != 0)
+ memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
+
+ memcpy(ptr, new, newlen);
+ ptr += newlen;
+ left -= oldlen;
+ }
+
+ return s;
+}
+
+void
+string_canonize_case(gchar *str)
+{
+ while (*str)
+ {
+ *str = g_ascii_toupper(*str);
+ str++;
+ }
+}
diff --git a/src/libaudcore/audstrings.h b/src/libaudcore/audstrings.h
index f15e0cf..bc64e97 100644
--- a/src/libaudcore/audstrings.h
+++ b/src/libaudcore/audstrings.h
@@ -31,8 +31,6 @@
G_BEGIN_DECLS
-gchar *escape_shell_chars(const gchar * string);
-
gchar *str_append(gchar * str, const gchar * add_str);
gchar *str_replace(gchar * str, gchar * new_str);
void str_replace_in(gchar ** str, gchar * new_str);
@@ -42,19 +40,17 @@ gboolean str_has_suffix_nocase(const gchar * str, const gchar * suffix);
gboolean str_has_suffixes_nocase(const gchar * str, gchar * const *suffixes);
gchar *str_assert_utf8(const gchar *str);
-extern gchar *(*str_to_utf8)(const gchar * str);
-gchar *str_to_utf8_fallback(const gchar * str);
-extern gchar * (* chardet_to_utf8) (const gchar * string, gssize length, gsize *
- bytes_read, gsize * bytes_written, GError * * error);
+
+void str_set_utf8_impl (gchar * (* stu_impl) (const gchar *),
+ gchar * (* stuf_impl) (const gchar *, gssize, gsize *, gsize *, GError * *));
+gchar * str_to_utf8 (const gchar * str);
+gchar * str_to_utf8_full (const gchar * str, gssize len, gsize * bytes_read,
+ gsize * bytes_written, GError * * err);
const gchar *str_skip_chars(const gchar * str, const gchar * chars);
gchar *convert_dos_path(gchar * text);
-extern gchar *(*chardet_to_utf8)(const gchar *str, gssize len,
- gsize *arg_bytes_read, gsize *arg_bytes_write,
- GError **arg_error);
-
gchar *filename_get_subtune(const gchar * filename, gint * track);
gchar *filename_split_subtune(const gchar * filename, gint * track);
@@ -67,6 +63,9 @@ gchar * uri_to_utf8 (const gchar * uri);
void uri_check_utf8 (gchar * * uri, gboolean warn);
gchar * filename_to_uri (const gchar * filename);
gchar * uri_to_filename (const gchar * uri);
+gchar * uri_to_display (const gchar * uri);
+
+gchar * uri_get_extension (const gchar * uri);
void string_cut_extension(gchar *string);
gint string_compare (const gchar * a, const gchar * b);
@@ -75,6 +74,10 @@ gint string_compare_encoded (const gchar * a, const gchar * b);
const void * memfind (const void * mem, gint size, const void * token, gint
length);
+gchar *str_replace_fragment(gchar *s, gint size, const gchar *old_str, const gchar *new_str);
+
+void string_canonize_case(gchar *string);
+
G_END_DECLS
#endif /* AUDACIOUS_STRINGS_H */
diff --git a/src/libaudcore/index.c b/src/libaudcore/index.c
index 9344e7b..0ee66db 100644
--- a/src/libaudcore/index.c
+++ b/src/libaudcore/index.c
@@ -36,7 +36,7 @@ struct index
struct index * index_new (void)
{
- struct index * index = g_malloc (sizeof (struct index));
+ struct index * index = g_slice_new (struct index);
index->data = NULL;
index->count = 0;
@@ -50,7 +50,7 @@ struct index * index_new (void)
void index_free (struct index * index)
{
g_free (index->data);
- g_free (index);
+ g_slice_free (struct index, index);
}
gint index_count (struct index * index)
@@ -58,6 +58,20 @@ gint index_count (struct index * index)
return index->count;
}
+void index_allocate (struct index * index, gint size)
+{
+ if (size <= index->size)
+ return;
+
+ if (! index->size)
+ index->size = 64;
+
+ while (size > index->size)
+ index->size <<= 1;
+
+ index->data = g_realloc (index->data, sizeof (void *) * index->size);
+}
+
void index_set (struct index * index, gint at, void * value)
{
index->data[at] = value;
@@ -68,27 +82,14 @@ void * index_get (struct index * index, gint at)
return index->data[at];
}
-static void resize_to (struct index * index, gint size)
+static void make_room (struct index * index, gint at, gint count)
{
- if (size < 100)
- size = (size + 9) / 10 * 10;
- else if (size < 1000)
- size = (size + 99) / 100 * 100;
- else
- size = (size + 999) / 1000 * 1000;
+ index_allocate (index, index->count + count);
- if (index->size < size)
- {
- index->data = g_realloc (index->data, sizeof (void *) * size);
- index->size = size;
- }
-}
+ if (at < index->count)
+ memmove (index->data + at + count, index->data + at, sizeof (void *) *
+ (index->count - at));
-static void make_room (struct index * index, gint at, gint count)
-{
- resize_to (index, index->count + count);
- memmove (index->data + at + count, index->data + at, sizeof (void *) *
- (index->count - at));
index->count += count;
}
diff --git a/src/libaudcore/index.h b/src/libaudcore/index.h
index 67b1781..0a3499b 100644
--- a/src/libaudcore/index.h
+++ b/src/libaudcore/index.h
@@ -27,6 +27,7 @@ struct index;
struct index * index_new (void);
void index_free (struct index * index);
gint index_count (struct index * index);
+void index_allocate (struct index * index, gint size);
void index_set (struct index * index, gint at, void * value);
void * index_get (struct index * index, gint at);
void index_insert (struct index * index, gint at, void * value);
diff --git a/src/libaudcore/log.c b/src/libaudcore/log.c
deleted file mode 100644
index 089bfd0..0000000
--- a/src/libaudcore/log.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Logging mechanisms
- * Copyright (c) 2009 Audacious team
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#include "log.h"
-#include <stdio.h>
-#include <string.h>
-
-/** Logfile creation timestamp format */
-#define AUD_LOG_CTIME_FMT "%c"
-
-/** Logfile entry timestamp format */
-#define AUD_LOG_LTIME_FMT "%H:%M:%S"
-
-/**
- * Global log level setting, this determines what is logged in
- * the logfile. Anything "above" this level will not be logged.
- */
-static gint log_level = AUD_LOG_INFO;
-
-/** Global log file handle */
-static FILE *log_file = NULL;
-
-/** Mutex for protecting from threaded access */
-static GMutex *log_mutex = NULL;
-
-/** Hashtable that contains registered thread information */
-static GHashTable *log_thread_hash = NULL;
-
-/** Descriptive names for different log levels */
-const gchar *log_level_names[AUD_LOG_ALL] = {
- "none",
- "FATAL",
- "ERROR",
- "warning",
- "info",
- "DEBUG",
- "DEBUG+",
-};
-
-
-/**
- * Create a time/date string based on given format string.
- * Current adjusted local time is used as timestamp.
- *
- * @param[in] fmt Format for time/date string, as described in 'man strftime'.
- * @return Newly allocated string, must be freed with g_free().
- */
-static gchar *
-aud_log_timestr(const gchar *fmt)
-{
- gchar tmp[256] = "";
- time_t stamp = time(NULL);
- struct tm stamp_tm;
-
- if (stamp >= 0 && localtime_r(&stamp, &stamp_tm) != NULL)
- strftime(tmp, sizeof(tmp), fmt, &stamp_tm);
-
- return g_strdup(tmp);
-}
-
-/**
- * The actual internal function that does the logfile output.
- * Entry is prefixed with timestamp information, log level's name
- * (as defined in #log_level_names), logging context and the message
- * itself. Linefeeds are optional in format string, they are added
- * automatically for compatibility with g_log().
- *
- * @param[in] f File handle to write into.
- * @param[in] ctx Logging context or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] msg Log message string.
- */
-static void
-aud_log_msg(FILE *f, const gchar *ctx, gint level, const gchar *msg)
-{
- gchar *timestamp;
- GThread *thread = g_thread_self();
- gchar *name = (log_thread_hash != NULL) ?
- g_hash_table_lookup(log_thread_hash, thread) : NULL;
-
- timestamp = aud_log_timestr(AUD_LOG_LTIME_FMT);
- fprintf(f, "%s <", timestamp);
- g_free(timestamp);
-
- if (name != NULL)
- {
- if (ctx != NULL)
- fprintf(f, "%s|%s", ctx, name);
- else
- fprintf(f, "%s", name);
- }
- else
- {
- fprintf(f, "%s|%p", ctx != NULL ? ctx : "global", (void *) thread);
- }
-
- fprintf(f, "> [%s]: %s", (level >= 0) ? log_level_names[level] :
- log_level_names[AUD_LOG_INFO], msg);
-
- /* A small hack here to ease transition from g_log() etc. */
- if (msg[strlen(msg) - 1] != '\n')
- fprintf(f, "\n");
-
- fflush(f);
-}
-
-
-/**
- * Varargs version of internal non-locked logging function.
- *
- * @param[in] f File handle to write into.
- * @param[in] ctx Logging context or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] fmt Message printf() style format string.
- * @param[in] args Argument structure.
- */
-static void
-aud_do_logv(FILE *f, const gchar *ctx, gint level, const gchar *fmt, va_list args)
-{
- gchar *msg = g_strdup_vprintf(fmt, args);
- aud_log_msg(f, ctx, level, msg);
- g_free(msg);
-}
-
-/**
- * Internal message logging function that does take the global lock.
- *
- * @param[in] f File handle to write into.
- * @param[in] ctx Logging context or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] fmt Message printf() style format string.
- * @param[in] ... Printf() style arguments, if any.
- */
-static void
-aud_do_log(FILE *f, const gchar *ctx, gint level, const gchar *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- aud_do_logv(f, ctx, level, fmt, ap);
- va_end(ap);
-}
-
-/**
- * Initialize logging subsystem.
- *
- * @param[in] filename Filename for logfile, or NULL to use stderr.
- * @param[in] mode Open mode for fopen().
- * @param[in] level Default logging level.
- */
-gint
-aud_log_init(const gchar *filename, const gchar *mode, gint level)
-{
- FILE *tmp;
- gchar *timestamp;
-
- /* Open or set logging file descriptor */
- if (filename != NULL)
- {
- if ((tmp = fopen(filename, mode)) == NULL)
- return -1;
- }
- else
- tmp = NULL;
-
- /* Create mutex, unless it already is set */
- if (log_mutex != NULL || (log_mutex = g_mutex_new()) == NULL)
- {
- fclose(tmp);
- return -3;
- }
-
- /* Acquire mutex, set log_file etc. */
- g_mutex_lock(log_mutex);
- if (log_file != NULL)
- fclose(log_file);
-
- if (tmp == NULL)
- log_file = stderr;
- else
- log_file = tmp;
-
- log_level = level;
-
- /* Logging starts here */
- timestamp = aud_log_timestr(AUD_LOG_CTIME_FMT);
- aud_do_log(log_file, NULL, -1, "Logfile opened %s.\n", timestamp);
- g_free(timestamp);
-
- /* Setup thread context hash table */
- if (log_thread_hash != NULL)
- {
- aud_do_log(log_file, NULL, -1, "Warning, log_thread_hash != NULL (%p)!",
- log_thread_hash);
- g_hash_table_destroy(log_thread_hash);
- }
-
- log_thread_hash = g_hash_table_new_full(
- g_direct_hash, g_direct_equal, NULL, g_free);
-
- g_mutex_unlock(log_mutex);
- return 0;
-}
-
-/** Internal helper function for #aud_log_close(). */
-static void
-aud_log_print_hash(gpointer key, gpointer value, gpointer found)
-{
- if (*(gboolean *)found == FALSE)
- {
- *(gboolean *)found = TRUE;
- aud_do_log(log_file, NULL, -1,
- "Warning, following lingering log thread contexts found:\n");
- }
-
- aud_do_log(log_file, NULL, -1, " - %p = '%s'\n", key, value);
-}
-
-/**
- * Shut down the logging subsystem. Logfile handle is closed,
- * mutexes and such freed, etc.
- */
-void
-aud_log_close(void)
-{
- GMutex *tmp;
- gchar *timestamp;
-
- if ((tmp = log_mutex) != NULL)
- {
- g_mutex_lock(tmp);
-
- if (log_thread_hash != NULL)
- {
- gboolean found = FALSE;
- g_hash_table_foreach(log_thread_hash,
- aud_log_print_hash, &found);
-
- g_hash_table_destroy(log_thread_hash);
- }
- log_thread_hash = NULL;
-
- timestamp = aud_log_timestr(AUD_LOG_CTIME_FMT);
- aud_do_log(log_file, NULL, -1, "Logfile closed %s.\n", timestamp);
- g_free(timestamp);
-
- log_mutex = NULL;
-
- if (log_file != NULL)
- fflush(log_file);
-
- if (log_file != stderr)
- fclose(log_file);
-
- log_file = NULL;
- g_mutex_unlock(tmp);
- }
-}
-
-/**
- * Add symbolic name for given thread identifier. The identifier
- * will be used in subsequent log messages originating from the
- * thread.
- *
- * @param[in] thread Pointer to a GThread structure of the thread.
- * @param[in] name String describing the thread.
- */
-void
-aud_log_add_thread_context(GThread *thread, const gchar *name)
-{
- gchar *tmp = g_strdup(name), *old;
- g_mutex_lock(log_mutex);
-
- old = g_hash_table_lookup(log_thread_hash, thread);
- if (old != NULL)
- aud_do_log(log_file, NULL, AUD_LOG_INFO,
- "Warning, thread %p is already in context ('%s')!\n", thread, old);
-
- g_hash_table_insert(log_thread_hash, thread, tmp);
-
- aud_do_log(log_file, NULL, AUD_LOG_INFO,
- "Thread %p name set to '%s'\n", thread, name);
-
- g_mutex_unlock(log_mutex);
-}
-
-/**
- * Removes identifier for thread, if present. If thread had not been
- * added in first place (via #aud_log_add_thread_context()), a warning
- * is logged instead.
- *
- * @param[in] thread Pointer to a GThread structure of the thread.
- */
-void
-aud_log_delete_thread_context(GThread *thread)
-{
- gchar *old;
- g_mutex_lock(log_mutex);
-
- old = g_hash_table_lookup(log_thread_hash, thread);
- if (old == NULL)
- {
- aud_do_log(log_file, NULL, AUD_LOG_INFO,
- "Warning, thread %p does not exist in context table!\n", thread);
- }
- else
- {
- aud_do_log(log_file, NULL, AUD_LOG_INFO,
- "Thread %p name ('%s') deleted from context table.\n", thread, old);
- g_hash_table_remove(log_thread_hash, thread);
- }
-
- g_mutex_unlock(log_mutex);
-}
-
-/**
- * Write a log entry with variable arguments structure.
- *
- * @param[in] ctx Logging context or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] fmt Message printf() style format string.
- * @param[in] args Argument structure.
- */
-void
-aud_logv(const gchar *ctx, gint level, const gchar *fmt, va_list args)
-{
- if (log_mutex == NULL || log_file == NULL)
- aud_do_log(stderr, ctx, level, fmt, args);
- else
- {
- g_mutex_lock(log_mutex);
- if (level <= log_level)
- aud_do_logv(log_file, ctx, level, fmt, args);
- g_mutex_unlock(log_mutex);
- }
-}
-
-/**
- * Write a log entry.
- *
- * @param[in] ctx Logging context or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] fmt Message printf() style format string.
- * @param[in] ... Optional printf() arguments.
- */
-void
-aud_log(const gchar *ctx, gint level, const gchar *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- aud_logv(ctx, level, fmt, ap);
- va_end(ap);
-}
-
-/**
- * Write a log entry with file/func/line information.
- *
- * @param[in] ctx Logging context pointer or NULL if no context / global context.
- * @param[in] level Message's log level setting.
- * @param[in] file Filename (usually obtained through __FILE__ macro)
- * @param[in] func Function name (usually obtained through __FUNCTION__ macro)
- * @param[in] line Linenumber (usually obtained through __LINE__ macro)
- * @param[in] fmt Message printf() style format string.
- * @param[in] ... Optional printf() arguments.
- */
-void
-aud_log_line(const gchar *ctx, gint level, const gchar *file, const gchar *func,
- gint line, const gchar *fmt, ...)
-{
- gchar *msg, *str, *info = g_strdup_printf("(%s:%s:%d) ", file, func, line);
- va_list ap;
-
- va_start(ap, fmt);
- msg = g_strdup_vprintf(fmt, ap);
- va_end(ap);
-
- str = g_strconcat(info, msg, NULL);
-
- if (log_mutex == NULL || log_file == NULL)
- aud_log_msg(stderr, ctx, level, str);
- else
- {
- g_mutex_lock(log_mutex);
- aud_log_msg(log_file, ctx, level, str);
- g_mutex_unlock(log_mutex);
- }
-
- g_free(info);
- g_free(msg);
- g_free(str);
-}
diff --git a/src/libaudcore/log.h b/src/libaudcore/log.h
deleted file mode 100644
index 769bd6d..0000000
--- a/src/libaudcore/log.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Logging and debug mechanisms
- * Copyright (c) 2009 Audacious team
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-/**
- * @file log.h
- * @brief Informative logging API (aud_log(), aud_debug() and friends).
- * Functions for logfile handling, log contexts, logging levels, etc.
- * Also functions and macros for debug-level stuff.
- */
-
-#ifndef AUD_LOG_CTX
-# define AUD_LOG_CTX NULL
-#endif
-
-#ifndef AUDACIOUS_LOG_H
-#define AUDACIOUS_LOG_H
-
-#include <glib.h>
-#include <stdarg.h>
-
-G_BEGIN_DECLS
-
-/** Log levels from least noisy to noisiest */
-typedef enum {
- AUD_LOG_NONE = 0, /**< Pseudo log-level for suppressing most log messages */
- AUD_LOG_FATAL_ERROR,
- AUD_LOG_ERROR,
- AUD_LOG_WARNING,
- AUD_LOG_INFO,
- AUD_LOG_DEBUG, /**< General debugging */
- AUD_LOG_DEBUG_INT, /**< Intensive debugging (more details) */
- AUD_LOG_ALL /**< Pseudo log-level for full logging */
-} AudLogLevel;
-
-gint aud_log_init(const gchar *filename, const gchar *mode, gint level);
-void aud_log_close(void);
-
-void aud_log_add_thread_context(GThread *thread, const gchar *name);
-void aud_log_delete_thread_context(GThread *thread);
-
-void aud_logv(const gchar *ctx, gint level, const gchar *fmt, va_list args) __attribute__ ((format(printf, 3, 0)));
-void aud_log(const gchar *ctx, gint level, const gchar *fmt, ...) __attribute__ ((format(printf, 3, 4)));
-void aud_log_line(const gchar *ctx, gint level, const gchar *file, const gchar *func, gint line, const gchar *fmt, ...) __attribute__ ((format(printf, 6, 7)));
-
-
-/* These are here as a quick hack for transition from glib message system */
-//#define GLIB_COMPAT
-
-#ifdef GLIB_COMPAT
-#undef g_message
-#undef g_warning
-#undef g_debug
-#undef g_error
-#undef g_critical
-#define g_message(...) aud_log(AUD_LOG_CTX, AUD_LOG_INFO, __VA_ARGS__)
-#define g_warning(...) aud_log(AUD_LOG_CTX, AUD_LOG_WARNING, __VA_ARGS__)
-#define g_error(...) do { aud_log(AUD_LOG_CTX, AUD_LOG_ERROR, __VA_ARGS__); abort(); } while (0)
-#define g_critical(...) do { aud_log(AUD_LOG_CTX, AUD_LOG_ERROR, __VA_ARGS__); abort(); } while (0)
-#endif
-
-//@{
-/** Convenience wrapper message macros */
-#if defined(DEBUG)
-# define aud_message(...) aud_log_line(AUD_LOG_CTX, AUD_LOG_INFO, __FILE__, __FUNCTION__, (gint) __LINE__, __VA_ARGS__)
-# define aud_warning(...) aud_log_line(AUD_LOG_CTX, AUD_LOG_WARNING, __FILE__, __FUNCTION__, (gint) __LINE__ , __VA_ARGS__)
-#else
-# define aud_message(...) aud_log(AUD_LOG_CTX, AUD_LOG_INFO, __VA_ARGS__)
-# define aud_warning(...) aud_log(AUD_LOG_CTX, AUD_LOG_WARNING, __VA_ARGS__)
-#endif
-//@}
-
-//@{
-/** Debug message macro and transitional aliases */
-#if defined(DEBUG)
-# define AUDDBG(...) aud_log_line(AUD_LOG_CTX, AUD_LOG_DEBUG, __FILE__, __FUNCTION__, (gint) __LINE__, __VA_ARGS__)
-# define aud_debug AUDDBG
-# ifdef GLIB_COMPAT
-# define g_debug AUDDBG
-# endif
-#else
-# define AUDDBG(...)
-# define aud_debug(...)
-# ifdef GLIB_COMPAT
-# define g_debug
-# endif
-#endif
-//@}
-
-//@{
-/** Extra debug messages (more noisy, needs DEBUG > 1) */
-#if defined(DEBUG) && (DEBUG > 1)
-# define AUDDBG_I(...) aud_log_line(AUD_LOG_CTX, AUD_LOG_DEBUG_INT, __FILE__, __FUNCTION__, (gint) __LINE__, __VA_ARGS__)
-#else
-# define AUDDBG_I(...)
-#endif
-//@}
-
-G_END_DECLS
-
-#endif /* AUDACIOUS_LOG_H */
diff --git a/src/libaudcore/stringpool.c b/src/libaudcore/stringpool.c
index 7833069..b30889d 100644
--- a/src/libaudcore/stringpool.c
+++ b/src/libaudcore/stringpool.c
@@ -1,6 +1,7 @@
/*
* Audacious
* Copyright © 2009 William Pitcock <nenolod@atheme.org>
+ * Copyright © 2010 John Lindgren <john.lindgren@tds.net>
*
* 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
@@ -18,110 +19,71 @@
* Audacious or using our public API to be a derived work.
*/
-/*
- * Note: This code used to do some normalization of strings: conversion to
- * UTF-8, conversion of the empty string to NULL, and (optionally) conversion
- * to uppercase. However, because such conversions can change the length of the
- * string, they can lead to a double-free.
- *
- * Consider:
- *
- * stringpool_get is called twice with the same 99-character ISO-8859-1 string.
- * The string is short enough to be cached, so stringpool_get returns a cached,
- * 101-character UTF-8 string. stringpool_unref is then called twice
- * with the cached string. Now that it has been converted, it is too long to be
- * cached, so stringpool_unref simply frees it, twice.
- *
- * Therefore, it is essential for stringpool_get to return a string that is
- * exactly the same as the one passed it.
- *
- * --jlindgren
- */
-
+#include <assert.h>
#include <glib.h>
#include <mowgli.h>
-#include "audstrings.h"
-
-#define MAXLEN 100
-
-static void
-noopcanon(gchar *str)
-{
- return;
-}
-
-/** Structure to handle string refcounting. */
-typedef struct {
- gint refcount;
- gchar *str;
-} PooledString;
-
static mowgli_patricia_t *stringpool_tree = NULL;
static GStaticMutex stringpool_mutex = G_STATIC_MUTEX_INIT;
-static inline gboolean stringpool_should_cache(const gchar *string)
-{
- const gchar *end = memchr(string, '\0', MAXLEN + 1);
- return end != NULL ? TRUE : FALSE;
-}
+#define MAXLEN 100
gchar *
-stringpool_get(const gchar *str)
+stringpool_get(gchar *str, gboolean take)
{
- PooledString *ps;
-
- g_return_val_if_fail(str != NULL, NULL);
+ if (str == NULL)
+ return NULL;
- if (!stringpool_should_cache(str))
- return g_strdup(str);
+ if (strlen(str) > MAXLEN)
+ return take ? str : g_strdup(str);
g_static_mutex_lock(&stringpool_mutex);
if (stringpool_tree == NULL)
- stringpool_tree = mowgli_patricia_create(noopcanon);
+ stringpool_tree = mowgli_patricia_create(NULL);
- if ((ps = mowgli_patricia_retrieve(stringpool_tree, str)) != NULL)
+ mowgli_patricia_elem_t *elem = mowgli_patricia_elem_find(stringpool_tree, str);
+ if (elem != NULL)
{
- ps->refcount++;
-
- g_static_mutex_unlock(&stringpool_mutex);
- return ps->str;
+ gint refcount = GPOINTER_TO_INT(mowgli_patricia_elem_get_data(elem));
+ mowgli_patricia_elem_set_data(elem, GINT_TO_POINTER(refcount + 1));
+ }
+ else
+ {
+ elem = mowgli_patricia_elem_add(stringpool_tree, str, GINT_TO_POINTER(1));
+ assert(elem != NULL);
}
- ps = g_slice_new0(PooledString);
- ps->refcount++;
- ps->str = g_strdup(str);
- mowgli_patricia_add(stringpool_tree, str, ps);
+ if (take)
+ g_free(str);
+ str = (gchar *)mowgli_patricia_elem_get_key(elem);
g_static_mutex_unlock(&stringpool_mutex);
- return ps->str;
+
+ return str;
}
void
stringpool_unref(gchar *str)
{
- PooledString *ps;
-
- g_return_if_fail(str != NULL);
-
- if (!stringpool_should_cache(str))
- {
- g_free(str);
+ if (str == NULL)
return;
- }
+
+ if (strlen(str) > MAXLEN)
+ return g_free(str);
g_return_if_fail(stringpool_tree != NULL);
g_static_mutex_lock(&stringpool_mutex);
- ps = mowgli_patricia_retrieve(stringpool_tree, str);
- if (ps != NULL && --ps->refcount <= 0)
- {
- mowgli_patricia_delete(stringpool_tree, str);
- g_free(ps->str);
- g_slice_free(PooledString, ps);
- }
+ mowgli_patricia_elem_t *elem = mowgli_patricia_elem_find(stringpool_tree, str);
+ assert(elem != NULL);
+
+ gint refcount = GPOINTER_TO_INT(mowgli_patricia_elem_get_data(elem));
+ if (refcount == 1)
+ mowgli_patricia_elem_delete(stringpool_tree, elem);
+ else
+ mowgli_patricia_elem_set_data(elem, GINT_TO_POINTER(refcount - 1));
g_static_mutex_unlock(&stringpool_mutex);
}
diff --git a/src/libaudcore/stringpool.h b/src/libaudcore/stringpool.h
index 985dfd3..0bd4255 100644
--- a/src/libaudcore/stringpool.h
+++ b/src/libaudcore/stringpool.h
@@ -32,10 +32,12 @@
* Otherwise, a new string is created in the pool with one reference.
*
* @param[in] str String to be poolified.
+ * @param[in] take Nonzero if the caller no longer needs str; in this case, the
+ * pool will eventually call g_free(str).
* @return Reference to the pooled string, or NULL if the given
* string was NULL or an error occured.
*/
-gchar *stringpool_get(const gchar *str);
+gchar *stringpool_get(gchar *str, gboolean take);
/**
* Unreference a pooled string. When there are no references left,
diff --git a/src/libaudcore/tuple.c b/src/libaudcore/tuple.c
index e7677b1..878b2f8 100644
--- a/src/libaudcore/tuple.c
+++ b/src/libaudcore/tuple.c
@@ -25,10 +25,16 @@
#include <glib.h>
#include <mowgli.h>
+#include <audacious/i18n.h>
+
+#include "config.h"
#include "tuple.h"
#include "audstrings.h"
#include "stringpool.h"
+static gboolean set_string (Tuple * tuple, const gint nfield,
+ const gchar * field, gchar * string, gboolean take);
+
/** Ordered table of basic #Tuple field names and their #TupleValueType.
*/
const TupleBasicType tuple_fields[FIELD_LAST] = {
@@ -82,32 +88,33 @@ static mowgli_heap_t *tuple_heap = NULL;
static mowgli_heap_t *tuple_value_heap = NULL;
static mowgli_object_class_t tuple_klass;
-/** Global R/W lock for preserve data consistency of heaps */
-static GStaticRWLock tuple_rwlock = G_STATIC_RW_LOCK_INIT;
+/** Global lock to preserve data consistency of heaps */
+static GStaticMutex tuple_mutex = G_STATIC_MUTEX_INIT;
//@{
/**
- * Convenience macro for read/write locking of the globally
+ * Convenience macros to lock the globally
* used internal Tuple system structures.
*/
-#define TUPLE_LOCK_WRITE(X) g_static_rw_lock_writer_lock(&tuple_rwlock)
-#define TUPLE_UNLOCK_WRITE(X) g_static_rw_lock_writer_unlock(&tuple_rwlock)
-#define TUPLE_LOCK_READ(X) g_static_rw_lock_reader_lock(&tuple_rwlock)
-#define TUPLE_UNLOCK_READ(X) g_static_rw_lock_reader_unlock(&tuple_rwlock)
+#define TUPLE_LOCK_WRITE(X) g_static_mutex_lock (& tuple_mutex)
+#define TUPLE_UNLOCK_WRITE(X) g_static_mutex_unlock (& tuple_mutex)
+#define TUPLE_LOCK_READ(X) g_static_mutex_lock (& tuple_mutex)
+#define TUPLE_UNLOCK_READ(X) g_static_mutex_unlock (& tuple_mutex)
//@}
-/* iterative destructor of tuple values. */
-static void
-tuple_value_destroy(mowgli_dictionary_elem_t *delem, gpointer privdata)
+static void tuple_value_destroy (TupleValue * value)
{
- TupleValue *value = (TupleValue *) delem->data;
+ if (value->type == TUPLE_STRING)
+ stringpool_unref (value->value.string);
- if (value->type == TUPLE_STRING) {
- stringpool_unref(value->value.string);
- value->value.string = NULL;
- }
+ memset (value, 0, sizeof (TupleValue));
+ mowgli_heap_free (tuple_value_heap, value);
+}
- mowgli_heap_free(tuple_value_heap, value);
+/* iterative destructor of tuple values. */
+static void tuple_value_destroy_cb (const gchar * key, void * data, void * priv)
+{
+ tuple_value_destroy (data);
}
static void
@@ -117,22 +124,17 @@ tuple_destroy(gpointer data)
gint i;
TUPLE_LOCK_WRITE();
- mowgli_dictionary_destroy(tuple->dict, tuple_value_destroy, NULL);
+ mowgli_patricia_destroy(tuple->dict, tuple_value_destroy_cb, NULL);
for (i = 0; i < FIELD_LAST; i++)
- if (tuple->values[i]) {
- TupleValue *value = tuple->values[i];
-
- if (value->type == TUPLE_STRING) {
- stringpool_unref(value->value.string);
- value->value.string = NULL;
- }
-
- mowgli_heap_free(tuple_value_heap, value);
- }
+ {
+ if (tuple->values[i])
+ tuple_value_destroy (tuple->values[i]);
+ }
g_free(tuple->subtunes);
+ memset (tuple, 0, sizeof (Tuple));
mowgli_heap_free(tuple_heap, tuple);
TUPLE_UNLOCK_WRITE();
}
@@ -155,7 +157,7 @@ tuple_new_unlocked(void)
memset(tuple, 0, sizeof(Tuple));
mowgli_object_init(mowgli_object(tuple), NULL, &tuple_klass, NULL);
- tuple->dict = mowgli_dictionary_create(g_ascii_strcasecmp);
+ tuple->dict = mowgli_patricia_create(string_canonize_case);
return tuple;
}
@@ -190,50 +192,38 @@ tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, Tuple
* @param[in] filename Filename URI.
* @param[in,out] tuple Tuple structure to manipulate.
*/
-void
-tuple_set_filename(Tuple *tuple, const gchar *filename)
+void tuple_set_filename (Tuple * tuple, const gchar * name)
{
- gchar *local = g_strdup(filename);
- gchar *slash, *period, *question;
-
- string_decode_percent(local);
-
- /* Convert invalid UTF-8 URI's quietly. */
- if (! g_utf8_validate (local, -1, NULL))
+ const gchar * slash;
+ if ((slash = strrchr (name, '/')))
{
- gchar * utf8 = str_to_utf8 (local);
- g_free (local);
- local = utf8;
+ gchar path[slash - name + 2];
+ memcpy (path, name, slash - name + 1);
+ path[slash - name + 1] = 0;
+
+ set_string (tuple, FIELD_FILE_PATH, NULL, uri_to_display (path), TRUE);
+ name = slash + 1;
}
- slash = strrchr(local, '/');
- period = strrchr(local, '.');
- question = strrchr(local, '?');
+ gchar buf[strlen (name) + 1];
+ strcpy (buf, name);
- if (slash != NULL)
+ gchar * c;
+ if ((c = strrchr (buf, '?')))
{
- gchar temp = *(slash + 1);
+ gint sub;
+ if (sscanf (c + 1, "%d", & sub) == 1)
+ tuple_associate_int (tuple, FIELD_SUBSONG_ID, NULL, sub);
- *(slash + 1) = 0;
- tuple_associate_string(tuple, FIELD_FILE_PATH, NULL, local);
- *(slash + 1) = temp;
- tuple_associate_string(tuple, FIELD_FILE_NAME, NULL, slash + 1);
+ * c = 0;
}
- if (question != NULL)
- {
- gint subtune;
-
- *question = 0;
+ gchar * base = uri_to_display (buf);
- if (sscanf(question + 1, "%d", &subtune) == 1)
- tuple_associate_int(tuple, FIELD_SUBSONG_ID, NULL, subtune);
- }
+ if ((c = strrchr (base, '.')))
+ set_string (tuple, FIELD_FILE_EXT, NULL, c + 1, FALSE);
- if (period != NULL)
- tuple_associate_string(tuple, FIELD_FILE_EXT, NULL, period + 1);
-
- g_free(local);
+ set_string (tuple, FIELD_FILE_NAME, NULL, base, TRUE);
}
/**
@@ -251,11 +241,12 @@ tuple_copy_value(TupleValue *src)
if (src == NULL) return NULL;
res = mowgli_heap_alloc(tuple_value_heap);
+ g_strlcpy(res->name, src->name, TUPLE_NAME_MAX);
res->type = src->type;
switch (src->type) {
case TUPLE_STRING:
- res->value.string = stringpool_get(src->value.string);
+ res->value.string = stringpool_get (src->value.string, FALSE);
break;
case TUPLE_INT:
res->value.integer = src->value.integer;
@@ -278,7 +269,7 @@ tuple_copy(const Tuple *src)
{
Tuple *dst;
TupleValue * tv, * copied;
- mowgli_dictionary_iteration_state_t state;
+ mowgli_patricia_iteration_state_t state;
gint i;
g_return_val_if_fail(src != NULL, NULL);
@@ -292,10 +283,10 @@ tuple_copy(const Tuple *src)
dst->values[i] = tuple_copy_value(src->values[i]);
/* Copy dictionary contents */
- MOWGLI_DICTIONARY_FOREACH (tv, & state, src->dict)
+ MOWGLI_PATRICIA_FOREACH (tv, & state, src->dict)
{
if ((copied = tuple_copy_value (tv)) != NULL)
- mowgli_dictionary_add (dst->dict, state.cur->key, copied);
+ mowgli_patricia_add (dst->dict, copied->name, copied);
}
/* Copy subtune number information */
@@ -386,7 +377,7 @@ tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, Tuple
return NULL;
}
} else {
- value = mowgli_dictionary_retrieve(tuple->dict, tfield);
+ value = mowgli_patricia_retrieve(tuple->dict, tfield);
}
if (value != NULL) {
@@ -399,15 +390,45 @@ tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, Tuple
/* Allocate a new value */
value = mowgli_heap_alloc(tuple_value_heap);
value->type = ftype;
+
if (nfield >= 0)
+ {
+ value->name[0] = 0;
tuple->values[nfield] = value;
+ }
else
- mowgli_dictionary_add(tuple->dict, tfield, value);
+ {
+ g_strlcpy (value->name, tfield, TUPLE_NAME_MAX);
+ mowgli_patricia_add(tuple->dict, tfield, value);
+ }
}
return value;
}
+static gboolean set_string (Tuple * tuple, const gint nfield,
+ const gchar * field, gchar * string, gboolean take)
+{
+ TUPLE_LOCK_WRITE ();
+
+ TupleValue * value = tuple_associate_data (tuple, nfield, field,
+ TUPLE_STRING);
+ if (! value)
+ {
+ if (take)
+ g_free (string);
+ return FALSE;
+ }
+
+ if (! string)
+ value->value.string = NULL;
+ else
+ value->value.string = stringpool_get (string, take);
+
+ TUPLE_UNLOCK_WRITE ();
+ return TRUE;
+}
+
/**
* Associates copy of given string to a field in specified #Tuple.
* If field already exists, old value is freed and replaced.
@@ -421,29 +442,18 @@ tuple_associate_data(Tuple *tuple, const gint cnfield, const gchar *field, Tuple
* @param[in] string String to be associated to given field in Tuple.
* @return TRUE if operation was succesful, FALSE if not.
*/
-gboolean
-tuple_associate_string(Tuple *tuple, const gint nfield, const gchar *field, const gchar *string)
-{
- TupleValue *value;
- TUPLE_LOCK_WRITE();
- if ((value = tuple_associate_data(tuple, nfield, field, TUPLE_STRING)) == NULL)
- return FALSE;
-
- if (string == NULL)
- value->value.string = NULL;
- else if (g_utf8_validate (string, -1, NULL))
- value->value.string = stringpool_get (string);
- else
+gboolean tuple_associate_string (Tuple * tuple, const gint nfield,
+ const gchar * field, const gchar * string)
+{
+ if (string && ! g_utf8_validate (string, -1, NULL))
{
fprintf (stderr, "Invalid UTF-8: %s.\n", string);
- gchar * copy = str_to_utf8 (string);
- value->value.string = stringpool_get (copy);
- g_free (copy);
+ return set_string (tuple, nfield, field, str_to_utf8 (string), TRUE);
}
- TUPLE_UNLOCK_WRITE();
- return TRUE;
+ gboolean ret = set_string (tuple, nfield, field, (gchar *) string, FALSE);
+ return ret;
}
/**
@@ -464,9 +474,15 @@ tuple_associate_string(Tuple *tuple, const gint nfield, const gchar *field, cons
gboolean tuple_associate_string_rel (Tuple * tuple, const gint nfield,
const gchar * field, gchar * string)
{
- gboolean ret = tuple_associate_string (tuple, nfield, field, string);
- g_free (string);
- return ret;
+ if (string && ! g_utf8_validate (string, -1, NULL))
+ {
+ fprintf (stderr, "Invalid UTF-8: %s.\n", string);
+ gchar * copy = str_to_utf8 (string);
+ g_free (string);
+ string = copy;
+ }
+
+ return set_string (tuple, nfield, field, string, TRUE);
}
/**
@@ -521,24 +537,15 @@ tuple_disassociate(Tuple *tuple, const gint cnfield, const gchar *field)
TUPLE_LOCK_WRITE();
if (nfield < 0)
/* why _delete()? because _delete() returns the dictnode's data on success */
- value = mowgli_dictionary_delete(tuple->dict, field);
+ value = mowgli_patricia_delete(tuple->dict, field);
else {
value = tuple->values[nfield];
tuple->values[nfield] = NULL;
}
- if (value == NULL) {
- TUPLE_UNLOCK_WRITE();
- return;
- }
+ if (value)
+ tuple_value_destroy (value);
- /* Free associated data */
- if (value->type == TUPLE_STRING) {
- stringpool_unref(value->value.string);
- value->value.string = NULL;
- }
-
- mowgli_heap_free(tuple_value_heap, value);
TUPLE_UNLOCK_WRITE();
}
@@ -567,7 +574,7 @@ TupleValueType tuple_get_value_type (const Tuple * tuple, gint cnfield,
TUPLE_LOCK_READ();
if (nfield < 0) {
TupleValue *value;
- if ((value = mowgli_dictionary_retrieve(tuple->dict, field)) != NULL)
+ if ((value = mowgli_patricia_retrieve(tuple->dict, field)) != NULL)
type = value->type;
} else {
if (tuple->values[nfield])
@@ -603,7 +610,7 @@ const gchar * tuple_get_string (const Tuple * tuple, gint cnfield, const gchar *
TUPLE_LOCK_READ();
if (nfield < 0)
- value = mowgli_dictionary_retrieve(tuple->dict, field);
+ value = mowgli_patricia_retrieve(tuple->dict, field);
else
value = tuple->values[nfield];
@@ -644,7 +651,7 @@ gint tuple_get_int (const Tuple * tuple, gint cnfield, const gchar * field)
TUPLE_LOCK_READ();
if (nfield < 0)
- value = mowgli_dictionary_retrieve(tuple->dict, field);
+ value = mowgli_patricia_retrieve(tuple->dict, field);
else
value = tuple->values[nfield];
@@ -659,3 +666,38 @@ gint tuple_get_int (const Tuple * tuple, gint cnfield, const gchar * field)
return 0;
}
}
+
+#define APPEND(b, ...) snprintf (b + strlen (b), sizeof b - strlen (b), \
+ __VA_ARGS__)
+
+void tuple_set_format (Tuple * t, const gchar * format, gint chans, gint rate,
+ gint brate)
+{
+ if (format)
+ tuple_associate_string (t, FIELD_CODEC, NULL, format);
+
+ gchar buf[32];
+ buf[0] = 0;
+
+ if (chans > 0)
+ {
+ if (chans == 1)
+ APPEND (buf, _("Mono"));
+ else if (chans == 2)
+ APPEND (buf, _("Stereo"));
+ else
+ APPEND (buf, _("%d channels"), chans);
+
+ if (rate > 0)
+ APPEND (buf, ", ");
+ }
+
+ if (rate > 0)
+ APPEND (buf, "%d kHz", rate / 1000);
+
+ if (buf[0])
+ tuple_associate_string (t, FIELD_QUALITY, NULL, buf);
+
+ if (brate > 0)
+ tuple_associate_int (t, FIELD_BITRATE, NULL, brate);
+}
diff --git a/src/libaudcore/tuple.h b/src/libaudcore/tuple.h
index 3ef8ca4..bb277bf 100644
--- a/src/libaudcore/tuple.h
+++ b/src/libaudcore/tuple.h
@@ -80,7 +80,7 @@ enum {
FIELD_GAIN_GAIN_UNIT,
FIELD_GAIN_PEAK_UNIT,
- FIELD_COMPOSER, /**< Composer of song, if different than artist. */
+ FIELD_COMPOSER, /**< Composer of song, if different than artist. */
/* Special field, must always be last */
FIELD_LAST
@@ -99,7 +99,10 @@ typedef struct {
extern const TupleBasicType tuple_fields[FIELD_LAST];
+#define TUPLE_NAME_MAX 20
+
typedef struct {
+ gchar name[TUPLE_NAME_MAX]; /* for standard fields, the empty string */
TupleValueType type;
union {
gchar *string;
@@ -113,7 +116,7 @@ typedef struct {
*/
typedef struct _Tuple {
mowgli_object_t parent;
- mowgli_dictionary_t *dict; /**< Mowgli dictionary for holding other than basic values. */
+ mowgli_patricia_t *dict; /**< Mowgli dictionary for holding other than basic values. */
TupleValue *values[FIELD_LAST]; /**< Basic #Tuple values, entry is NULL if not set. */
gint nsubtunes; /**< Number of subtunes, if any. Values greater than 0
mean that there are subtunes and #subtunes array
@@ -140,6 +143,15 @@ const gchar * tuple_get_string (const Tuple * tuple, gint nfield, const gchar *
gint tuple_get_int (const Tuple * tuple, gint nfield, const gchar * field);
#define tuple_free(x) mowgli_object_unref(x);
+/* Fills in format-related fields (specifically FIELD_CODEC, FIELD_QUALITY, and
+ * FIELD_BITRATE. Plugins should use this function instead of setting these
+ * fields individually so that the style is consistent across file formats.
+ * <format> should be a brief description such as "Microsoft WAV", "MPEG-1 layer
+ * 3", "Audio CD", and so on. <samplerate> is in Hertz. <bitrate> is in 1000
+ * bits per second. */
+void tuple_set_format (Tuple * tuple, const gchar * format, gint channels, gint
+ samplerate, gint bitrate);
+
G_END_DECLS
#endif /* AUDACIOUS_TUPLE_H */
diff --git a/src/libaudcore/tuple_compiler.c b/src/libaudcore/tuple_compiler.c
index 18f84a5..c930f5b 100644
--- a/src/libaudcore/tuple_compiler.c
+++ b/src/libaudcore/tuple_compiler.c
@@ -580,7 +580,7 @@ static TupleValue * tf_get_fieldref (TupleEvalVar * var, const Tuple * tuple)
{
if (var->type == TUPLE_VAR_FIELD && var->fieldref == NULL) {
if (var->fieldidx < 0)
- var->fieldref = mowgli_dictionary_retrieve(tuple->dict, var->name);
+ var->fieldref = mowgli_patricia_retrieve(tuple->dict, var->name);
else
var->fieldref = tuple->values[var->fieldidx];
}
@@ -819,7 +819,7 @@ static gboolean tuple_formatter_eval_do (TupleEvalContext * ctx, TupleEvalNode *
gchar * tuple_formatter_eval (TupleEvalContext * ctx, TupleEvalNode * expr,
const Tuple * tuple)
{
- gchar *res = g_strdup("");
+ gchar *res = NULL;
gssize resmax = 0, reslen = 0;
assert(ctx != NULL);
assert(tuple != NULL);
diff --git a/src/libaudcore/tuple_formatter.c b/src/libaudcore/tuple_formatter.c
index 1124b38..4738ecb 100644
--- a/src/libaudcore/tuple_formatter.c
+++ b/src/libaudcore/tuple_formatter.c
@@ -42,7 +42,7 @@
#ifdef TUPLE_USE_COMPILER
# include "tuple_compiler.h"
-static GStaticRWLock tuplec_rwlock = G_STATIC_RW_LOCK_INIT;
+static GStaticMutex tuplec_mutex = G_STATIC_MUTEX_INIT;
#endif
#ifdef _DEBUG
@@ -544,7 +544,8 @@ gchar * tuple_formatter_process_string (const Tuple * tuple, const gchar * strin
}
#ifdef TUPLE_USE_COMPILER
- g_static_rw_lock_writer_lock(&tuplec_rwlock);
+ g_static_mutex_lock (& tuplec_mutex);
+
if (last_string == NULL ||
(last_string != NULL && strcmp(last_string, string)))
{
@@ -576,14 +577,13 @@ gchar * tuple_formatter_process_string (const Tuple * tuple, const gchar * strin
#endif
tuple_evalctx_reset(last_ctx);
- g_static_rw_lock_writer_unlock(&tuplec_rwlock);
- g_static_rw_lock_reader_lock(&tuplec_rwlock);
result = tuple_formatter_eval(last_ctx, last_ev, tuple);
if (last_ctx->iserror) {
g_warning("[TuplezEV]: %s", last_ctx->errmsg);
}
- g_static_rw_lock_reader_unlock(&tuplec_rwlock);
+
+ g_static_mutex_unlock (& tuplec_mutex);
return result;
#else
diff --git a/src/libaudcore/vfs.c b/src/libaudcore/vfs.c
index 09a5302..b05b47e 100644
--- a/src/libaudcore/vfs.c
+++ b/src/libaudcore/vfs.c
@@ -17,6 +17,8 @@
* Audacious or using our public API to be a derived work.
*/
+#include <inttypes.h>
+
#include "vfs.h"
#include "audstrings.h"
#include <stdio.h>
@@ -25,49 +27,120 @@
#include <sys/types.h>
#include <string.h>
+#include <mowgli.h>
-/**
- * GList of #VFSConstructor objects holding all the registered
- * VFS transports.
- */
-GList *vfs_transports = NULL; /* temporary. -nenolod */
+/* Audacious core provides us with a function that looks up a VFS transport for
+ * a given URI scheme. Since this function will load plugins as needed, it can
+ * only be called from the main thread. When VFS is used from parallel threads,
+ * vfs_prepare must be called from the main thread to look up any needed
+ * transports beforehand. */
+typedef struct {
+ VFSConstructor * transport;
+ gboolean prepared;
+} LookupNode;
-/**
- * Registers a #VFSConstructor vtable with the VFS system.
- *
- * @param vtable The #VFSConstructor vtable to register.
- */
-void vfs_register_transport (VFSConstructor * vtable)
+static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
+static GThread * lookup_thread = NULL;
+static VFSConstructor * (* lookup_func) (const gchar * scheme) = NULL;
+static mowgli_patricia_t * lookup_table = NULL;
+
+void vfs_set_lookup_func (VFSConstructor * (* func) (const gchar * scheme))
{
- vfs_transports = g_list_append (vfs_transports, vtable);
+ g_static_mutex_lock (& mutex);
+
+ lookup_thread = g_thread_self ();
+ lookup_func = func;
+
+ if (! lookup_table)
+ lookup_table = mowgli_patricia_create (NULL);
+
+ g_static_mutex_unlock (& mutex);
}
-static VFSConstructor *
-vfs_get_constructor(const gchar *path)
+static VFSConstructor * do_lookup (const gchar * scheme, gboolean prepare)
{
- VFSConstructor *vtable = NULL;
- GList *node;
+ g_return_val_if_fail (lookup_thread && lookup_func && lookup_table, NULL);
- if (path == NULL)
- return NULL;
+ LookupNode * node = mowgli_patricia_retrieve (lookup_table, scheme);
+ if (! node)
+ {
+ node = g_slice_new (LookupNode);
+ node->transport = NULL;
+ node->prepared = FALSE;
+ mowgli_patricia_add (lookup_table, scheme, node);
+ }
- for (node = vfs_transports; node != NULL; node = g_list_next(node))
+ if (prepare)
+ node->prepared = TRUE;
+
+ /* vfs_prepare can only be called from the main thread. vfs_fopen can only
+ * be called from the main thread unless vfs_prepare has been called. */
+ if (prepare || ! node->prepared)
+ g_return_val_if_fail (g_thread_self () == lookup_thread, NULL);
+
+ /* do the actual lookup if needed, but only in the main thread */
+ if (! node->transport && g_thread_self () == lookup_thread)
{
- VFSConstructor *vtptr = (VFSConstructor *) node->data;
+ node->transport = lookup_func (scheme);
+ /* This is normal for custom URI schemes.
+ if (! node->transport)
+ fprintf (stderr, "No transport plugin found for URI scheme \"%s\".\n", scheme); */
+ }
+
+ return node->transport;
+}
+
+void vfs_prepare (const gchar * scheme)
+{
+ g_static_mutex_lock (& mutex);
+ do_lookup (scheme, TRUE);
+ g_static_mutex_unlock (& mutex);
+}
- if (!strncasecmp(path, vtptr->uri_id, strlen(vtptr->uri_id)))
+void vfs_prepare_filename (const gchar * path)
+{
+ const gchar * s = strstr (path, "://");
+ g_return_if_fail (s);
+ gchar scheme[s - path + 1];
+ strncpy (scheme, path, s - path);
+ scheme[s - path] = 0;
+
+ vfs_prepare (scheme);
+}
+
+static gboolean verbose = FALSE;
+
+void vfs_set_verbose (gboolean set)
+{
+ verbose = set;
+}
+
+static void logger (const gchar * format, ...)
+{
+ static gchar last[256] = "";
+ static gint repeated = 0;
+
+ gchar buf[256];
+
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buf, sizeof buf, format, args);
+ va_end (args);
+
+ if (! strcmp (buf, last))
+ repeated ++;
+ else
+ {
+ if (repeated)
{
- vtable = vtptr;
- break;
+ printf ("VFS: (last message repeated %d times)\n", repeated);
+ repeated = 0;
}
+
+ fputs (buf, stdout);
+ strcpy (last, buf);
}
-
- /* No transport vtable has been registered, bail. */
- if (vtable == NULL)
- g_warning("Could not open '%s', no transport plugin available.", path);
-
- return vtable;
}
/**
@@ -82,20 +155,37 @@ VFSFile *
vfs_fopen(const gchar * path,
const gchar * mode)
{
+ g_return_val_if_fail (path && mode, NULL);
+ g_return_val_if_fail (lookup_func, NULL);
+
VFSFile *file;
VFSConstructor *vtable = NULL;
- if (path == NULL || mode == NULL || (vtable = vfs_get_constructor(path)) == NULL)
+ const gchar * s = strstr (path, "://");
+ g_return_val_if_fail (s, NULL);
+ gchar scheme[s - path + 1];
+ strncpy (scheme, path, s - path);
+ scheme[s - path] = 0;
+
+ g_static_mutex_lock (& mutex);
+ vtable = do_lookup (scheme, FALSE);
+ g_static_mutex_unlock (& mutex);
+
+ if (! vtable)
return NULL;
file = vtable->vfs_fopen_impl(path, mode);
+ if (verbose)
+ logger ("VFS: <%p> open (mode %s) %s\n", file, mode, path);
+
if (file == NULL)
return NULL;
file->uri = g_strdup(path);
file->base = vtable;
file->ref = 1;
+ file->sig = VFS_SIG;
return file;
}
@@ -109,10 +199,12 @@ vfs_fopen(const gchar * path,
gint
vfs_fclose(VFSFile * file)
{
- gint ret = 0;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
- if (file == NULL)
- return -1;
+ if (verbose)
+ printf ("VFS: <%p> close\n", file);
+
+ gint ret = 0;
if (--file->ref > 0)
return -1;
@@ -121,7 +213,9 @@ vfs_fclose(VFSFile * file)
ret = -1;
g_free(file->uri);
- g_free(file);
+
+ memset (file, 0, sizeof (VFSFile));
+ g_free (file);
return ret;
}
@@ -137,10 +231,15 @@ vfs_fclose(VFSFile * file)
*/
gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
{
- if (file == NULL)
- return 0;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
+
+ gint64 readed = file->base->vfs_fread_impl (ptr, size, nmemb, file);
+
+ if (verbose)
+ logger ("VFS: <%p> read %"PRId64" elements of size %"PRId64" = "
+ "%"PRId64"\n", file, nmemb, size, readed);
- return file->base->vfs_fread_impl(ptr, size, nmemb, file);
+ return readed;
}
/**
@@ -154,23 +253,30 @@ gint64 vfs_fread (void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
*/
gint64 vfs_fwrite (const void * ptr, gint64 size, gint64 nmemb, VFSFile * file)
{
- if (file == NULL)
- return 0;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, 0);
+
+ gint64 written = file->base->vfs_fwrite_impl (ptr, size, nmemb, file);
+
+ if (verbose)
+ logger ("VFS: <%p> write %"PRId64" elements of size %"PRId64" = "
+ "%"PRId64"\n", file, nmemb, size, written);
- return file->base->vfs_fwrite_impl(ptr, size, nmemb, file);
+ return written;
}
/**
* Reads a character from a VFS stream.
*
* @param file #VFSFile object that represents the VFS stream.
- * @return On success, a character. Otherwise, -1.
+ * @return On success, a character. Otherwise, EOF.
*/
gint
vfs_getc(VFSFile *file)
{
- if (file == NULL)
- return -1;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
+
+ if (verbose)
+ logger ("VFS: <%p> getc\n", file);
return file->base->vfs_getc_impl(file);
}
@@ -180,13 +286,15 @@ vfs_getc(VFSFile *file)
*
* @param c The character to push back.
* @param file #VFSFile object that represents the VFS stream.
- * @return On success, 0. Otherwise, -1.
+ * @return On success, 0. Otherwise, EOF.
*/
gint
vfs_ungetc(gint c, VFSFile *file)
{
- if (file == NULL)
- return -1;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, EOF);
+
+ if (verbose)
+ logger ("VFS: <%p> ungetc\n", file);
return file->base->vfs_ungetc_impl(c, file);
}
@@ -209,8 +317,12 @@ vfs_fseek(VFSFile * file,
gint64 offset,
gint whence)
{
- if (file == NULL)
- return 0;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
+
+ if (verbose)
+ logger ("VFS: <%p> seek to %"PRId64" from %s\n", file, offset, whence ==
+ SEEK_CUR ? "current" : whence == SEEK_SET ? "beginning" : whence ==
+ SEEK_END ? "end" : "invalid");
return file->base->vfs_fseek_impl(file, offset, whence);
}
@@ -223,8 +335,10 @@ vfs_fseek(VFSFile * file,
void
vfs_rewind(VFSFile * file)
{
- if (file == NULL)
- return;
+ g_return_if_fail (file && file->sig == VFS_SIG);
+
+ if (verbose)
+ logger ("VFS: <%p> rewind\n", file);
file->base->vfs_rewind_impl(file);
}
@@ -235,13 +349,17 @@ vfs_rewind(VFSFile * file)
* @param file #VFSFile object that represents the VFS stream.
* @return On success, the current position. Otherwise, -1.
*/
-glong
+gint64
vfs_ftell(VFSFile * file)
{
- if (file == NULL)
- return -1;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
+
+ gint64 told = file->base->vfs_ftell_impl (file);
+
+ if (verbose)
+ logger ("VFS: <%p> tell = %"PRId64"\n", file, told);
- return file->base->vfs_ftell_impl(file);
+ return told;
}
/**
@@ -253,10 +371,14 @@ vfs_ftell(VFSFile * file)
gboolean
vfs_feof(VFSFile * file)
{
- if (file == NULL)
- return FALSE;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, TRUE);
+
+ gboolean eof = file->base->vfs_feof_impl (file);
- return (gboolean) file->base->vfs_feof_impl(file);
+ if (verbose)
+ logger ("VFS: <%p> eof = %s\n", file, eof ? "yes" : "no");
+
+ return eof;
}
/**
@@ -268,8 +390,10 @@ vfs_feof(VFSFile * file)
*/
gint vfs_ftruncate (VFSFile * file, gint64 length)
{
- if (file == NULL)
- return -1;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
+
+ if (verbose)
+ logger ("VFS: <%p> truncate to %"PRId64"\n", file, length);
return file->base->vfs_ftruncate_impl(file, length);
}
@@ -280,13 +404,16 @@ gint vfs_ftruncate (VFSFile * file, gint64 length)
* @param file #VFSFile object that represents the VFS stream.
* @return On success, the size of the file in bytes. Otherwise, -1.
*/
-gint64
-vfs_fsize(VFSFile * file)
+gint64 vfs_fsize (VFSFile * file)
{
- if (file == NULL)
- return -1;
+ g_return_val_if_fail (file && file->sig == VFS_SIG, -1);
+
+ gint64 size = file->base->vfs_fsize_impl (file);
- return file->base->vfs_fsize_impl(file);
+ if (verbose)
+ logger ("VFS: <%p> size = %"PRId64"\n", file, size);
+
+ return size;
}
/**
@@ -380,16 +507,7 @@ vfs_dup(VFSFile *in)
gboolean
vfs_is_remote(const gchar * path)
{
- VFSConstructor *vtable = NULL;
-
- if (path == NULL || (vtable = vfs_get_constructor(path)) == NULL)
- return FALSE;
-
- /* check if vtable->uri_id is file:// or not, for now. */
- if (!strncasecmp("file://", vtable->uri_id, strlen(vtable->uri_id)))
- return FALSE;
- else
- return TRUE;
+ return strncasecmp (path, "file://", 7) ? TRUE : FALSE;
}
/**
diff --git a/src/libaudcore/vfs.h b/src/libaudcore/vfs.h
index da39157..b9d2cca 100644
--- a/src/libaudcore/vfs.h
+++ b/src/libaudcore/vfs.h
@@ -36,7 +36,9 @@ G_BEGIN_DECLS
/** @struct VFSFile */
typedef struct _VFSFile VFSFile;
/** @struct VFSConstructor */
-typedef struct _VFSConstructor VFSConstructor;
+typedef const struct _VFSConstructor VFSConstructor;
+
+#define VFS_SIG ('V' | ('F' << 8) | ('S' << 16))
/**
* @struct _VFSFile
@@ -48,6 +50,7 @@ struct _VFSFile {
gpointer handle; /**< Opaque data used by the transport plugins */
VFSConstructor *base; /**< The base vtable used for VFS functions */
gint ref; /**< The amount of references that the VFSFile object has */
+ gint sig; /**< Used to detect invalid or twice-closed objects */
};
/**
@@ -57,9 +60,6 @@ struct _VFSFile {
* nature. VFS base vtables are registered via vfs_register_transport().
*/
struct _VFSConstructor {
- /** The URI identifier, e.g. "file" would handle "file://" streams. */
- gchar * uri_id;
-
/** A function pointer which points to a fopen implementation. */
VFSFile * (* vfs_fopen_impl) (const gchar * filename, const gchar * mode);
/** A function pointer which points to a fclose implementation. */
@@ -118,7 +118,7 @@ gint vfs_fprintf (VFSFile * stream, gchar const * format, ...) __attribute__
gint vfs_fseek (VFSFile * file, gint64 offset, gint whence) WARN_RETURN;
void vfs_rewind (VFSFile * file);
-glong vfs_ftell (VFSFile * file) WARN_RETURN;
+gint64 vfs_ftell (VFSFile * file) WARN_RETURN;
gint64 vfs_fsize (VFSFile * file) WARN_RETURN;
gint vfs_ftruncate (VFSFile * file, gint64 length) WARN_RETURN;
@@ -146,7 +146,11 @@ gboolean vfs_is_remote (const gchar * path) WARN_RETURN;
void vfs_file_get_contents (const gchar * filename, void * * buf, gint64 *
size);
-void vfs_register_transport (VFSConstructor * vtable);
+void vfs_set_lookup_func (VFSConstructor * (* func) (const gchar * scheme));
+void vfs_prepare (const gchar * scheme);
+void vfs_prepare_filename (const gchar * filename);
+
+void vfs_set_verbose (gboolean verbose);
#undef WARN_RETURN
diff --git a/src/libaudcore/vfs_async.c b/src/libaudcore/vfs_async.c
index b4e462f..cb4acd5 100644
--- a/src/libaudcore/vfs_async.c
+++ b/src/libaudcore/vfs_async.c
@@ -56,6 +56,8 @@ vfs_async_file_get_contents_worker(gpointer data)
void
vfs_async_file_get_contents(const gchar *filename, VFSConsumer cons_f, gpointer userdata)
{
+ vfs_prepare_filename (filename);
+
VFSAsyncTrampoline *tr;
tr = g_slice_new0(VFSAsyncTrampoline);
diff --git a/src/libaudcore/vfs_buffer.c b/src/libaudcore/vfs_buffer.c
index e023e67..33240f3 100644
--- a/src/libaudcore/vfs_buffer.c
+++ b/src/libaudcore/vfs_buffer.c
@@ -194,7 +194,6 @@ buffer_vfs_fsize_impl(VFSFile * file)
}
static VFSConstructor buffer_const = {
- NULL, // not a normal VFS class
buffer_vfs_fopen_impl,
buffer_vfs_fclose_impl,
buffer_vfs_fread_impl,
@@ -236,6 +235,7 @@ vfs_buffer_new(gpointer data, gsize size)
handle->handle = buffer;
handle->base = &buffer_const;
handle->ref = 1;
+ handle->sig = VFS_SIG;
return handle;
}
diff --git a/src/libaudcore/vfs_buffered_file.c b/src/libaudcore/vfs_buffered_file.c
index 2264e15..064d697 100644
--- a/src/libaudcore/vfs_buffered_file.c
+++ b/src/libaudcore/vfs_buffered_file.c
@@ -199,7 +199,6 @@ buffered_file_vfs_metadata_impl(VFSFile * file, const gchar * field)
}
VFSConstructor buffered_file_const = {
- NULL, // not a normal VFS class
buffered_file_vfs_fopen_impl,
buffered_file_vfs_fclose_impl,
buffered_file_vfs_fread_impl,
@@ -263,6 +262,7 @@ vfs_buffered_file_new_from_uri(const gchar *uri)
handle->base = &buffered_file_const;
handle->uri = g_strdup(uri);
handle->ref = 1;
+ handle->sig = VFS_SIG;
return handle;
}
diff --git a/src/libaudgui/Makefile b/src/libaudgui/Makefile
index 448c353..cbf6678 100644
--- a/src/libaudgui/Makefile
+++ b/src/libaudgui/Makefile
@@ -9,7 +9,7 @@ SRCS = confirm.c \
infopopup.c \
infowin.c \
init.c \
- library-store.c \
+ list.c \
ui_gtk.c \
ui_fileopener.c \
ui_urlopener.c \
@@ -23,14 +23,15 @@ SRCS = confirm.c \
util.c
INCLUDES = libaudgui.h \
- libaudgui-gtk.h
+ libaudgui-gtk.h \
+ list.h
include ../../buildsys.mk
include ../../extra.mk
includesubdir = libaudgui
-CPPFLAGS += -DHAVE_CONFIG_H ${LIB_CPPFLAGS} -I.. -I../.. ${GLIB_CFLASG} ${GTK_CFLAGS} ${DBUS_CFLAGS} ${LIBMCS_CFLAGS} ${AUDACIOUS_DEFINES} ${REGEX_CFLAGS}
+CPPFLAGS += -DHAVE_CONFIG_H -I.. -I../.. ${GLIB_CFLASG} ${GTK_CFLAGS} ${DBUS_CFLAGS} ${LIBMCS_CFLAGS} ${AUDACIOUS_DEFINES} ${REGEX_CFLAGS}
CFLAGS += -std=gnu99 ${LIB_CFLAGS}
LDFLAGS += $(AUDLDFLAGS)
LIBS += -lm ${GLIB_LIBS} ${MOWGLI_LIBS} ${GTK_LIBS} ${REGEX_LIBS} -L../libaudcore -laudcore
diff --git a/src/libaudgui/audacious_logo.xpm b/src/libaudgui/audacious_logo.xpm
deleted file mode 100644
index 4cacca2..0000000
--- a/src/libaudgui/audacious_logo.xpm
+++ /dev/null
@@ -1,454 +0,0 @@
-/* XPM */
-static char * audacious_logo_xpm[] = {
-"488 200 251 2",
-" c #FEFEFE",
-". c #FDFDFD",
-"+ c #FCFCFC",
-"@ c #FBFBFB",
-"# c #FAFAFA",
-"$ c #F9F9F9",
-"% c #F8F8F8",
-"& c #F7F7F7",
-"* c #F6F6F6",
-"= c #F5F5F5",
-"- c #F4F4F4",
-"; c #F3F3F3",
-"> c #F2F2F2",
-", c #F1F1F1",
-"' c #EFEFEF",
-") c #EEEEEE",
-"! c #EDEDED",
-"~ c #ECECEC",
-"{ c #EBEBEB",
-"] c #F0F0F0",
-"^ c #E9E9E9",
-"/ c #E7E7E7",
-"( c #E5E5E5",
-"_ c #E4E4E4",
-": c #E3E3E3",
-"< c #E2E2E2",
-"[ c #E1E1E1",
-"} c #E0E0E0",
-"| c #EAEAEA",
-"1 c #E6E6E6",
-"2 c #DFDFDF",
-"3 c #DCDCDC",
-"4 c #DADADA",
-"5 c #D8D8D8",
-"6 c #D6D6D6",
-"7 c #D5D5D5",
-"8 c #D4D4D4",
-"9 c #D3D3D3",
-"0 c #D7D7D7",
-"a c #CFCFCF",
-"b c #CCCCCC",
-"c c #CACACA",
-"d c #C8C8C8",
-"e c #C6C6C6",
-"f c #C5C5C5",
-"g c #C4C4C4",
-"h c #C3C3C3",
-"i c #C2C2C2",
-"j c #C7C7C7",
-"k c #D1D1D1",
-"l c #CBCBCB",
-"m c #BFBFBF",
-"n c #BCBCBC",
-"o c #B8B8B8",
-"p c #B5B5B5",
-"q c #B4B4B4",
-"r c #B1B1B1",
-"s c #B0B0B0",
-"t c #AFAFAF",
-"u c #CDCDCD",
-"v c #AEAEAE",
-"w c #A9A9A9",
-"x c #A4A4A4",
-"y c #A2A2A2",
-"z c #9F9F9F",
-"A c #9C9C9C",
-"B c #9B9B9B",
-"C c #9A9A9A",
-"D c #999999",
-"E c #CECECE",
-"F c #B7B7B7",
-"G c #ADADAD",
-"H c #A5A5A5",
-"I c #9D9D9D",
-"J c #969696",
-"K c #919191",
-"L c #8E8E8E",
-"M c #8A8A8A",
-"N c #888888",
-"O c #878787",
-"P c #868686",
-"Q c #858585",
-"R c #848484",
-"S c #838383",
-"T c #ABABAB",
-"U c #959595",
-"V c #8B8B8B",
-"W c #7D7D7D",
-"X c #797979",
-"Y c #767676",
-"Z c #727272",
-"` c #717171",
-" . c #707070",
-".. c #6F6F6F",
-"+. c #6D6D6D",
-"@. c #757575",
-"#. c #7C7C7C",
-"$. c #C9C9C9",
-"%. c #BBBBBB",
-"&. c #929292",
-"*. c #7B7B7B",
-"=. c #6C6C6C",
-"-. c #656565",
-";. c #616161",
-">. c #5E5E5E",
-",. c #5C5C5C",
-"'. c #5B5B5B",
-"). c #5A5A5A",
-"!. c #585858",
-"~. c #575757",
-"{. c #7A7A7A",
-"]. c #D2D2D2",
-"^. c #636363",
-"/. c #555555",
-"(. c #515151",
-"_. c #4D4D4D",
-":. c #4B4B4B",
-"<. c #4A4A4A",
-"[. c #494949",
-"}. c #484848",
-"|. c #474747",
-"1. c #464646",
-"2. c #505050",
-"3. c #5F5F5F",
-"4. c #545454",
-"5. c #4C4C4C",
-"6. c #454545",
-"7. c #404040",
-"8. c #3C3C3C",
-"9. c #3B3B3B",
-"0. c #3A3A3A",
-"a. c #393939",
-"b. c #383838",
-"c. c #363636",
-"d. c #353535",
-"e. c #444444",
-"f. c #BABABA",
-"g. c #333333",
-"h. c #2F2F2F",
-"i. c #2D2D2D",
-"j. c #2C2C2C",
-"k. c #2B2B2B",
-"l. c #2A2A2A",
-"m. c #282828",
-"n. c #7E7E7E",
-"o. c #6B6B6B",
-"p. c #262626",
-"q. c #242424",
-"r. c #222222",
-"s. c #212121",
-"t. c #202020",
-"u. c #1E1E1E",
-"v. c #1D1D1D",
-"w. c #292929",
-"x. c #373737",
-"y. c #A1A1A1",
-"z. c #8C8C8C",
-"A. c #787878",
-"B. c #666666",
-"C. c #535353",
-"D. c #303030",
-"E. c #1B1B1B",
-"F. c #191919",
-"G. c #181818",
-"H. c #171717",
-"I. c #161616",
-"J. c #151515",
-"K. c #B3B3B3",
-"L. c #898989",
-"M. c #4E4E4E",
-"N. c #3F3F3F",
-"O. c #131313",
-"P. c #121212",
-"Q. c #111111",
-"R. c #0F0F0F",
-"S. c #0E0E0E",
-"T. c #B2B2B2",
-"U. c #737373",
-"V. c #3D3D3D",
-"W. c #313131",
-"X. c #141414",
-"Y. c #101010",
-"Z. c #0C0C0C",
-"`. c #0B0B0B",
-" + c #272727",
-".+ c #2E2E2E",
-"++ c #1A1A1A",
-"@+ c #0A0A0A",
-"#+ c #080808",
-"$+ c #070707",
-"%+ c #090909",
-"&+ c #060606",
-"*+ c #050505",
-"=+ c #0D0D0D",
-"-+ c #040404",
-";+ c #020202",
-">+ c #010101",
-",+ c #000000",
-"'+ c #4F4F4F",
-")+ c #C1C1C1",
-"!+ c #A7A7A7",
-"~+ c #696969",
-"{+ c #D9D9D9",
-"]+ c #808080",
-"^+ c #979797",
-"/+ c #B6B6B6",
-"(+ c #A8A8A8",
-"_+ c #D0D0D0",
-":+ c #A3A3A3",
-"<+ c #7F7F7F",
-"[+ c #949494",
-"}+ c #686868",
-"|+ c #030303",
-"1+ c #AAAAAA",
-"2+ c #323232",
-"3+ c #909090",
-"4+ c #676767",
-"5+ c #9E9E9E",
-"6+ c #252525",
-"7+ c #1F1F1F",
-"8+ c #BDBDBD",
-"9+ c #6E6E6E",
-"0+ c #595959",
-"a+ c #ACACAC",
-"b+ c #818181",
-"c+ c #565656",
-"d+ c #8D8D8D",
-"e+ c #939393",
-"f+ c #A6A6A6",
-"g+ c #525252",
-"h+ c #232323",
-"i+ c #424242",
-"j+ c #B9B9B9",
-"k+ c #989898",
-"l+ c #343434",
-"m+ c #414141",
-"n+ c #1C1C1C",
-"o+ c #777777",
-"p+ c #BEBEBE",
-"q+ c #6A6A6A",
-"r+ c #8F8F8F",
-"s+ c #A0A0A0",
-"t+ c #C0C0C0",
-"u+ c #434343",
-"v+ c #747474",
-"w+ c #3E3E3E",
-"x+ c #646464",
-"y+ c #626262",
-"z+ c #606060",
-"A+ c #828282",
-"B+ c #5D5D5D",
-" . + @ # $ % & * = = - - - ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; - - - = = * & % $ # @ + . ",
-" . + # $ & = - > , ' ) ) ! ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { ~ ~ ~ ~ ~ ~ ~ ~ ~ ! ) ) ' , > - = & $ # + . ",
-" . @ # % = ; ] ! { ^ / ( _ : : < < [ [ [ [ [ [ [ } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } [ [ [ [ [ [ < < < : _ ( / ^ { ! ] ; = % # @ . ",
-". + # & - , ! | 1 < 2 3 4 5 6 7 7 8 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 8 7 7 6 5 4 3 2 < 1 | ! , - & # + . ",
-"+ # % - , ~ / [ 3 0 9 a b c d e f g g h h h h h h i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i h h h h h g g f e j c b a 9 0 3 [ / ~ ] - % # + ",
-"@ $ = , ~ 1 2 5 k l g m n o p q r r s s s t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t t s s r r q p o n m g l k 5 2 ( { , = $ @ ",
-"# & ; ! / 2 6 u g n p v w x y z A A B B C C C C C D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D C C C C C B A A z y x w v p n g u 6 2 / ! ; & # ",
-"$ = ] ^ [ 5 E i F G H I J K L M N O P P Q R R R R S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S R R R R P P O N M L K J I x G F i E 5 [ ^ ] = $ ",
-"% - ) 1 3 k g F T z U V R W X Y Z ` . ...+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+. . .` Z @.X #.R V U z T F g k 3 1 ) - % ",
-"& > { < 0 $.%.G z &.Q *.Z =.-.;.>.,.'.'.).!.!.!.!.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.!.!.!.!.'.'.,.>.;.-.=.Z {.Q K z G %.$.0 < { > & ",
-"* , ^ 2 ].f q H U P X +.^.,./.(._.:.<.[.}.|.|.|.|.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.|.|.|.|.[.<.:._.2./.'.^.+.X P U H q f ].2 ^ ] * ",
-"= ' / 3 a m v B V {.=.3.4.5.6.7.8.9.0.a.b.c.c.c.c.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.c.c.c.c.a.0.9.8.7.e.5.4.3.=.{.V B v m a 3 / ' = ",
-"= ) ( 4 l f.w J S Z ;.4.[.7.a.g.h.i.j.k.l.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.k.j.i.h.g.a.7.[.4.;.` S J w f.l 4 ( ) = ",
-"- ! _ 5 $.F x K n.o.).5.7.b.h.l.p.q.r.s.t.u.u.u.u.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.u.u.u.u.s.r.q.p.w.h.x.7.5.).o.#.K x F $.5 _ ! - ",
-"- ! : 6 j p y.z.A.B.C.6.0.D.m.r.v.E.F.G.H.I.I.I.I.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.J.I.I.I.I.G.F.E.v.r.m.D.a.6.C.B.A.z.y.q j 6 : ! - ",
-"; ~ < 7 f K.z L.@.;.M.N.g.w.s.E.H.J.O.P.Q.R.R.R.R.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.R.R.R.R.P.O.J.H.E.s.w.g.N.M.;.@.L.z T.f 7 < ~ ; ",
-"; ~ < 7 g T.I O U.3._.V.W.m.u.G.X.P.Y.R.S.Z.Z.Z.Z.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.Z.Z.Z.Z.R.Y.P.X.G.u. +W.V._.3.U.O I r g 7 < ~ ; ",
-"; ~ [ 9 h s A O .,.[.9..+q.++J.Y.S.Z.`.@+#+#+#+#+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+#+#+#+#+`.Z.S.Y.J.++q.i.9.[.,. .Q A s h 9 [ ~ ; ",
-"; ~ [ 9 h s B P .'.}.a.j.r.G.O.S.Z.@+%+#+&+&+&+&+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+&+&+&+&+%+@+Z.S.O.G.r.j.a.}.'. .Q C s h 9 [ ~ ; ",
-"; ~ [ 9 i s C Q ..'.}.b.k.s.H.P.=+`.%+#+$+*+*+*+*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*+*+*+*+#+%+`.=+P.H.s.k.b.}.)...R C s i 9 [ ~ ; ",
-"; ~ [ 9 i s C Q ..'.}.b.k.s.H.P.=+`.%+#+$+*+*+*+*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*+*+*+*+#+%+`.=+P.H.s.k.b.}.)...R C s i 9 [ ~ ; ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+F.'+#.A f.d ].6 l )+!+P ;.l.;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+E.~+F {+{+{+{+{+{+{+{+{+{+{+{+{+{+$.]+.+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+k.&.5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v e.;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++&.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v .+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 n.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+R.^+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r t.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++/+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l W.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++C.P (+g _+0 E )+:+<+}.Y.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+t.g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k 9.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+&+4.(+{+{+{+{+{+{+{+{+{+{+{+{+6 [+9.>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+-+W.}+K r d k 6 b m y.]+5.X.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+G.m {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+j.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+~.h {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+1+2+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+m.W d {+{+{+{+{+{+{+{+{+{+{+{+{+y 2.*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+E.C.R x )+u 0 k j s 3+4+h.|+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+%+K.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 s n {+{+{+{+{+{+{+{+{+{+{+{+j F.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+E.C.R x )+u 0 k j s 3+4+h.|+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+s.G {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+Q @+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+k.C {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+)+'.-+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+=+>.v {+{+{+{+{+{+{+{+{+{+{+{+{+j *.p.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+N {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5+r.,+,+ +y {+{+{+{+{+{+{+{+{+{+{+!+|+,+,+,+,+,+,+,+,+,+,+,+,+,+=+>.v {+{+{+{+{+{+{+{+{+{+{+{+{+j *.p.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+6+>.3+s $.9 6 l F J }+h.;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+[._+{+{+{+{+{+{+{+{+{+u S *.f.{+{+{+{+{+{+{+{+{+{+F s.,+,+,+,+,+,+,+,+,+,+,+,+S.S 5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+K.W.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+7+!.M T e k 0 u 8+I @.8.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Z.9+b {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^+l.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+[.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A.>+,+,+,+,+|+K {+{+{+{+{+{+{+{+{+{+{+o.,+,+,+,+,+,+,+,+,+,+,+Z.9+b {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^+l.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+@+3.q {+{+{+{+{+{+{+{+{+{+{+{+8+~+S.,+,+,+,+,+,+,+,+,+,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+y X.,+,+|+;.{+{+{+{+{+{+{+{+{+{+$.h.,+,+,+,+,+,+,+,+,+,+W.m {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 4+;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+$+0+a+{+{+{+{+{+{+{+{+{+{+{+{+u b+6+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+[.g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 n.=+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+$+b. .^+o c 7 8 $./+U +.d.*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+=+g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+8+*+,+,+,+,+,+,+=+a {+{+{+{+{+{+{+{+{+{+9 v.,+,+,+,+,+,+,+,+,+[.g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 n.=+,+,+,+,+,+,+,+,+,+,+,+,+,+-+>.c {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+u ~+&+,+,+,+,+,+,+,+,+,+,+c+{+{+{+{+{+{+{+{+{+{+)+@+,+,+,+,+,+{.{+{+{+{+{+{+{+{+{+{+b +,+,+,+,+,+,+,+,+_.7 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+d+*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+$+b. .^+o c 7 8 $./+U +.d.*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+0+f {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 L ++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+%+N {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+n j.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+j.S u {+{+{+{+{+{+{+{+{+{+{+{+c n.p.,+,+,+,+,+,+,+,+,+,+,+,+Y {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^.,+,+,+,+,+,+,+,+!+{+{+{+{+{+{+{+{+{+{+{+e+,+,+,+,+,+,+,+%+N {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+n j.,+,+,+,+,+,+,+,+,+,+,+q.r {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o l.,+,+,+,+,+,+,+,+x.0 {+{+{+{+{+{+{+{+{+{+U ,+,+,+,+,+,+5.{+{+{+{+{+{+{+{+{+{+{+h O.,+,+,+,+,+,+0+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C -+,+,+,+,+,+,+,+,+,+,+,+,+,+j.S u {+{+{+{+{+{+{+{+{+{+{+{+c n.p.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+r.v {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+>.>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+X.s {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+8 }.,+,+,+,+,+,+,+,+,+,+,+,+,+k.A {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+J 6+,+,+,+,+,+,+,+,+,+O.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+e.,+,+,+,+,+,+,+,+f+{+{+{+{+{+{+{+{+{+{+{+{+6+,+,+,+,+,+X.s {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+8 }.,+,+,+,+,+,+,+,+,+|.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 M.,+,+,+,+,+,+P.f {+{+{+{+{+{+{+{+{+{+{+_+m.,+,+,+,+>+:+{+{+{+{+{+{+{+{+{+{+{+{+5+>+,+,+,+,+5.5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+M >+,+,+,+,+,+,+,+,+,+,+k.A {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+J 6+,+,+,+,+,+,+,+,+,+,+,+,+,+,+}._+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+[+@+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+F.8+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 c+,+,+,+,+,+,+,+,+,+,+%+W 0 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 @.&+,+,+,+,+,+,+,+U.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+e.,+,+,+,+,+,+,+,+K.{+{+{+{+{+{+{+{+{+{+{+{+z.,+,+,+,+F.8+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 c+,+,+,+,+,+,+,+c+5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+,.,+,+,+,+,+L.{+{+{+{+{+{+{+{+{+{+{+{+{+d +,+,+,+g+{+{+{+{+{+{+{+{+{+{+{+{+{+{+2.,+,+,+w.9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+3.,+,+,+,+,+,+,+,+%+W 0 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 @.&+,+,+,+,+,+,+,+,+,+,+,+).5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+a+Q.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Q.F {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 |.,+,+,+,+,+,+,+,+h+p {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v u.,+,+,+,+,+|+f {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k.,+,+,+,+,+,+,+>+l {+{+{+{+{+{+{+{+{+{+{+{+8 S.,+,+Q.F {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 |.,+,+,+,+,+:.5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_.,+,+,+j.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+f i+j.9+9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+e %+,+%+f.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+7 l.,+,+,+,+,+,+h+p {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v u.,+,+,+,+,+,+,+,+,+g+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v `.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+y.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 m.,+,+,+,+,+,+2+l {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+d j.,+,+,+,+7.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 q m d j+).,+,+,+,+,+,+,+,+u.{+{+{+{+{+{+{+{+{+{+{+{+{+{+~.,+|+y.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 m.,+,+,+m.9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+7 f.G &.-.}+S f.{+{+{+{+{+{+8 l.,+,+k+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+3.,+` {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+T ;+,+,+,+,+2+l {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+d j.,+,+,+,+,+,+,+l+6 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+B ;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+=.{+{+{+{+{+{+{+{+{+{+{+c 1+^+V '+W.k..+V.>.L E {+{+{+{+{+{+{+{+{+{+{+{+f.@+,+,+,+,+W.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+a j.,+,+,+b+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l b+m+`.,+,+,+,+,+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+I ,+=.{+{+{+{+{+{+{+{+{+{+{+c 1+^+V '+W.k..+V.>.L E {+{+{+{+{+{+{+{+{+{+{+{+f.@+,+&+F {+{+{+{+{+{+{+{+{+{+{+{+{+y [.#+,+,+,+,+,+,+>+x.a+{+{+{+{+{+f.#+n+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+7 W !.:+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+n E.7 {+{+{+{+{+{+{+{+{+{+{+{+{+{+l A A.o+o+U l {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+(.,+,+,+W.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+a j.,+,+,+,+,+Y.i {+{+{+{+{+{+{+{+{+{+{+{+g C f.G I I I :+p+{+{+{+{+{+{+{+{+{+{+-.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+q.6 {+{+{+{+{+{+{+{+{+8 [.>+,+,+,+,+,+,+,+,+,+,+#+M.p {+{+{+{+{+{+{+{+{+{+{+@.,+,+,+s.l {+{+{+{+{+q k.Q.;.8 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+j u.,+,+f.{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 .%+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+w.6 {+{+{+{+{+{+{+{+{+8 [.>+,+,+,+,+,+,+,+,+,+,+#+M.p {+{+{+{+{+{+{+{+{+{+{+@.,+q+{+{+{+{+{+{+{+{+{+{+{+{+e+7+,+,+,+,+,+,+,+,+,+,+,+-+r+{+{+{+{+{+o.o.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+b W.,+,+;+..{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+q {+{+{+{+{+{+{+{+{+{+{+{+K.;.u.>+,+,+,+,+,+;+m.>.T {+{+{+{+{+{+{+{+{+{+{+{+{+f.|+,+s.l {+{+{+{+{+q k.Q.;.8 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+j u.,+,+,+,+S {+{+{+{+{+{+{+{+{+u P }.J.,+,+,+,+,+,+,+,+,+j./+{+{+{+{+{+{+{+{+8 7+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+s+{+{+{+{+{+{+{+{+{+5 7.,+,+,+,+,+,+,+,+,+,+,+,+,+,+-+=.{+{+{+{+{+{+{+{+{+{+6 t.,+$+T.{+{+{+{+{+t+O.,+,+,+_.{+{+{+{+{+{+{+{+{+f.g.$+6+#.0 {+{+{+{+{+{+t $+O.{+{+{+{+{+{+{+{+{+{+{+{+{+{+f.i.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+{+{+{+{+{+{+{+{+{+5 7.,+,+,+,+,+,+,+,+,+,+,+,+,+,+-+=.{+{+{+{+{+{+{+{+{+{+6 D.a {+{+{+{+{+{+{+{+{+{+$.m+,+,+,+,+,+,+,+,+,+,+,+,+,+,+#+%.{+{+{+{+_+%.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+m+,+,+,+,+,+N {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+e |.;+,+,+,+,+,+,+,+,+,+,+,+>+'+E {+{+{+{+{+{+{+{+{+{+{+{+|.$+T.{+{+{+{+{+t+O.,+,+,+_.{+{+{+{+{+{+{+{+{+f.g.$+6+#.0 {+{+{+{+{+{+t $+,+,+l.5 {+{+{+{+{+{+{+{+o+=+,+,+,+,+,+,+,+,+,+,+,+,+,+S.t {+{+{+{+{+{+{+{+^+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+d.{+{+{+{+{+{+{+{+{+{+k+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+;.{+{+{+{+{+{+{+{+{+{+L.,+A.{+{+{+{+{+6 j.,+,+,+,+>+(+{+{+{+{+{+{+{+_+v.,+,+,+,+a.k {+{+{+{+{+{+@.d.{+{+{+{+{+{+{+{+{+{+{+{+{+w S.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+k.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+;.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+f.7+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+C.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+H ,+,+,+,+,+,+|.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o J.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+r.o {+{+{+{+{+{+{+{+{+{+{+D A.{+{+{+{+{+6 j.,+,+,+,+>+(+{+{+{+{+{+{+{+_+v.,+,+,+,+a.k {+{+{+{+{+{+@.,+,+e+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+n+9 {+{+{+{+{+{+{+{+m.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+B {+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+x {+{+{+{+{+{+{+{+{+6 7.6 {+{+{+{+{+*.,+,+,+,+,+,+'.{+{+{+{+{+{+{+]+,+,+,+,+,+,+'.{+{+{+{+{+{+6 {.{+{+{+{+{+{+{+{+{+{+{+{+b I.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+h+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+x {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l n+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+s.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+@.,+,+,+,+,+,+h.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+E n+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+X.n {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+*.,+,+,+,+,+,+'.{+{+{+{+{+{+{+]+,+,+,+,+,+,+'.{+{+{+{+{+{+6 6+n+{+{+{+{+{+{+{+{+P ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+k+{+{+{+{+{+{+{+{+N ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+G.5 {+{+{+{+{+{+{+{+{+{+_+6+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+u+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k.,+,+,+,+,+,+s.{+{+{+{+{+{+{+_.,+,+,+,+,+,+Z.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+Z ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+p.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+6+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+u+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+N.,+,+,+,+,+,+,+,+-+X.X.X.S.,+,+,+,+>+Q {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+n+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+>.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+t.].{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k.,+,+,+,+,+,+s.{+{+{+{+{+{+{+_.,+,+,+,+,+,+Z.{+{+{+{+{+{+{+^+=.{+{+{+{+{+{+{+0 ++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+%.{+{+{+{+{+{+{+{+a %+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+^.{+{+{+{+{+{+{+{+{+{+{+{+k N A.I !+!+!+f+o+-+,+,+,+,+,+,+,+,+$+9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+$+,+,+,+,+,+,+,+5+{+{+{+{+{+{+0+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6+,+,+,+,+,+,+,+,+>+m+^.<.>+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k N A.I !+!+!+f+o+-+,+,+,+,+,+,+,+,+$+9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+D ,+,+,+,+,+,+,+,+m+h {+{+{+{+:+2+,+Z.P {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+S.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+t+*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+4+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+$+,+,+,+,+,+,+,+5+{+{+{+{+{+{+0+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+0 {+{+{+{+{+{+{+s+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+ .{+{+{+{+{+{+{+{+{+{+e.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+5+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+q.,+,+,+,+,+,+,+,+,+f+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+&+,+,+,+,+,+,+,+..{+{+{+{+{+{+Y ,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l >+,+,+,+,+,+,+,+>+o+{+{+{+W ,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+q.,+,+,+,+,+,+,+,+,+f+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+e.,+,+,+,+,+,+,+q.7 {+{+{+{+{+{+{+t+_+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+P.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+-.,+,+,+,+,+,+,+,+i+U J J r+7+,+,+,+,+,+,+,+%+E {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+&+,+,+,+,+,+,+,+..{+{+{+{+{+{+Y ,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+q+,+,+,+,+,+,+,+,+,+,+h+:+<+h+,+,+&+v+{+{+{+{+{+{+{+{+{+{+{+*.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+_+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k M ^.d.,+,+,+,+,+,+,+,+,+,+b+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+G.,+,+,+,+,+,+,+A.{+{+{+{+{+{+'+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+(+,+,+,+,+,+,+,+>+o+{+{+{+{+{+%+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k M ^.d.,+,+,+,+,+,+,+,+,+,+b+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+X.,+,+,+,+,+,+,+M {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+=.,+,+,+,+,+,+s.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 H.,+,+,+,+,+,+,+4.{+{+{+{+{+g 7+,+,+,+,+,+,+,+O {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+G.,+,+,+,+,+,+,+A.{+{+{+{+{+{+'+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5.,+,+,+,+,+,+,+,+,+,+++z s )+T.s+f {+{+{+{+{+{+{+{+{+{+{+{+(+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+7+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 K ,.w+Z.,+,+,+,+,+,+,+,+,+,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+d.,+,+,+,+,+,+,+U {+{+{+{+{+{+++,+,+,+,+,+,+%+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+L ,+,+,+,+,+,+,+|.{+{+{+{+{+{+E.,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 K ,.w+Z.,+,+,+,+,+,+,+,+,+,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+|+,+,+,+,+,+,+>+l {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+'.,+,+,+,+,+,+q.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+a+,+,+,+,+,+,+,+%+b {+{+{+{+{+{+K ,+,+,+,+,+,+,+C.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+d.,+,+,+,+,+,+,+U {+{+{+{+{+{+++,+,+,+,+,+,+%+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+I.*.{+{+{+{+{+{+{+{+{+{+{+{+{+j ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+7.{+{+{+{+{+{+{+{+{+{+{+{+{+n h.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+N.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+(+{+{+{+{+{+{+|+,+,+,+,+,+,+0.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+<+,+,+,+,+,+,+,+ .{+{+{+{+{+{+d.,+,+,+,+,+,+,+ +{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+n h.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+N.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+&+,+,+,+,+,+,+G.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+..,+,+,+,+,+,+X.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+n.,+,+,+,+,+,+,+[.{+{+{+{+{+{+{+v ,+,+,+,+,+,+,+i+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+(+{+{+{+{+{+{+|+,+,+,+,+,+,+0.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+L ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+o.{+{+{+{+{+{+{+{+{+{+{+{+{+-+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+2.{+{+{+{+{+{+{+{+{+{+{+{+v P.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+:+{+{+{+{+{+)+,+,+,+,+,+,+,+e.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+Z ,+,+,+,+,+,+,+ .{+{+{+{+{+{+a.,+,+,+,+,+,+,+7+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v P.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+X.,+,+,+,+,+,+ +{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+X.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+..,+,+,+,+,+,+,+/.{+{+{+{+{+{+{+(+,+,+,+,+,+,+,+k.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+:+{+{+{+{+{+)+,+,+,+,+,+,+,+e.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 v.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+4.].{+{+{+{+{+{+{+{+{+{+{+S.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+).{+{+{+{+{+{+{+{+{+{+{+p+O.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+g+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+1.,+,+,+,+,+,+,+P {+{+{+{+{+3+,+,+,+,+,+,+,+e.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9+,+,+,+,+,+,+,++.{+{+{+{+{+{+0+,+,+,+,+,+,+,+i.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p+O.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+g+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p.,+,+,+,+,+,+v.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+++{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+#.,+,+,+,+,+,+,+W.{+{+{+{+{+{+{+d+,+,+,+,+,+,+,+&+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+1.,+,+,+,+,+,+,+P {+{+{+{+{+3+,+,+,+,+,+,+,+e.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+D >+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+_.{+{+{+{+{+{+{+{+{+{+{+Y.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+'.{+{+{+{+{+{+{+{+{+{+{+l+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+&.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+x+,+,+,+,+,+,+,+^.{+{+{+{+{+A.,+,+,+,+,+,+,+i+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+,+e.{+{+{+{+{+{++.,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+&.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0.,+,+,+,+,+,+,+e+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+v.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+U ,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+y+,+,+,+,+,+,+,+-+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+x+,+,+,+,+,+,+,+^.{+{+{+{+{+A.,+,+,+,+,+,+,+i+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+z+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+&+b {+{+{+{+{+{+{+{+{+{+*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+(.{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+P.1+o F c.,+,+,+,+,+,+,+,+z {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A+,+,+,+,+,+,+,+|.{+{+{+{+{+~+,+,+,+,+,+,+,+q.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+<+,+,+,+,+,+,+,+*+t+{+{+{+{+{++.,+,+,+,+,+,+,+D.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+P.1+o F c.,+,+,+,+,+,+,+,+z {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+X ,+,+,+,+,+,+,+J.e {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+-+k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+/+,+,+,+,+,+,+,+j.{+{+{+{+{+{+{+6+,+,+,+,+,+,+,+=+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A+,+,+,+,+,+,+,+|.{+{+{+{+{+~+,+,+,+,+,+,+,+q.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 M.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+O {+{+{+{+{+{+{+{+{+u ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+m+{+{+{+{+{+{+{+{+{+{+o+,+,+,+,+,+,+,+,+'+{+{+{++.,+,+,+,+,+,+,+,+/+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+L.,+,+,+,+,+,+,+h+{+{+{+{+{+~.,+,+,+,+,+,+,+%+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+z ,+,+,+,+,+,+,+,+|.{+{+{+{+{+,.,+,+,+,+,+,+,+k.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o+,+,+,+,+,+,+,+,+'+{+{+{++.,+,+,+,+,+,+,+,+/+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+)+|+,+,+,+,+,+,+,+j.E {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+,+r {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+I.,+,+,+,+,+,+*+d {+{+{+{+{+(+,+,+,+,+,+,+,+,+ +{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+L.,+,+,+,+,+,+,+h+{+{+{+{+{+~.,+,+,+,+,+,+,+%+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+<+F.,+,+,+,+,+,+,+,+,+,+,+,+,+,+'+{+{+{+{+{+{+{+{+{+a+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+t.{+{+{+{+{+{+{+{+{+{+o+,+,+,+,+,+,+,+,+w.6 {+7 9.,+,+,+,+,+,+,+;+8 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+^+{+{+{+)+P.,+,+,+,+,+,+,+S.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+a *+,+,+,+,+,+,+,+,+0+k {+{+t Z.,+,+,+,+,+,+,+7+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o+,+,+,+,+,+,+,+,+w.6 {+7 9.,+,+,+,+,+,+,+;+8 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_.,+,+,+,+,+,+,+,+k.A {+{+{+8 d+2.4.f {+{+{+{+{+{+{+` {+{+{+{+{+{+{+{+{+{+{+{+{+ .,+,+,+,+,+,+,+C {+{+{+{+{+{+{+{+{+{+{+{+c x {+{+{+{+{+{+{+{+_.,+,+,+,+,+,+,+x+{+{+{+{+5 l+,+,+,+,+,+,+,+,+x+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+^+{+{+{+)+P.,+,+,+,+,+,+,+S.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 U n.N.-+,+,+,+,+,+,+,+,+,+,+C.{+{+{+{+{+{+{+{+{+S ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+-+].{+{+{+{+{+{+{+{+{+*.,+,+,+,+,+,+,+,+,+r.C.2+,+,+,+,+,+,+,+,+#+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+$+}+r+#.P.,+,+,+,+,+,+,+,+@+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+i+,+,+,+,+,+,+,+,+,+H.}+(.*+,+,+,+,+,+,+,+,+R.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+*.,+,+,+,+,+,+,+,+,+r.C.2+,+,+,+,+,+,+,+,+#+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+%.*+,+,+,+,+,+,+,+,+,+`.S.S.#+,+,+,+h+k {+{+{+{+{+l $+z.{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+@.{+{+{+{+{+{+{+{+{+{+{+{+~.g+{+{+{+{+{+{+{+{+X ,+,+,+,+,+,+,+>+Z 5 {+0 >.,+,+,+,+,+,+,+,+&+)+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r+,+,+,+,+,+,+,+,+$+}+r+#.P.,+,+,+,+,+,+,+,+@+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+7 [+e+T.5 {+{+{+z.,+,+,+,+,+,+,+,+,+,+@.{+{+{+{+{+{+{+{+{+<.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+y.{+{+{+{+{+{+{+{+{+v ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+f.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+f+a {+{+{+{+{+{+{+{+{+y >+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+i {+{+{+{+{+{+{+{+{+{+{+{+9 {+{+{+{+{+{+{+{+{+v ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+f.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+I {+{+{+{+{+#.,+X.d {+{+{+{+{+{+{+{+{+{+{+g.,+,+,+,+,+,+,+<.{+{+{+{+{+{+{+{+{+{+{+:+;+`._+{+{+{+{+{+{+{+m |+,+,+,+,+,+,+,+,+6+C.q.,+,+,+,+,+,+,+,+,+o.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+^+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k .+,+,+,+Y.N.m+m+r.,+,+,+,+,+,+,+,+,+*+m {+{+{+{+{+{+{+{+9 S.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+4+{+{+{+{+{+{+{+{+{+{+++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Q {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l #+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+ .U.{+{+{+{+{+{+{+{+{+{+i+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+G {+{+{+{+{+{+{+{+{+{+{+s+4+{+{+{+{+{+{+{+{+{+{+++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Q {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+E u.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+*+e {+{+{+{+8 F.,+,+V.{+{+{+{+{+{+{+{+{+{+{+c+,+,+,+,+,+,+,+e.{+{+{+{+{+{+{+{+{+{+f J.,+,+{.{+{+{+{+{+{+{+{+_.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+i.7 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l #+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+..{+{+{+{+{+{+{+{+{+L ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++{+{+{+{+{+{+{+{+{+{+W ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+3+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+x+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+#+{+{+{+{+{+{+{+{+{+b.`.g {+{+{+{+{+{+{+{+{+f ++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+r.6 {+{+{+{+{+{+{+{+{+{+6 p.++{+{+{+{+{+{+{+{+{+{+W ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+3+{+{+{+{+{+{+{+{+{+_+{+{+{+{+{+{+{+{+{+{+F n+,+,+,+,+,+,+,+,+,+,+,+,+,+,+z+{+{+{+{+{+Y ,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+p+%+,+,+,+,+,+,+b+{+{+{+{+{+{+{+{+{+a i.,+,+,+H.9 {+{+{+{+{+{+{+e G.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+J.m {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+x+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+#+{+{+{+{+{+{+{+{+{+b {+{+{+{+{+{+]+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+w+5 {+{+{+{+{+{+{+{+{+.+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+z {+{+{+{+{+{+{+{+{+{+c+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++_+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+_+++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+d.{+{+{+{+{+{+{+{+u $+,+[.{+{+{+{+{+{+{+{+{+{+j+7+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+R.q {+{+{+{+{+{+{+{+{+{+{+@.,+,+z {+{+{+{+{+{+{+{+{+{+c+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++_+{+{+{+{+{+{+{+{+0 s.q {+{+{+{+{+{+{+{+{+{+_+o.S.,+,+,+,+,+,+,+,+,+,+,+_.6 {+{+{+{+m %+,+,+,+,+,+4+{+{+{+{+{+{+{+{+{+{+z.|+,+,+,+,+8.6 {+{+{+{+{+{+{+{+b l+,+,+,+,+,++.{+{+{+{+{+{+{+{+p ++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+R.r {+{+{+{+{+{+{+{+{+f.9 {+{+{+{+{+{+{+{+_+++,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+d.{+{+{+{+{+{+{+{+u 2+{+{+{+{+{+{+l Y.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+h+u {+{+{+{+{+{+{+{+{+B ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+b.{+{+{+{+{+{+{+{+{+{+{+{.&+,+,+,+,+,+>+j.9+L 3+6.;+,+,+,+G.q {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+(+&+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+]+{+{+{+{+{+{+{+{+S ,+,+,+M {+{+{+{+{+{+{+{+{+{+E y+&+,+,+,+,+,+v.M l k F *.a.$+,+H.G {+{+{+{+{+{+{+{+{+{+{+t $+,+,+b.{+{+{+{+{+{+{+{+{+{+{+{.&+,+,+,+,+,+>+j.9+L 3+6.;+,+,+,+G.q {+{+{+{+{+{+{+{+{+z.,+p.9 {+{+{+{+{+{+{+{+{+{+{+_+&.b+b+]+'+7+%+|+X.6.I {+{+{+{+{+7 h.,+,+,+,+,+,+,+g+9 {+{+{+{+{+{+{+{+{+:+8.%+E.9+6 {+{+{+{+{+{+{+{+n 6+,+,+,+,+,+,+#+o {+{+{+{+{+{+{+{+c _.>+,+,+,+,+,+,+,+,+,+,+,+,+++q {+{+{+{+{+{+{+{+{+0 D.O {+{+{+{+{+{+{+{+{+(+&+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+]+{+{+{+{+{+{+{+{+S ,+P {+{+{+{+{+{+B $+,+,+,+,+,+,+,+,+,+,+,+,+,+w.8+{+{+{+{+{+{+{+{+{+7 s.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+:+{+{+{+{+{+{+{+{+{+{+{+r C.S.,+|+/.q {+{+{+{+{+o =.4.{.E {+{+{+{+{+{+{+{+{+6 C.{+{+{+{+{+{+{+{+{+{+J $+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.6 {+{+{+{+{+{+{+{+j.,+,+,+`.F {+{+{+{+{+{+{+{+{+{+{+t+9+u+x.N.A+7 {+{+{+{+{+{+{+b {+{+{+{+{+{+{+{+{+{+{+{+b u.,+,+,+>+:+{+{+{+{+{+{+{+{+{+{+{+r C.S.,+|+/.q {+{+{+{+{+o =.4.{.E {+{+{+{+{+{+{+{+{+6 h+,+,+5.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C.,+,+,+,+,+,+,+,+,+m.q {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+L.Z.,+,+,+,+,+,+,+,+m.9 {+{+{+{+{+{+{+{+{+C 6+,+,+,+,+,+,+,+,+,+;+M.l {+{+{+{+{+{+{+{+{+{+x+,+D.{+{+{+{+{+{+{+{+{+{+J $+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.6 {+{+{+{+{+{+{+{+j.,+Q.g {+{+{+{+{+{+K.y+[.Y.,+,+,+,+,+,+,+,+6+A+6 {+{+{+{+{+{+{+{+{+{+q+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+p.6 {+{+{+{+{+{+{+{+{+{+{+{+7 q )+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o+,+s+{+{+{+{+{+{+{+{+{+{+t l+,+,+,+,+|+b.L v v v v R e.0.@.].{+{+{+{+{+{+{+{+A ,+,+,+,+,+n+f {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+].l+,+,+,+,+,+p.6 {+{+{+{+{+{+{+{+{+{+{+{+7 q )+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+o+,+,+,+,+,.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+3.,+,+,+,+,+,+,+,+,+,+,+-+;.$.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+v c.,+,+,+,+,+,+,+,+,+,+,+_.{+{+{+{+{+{+{+{+{+{+5 z./.4.w+V.V.6.'.*.n {+{+{+{+{+{+{+{+{+{+{+d+;+,+,+s+{+{+{+{+{+{+{+{+{+{+t l+,+,+,+,+|+b.L v v v v R e.0.@.].{+{+{+{+{+{+{+{+A ,+,+,+x.6 {+{+{+{+{+{+{+{+0 a+z.x+w+V.|.]+f.{+{+{+{+{+{+{+{+{+{+{+{+5+|+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+..{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+%.`.,+i.5 {+{+{+{+{+{+{+{+{+{+{+f+z+0+M e {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 k.,+,+,+,+,+,+m.$.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+8 N.,+,+,+,+,+,+,+..{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+%.`.,+,+,+,+,+2.8 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 _.,+,+,+,+,+,+,+,+,+,+,+,+,+,+@+3.K.{+{+{+{+{+{+{+{+{+{+{+{+8 [+0.>+,+,+,+,+,+,+,+,+,+,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+C *+,+,+,+i.5 {+{+{+{+{+{+{+{+{+{+{+f+z+0+M e {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 k.,+,+,+,+/.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+T.S.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+:+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 l.,+,+,+]+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+W ,+,+,+,+,+,+,+,+r.t+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l d.,+,+,+,+,+,+,+,+|+:+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+9 l.,+,+,+,+,+,+,+j.f.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p m.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+q.,.z.v d ].0 E m y.*.1.S.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+4.0 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+z.*+,+,+,+,+,+]+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+W ,+,+,+,+,+,+>.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+r X.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+P.j+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 <.,+,+,+,+@+o {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p %+,+,+,+,+,+,+,+,+,+I.x {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+q r.,+,+,+,+,+,+,+,+,+,+P.j+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 <.,+,+,+,+,+,+,+,+,+#+.._+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+b x+*+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+b.f {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+6 -.;+,+,+,+,+,+,+@+o {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p %+,+,+,+,+,+,+,+5.k {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A =+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+++m {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0+,+,+,+,+,+,+p.u {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l h+,+,+,+,+,+,+,+,+,+,+,+|+..6 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 W #+,+,+,+,+,+,+,+,+,+,+,+,+++m {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0+,+,+,+,+,+,+,+,+,+,+,+,+P...)+{+{+{+{+{+{+{+{+{+{+{+{+j+x+=+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+X.L {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+s .+,+,+,+,+,+,+,+,+,+p.u {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l h+,+,+,+,+,+,+,+,+,+6+s {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+].x+;+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+I.T.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+7 :.,+,+,+,+,+,+,+,+c.9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k 2+,+,+,+,+,+,+,+,+,+,+,+,+,+,+6+H {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+w j.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+I.T.{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+7 :.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+|+g.q+^+j+b 6 8 c K.&.y+l.>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+x.!+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+m !.|+,+,+,+,+,+,+,+,+,+,+,+c.9 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k 2+,+,+,+,+,+,+,+,+,+,+,+|+3.d {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+e+n+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+`.V {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p+.+,+,+,+,+,+,+,+,+,+,+c.E {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l W.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+V.(+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+f+N.>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+`.V {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+p+.+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+d.M _+{+{+{+{+{+{+{+{+{+{+{+{+0 I _.-+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.E {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+l W.,+,+,+,+,+,+,+,+,+,+,+,+,+,+@+3.q {+{+{+{+{+{+{+{+{+{+{+{+b A+6+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+<.g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 ]+=+,+,+,+,+,+,+,+,+,+,+,+,+p.o {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+K.s.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+k.#.e {+{+{+{+{+{+{+{+{+{+{+{+{+{+i o+w.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+<.g {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+5 ]+=+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+%+9.` ^+F c 8 6 b 8+z *.|.P.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+p.o {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+K.s.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+6+>.r+s $.9 0 u n A U.8.$+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Z...b {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k+k.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+@+]+5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 {.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+;+p.B+Q H t+l 6 7 l p+y b+!.s.>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+Z...b {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+k+k.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+@+]+5 {+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+0 {.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+=+>.t {+{+{+{+{+{+{+{+{+{+{+{+{+d #.p.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+i.s+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A m.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+=+>.t {+{+{+{+{+{+{+{+{+{+{+{+{+d #.p.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+i.s+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+{+A m.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+n+4.R H i E 0 ].d T.K }+W.-+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.O a {+{+{+{+{+{+{+{+{+{+{+{+E Q j.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+n+4.R H i E 0 ].d T.K }+W.-+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+D.O a {+{+{+{+{+{+{+{+{+{+{+{+E Q j.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+%+9.` k+j+l 6 7 l o k+ .0.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+%+9.` k+j+l 6 7 l o k+ .0.#+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.:+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.a+{+g+,+,+,+,+,+,+,+{+b +.+.+.J {+:++.+.+.m {+E.,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.+.+.w.,+{+m ,+,+{+b +.+.+.+.+.+.+.w.,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.:+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.a+{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+b +.+.+.+.+.:+{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+b +.+.+.+.+.:+{+g+,+{+b +.+.+.+.+.:+{+g+,+,+,+,+,+,+,+{+b +.+.+.+.+.+.+.w.,+{+m ,+,+,+,+,++.{+g+,+{+b +.+.+.+.+.+.+.w.,+{+b +.+.+.+.+.+.+.w.,+{+b +.+.+.+.+.:+{+g+,++.+.+.N {+r +.+.+.w.,+{+m ,+,+{+b +.+.+.+.+.:+{+g+,+{+b +.+.+.+.+.:+{+g+,+{+b +.+.+.+.+.+.+.w.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+n.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+n.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+_+N N N N N r {+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+_+N N N N N U.g+7+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+_+N N N N N N N g.,+{+m ,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+_+N N N N N r {+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+_+N N N N N U.g+7+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+_+N N N N N r {+g+,+{+_+N N N N N r {+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+_+N N N N N e.,+,+,+g+0+N N N N N +.g+7+,+{+m ,+,+,+,+,+,+,+,+,+{+_+N N N N N e.,+,+,+{+_+N N N N N r {+g+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+_+N N N N N N N g.,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{++.,+,+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{++.,+,+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+{+{+{+{+{+{++.,+,+,+,+E.{+{+{+{+{++.,+,+,+{+m ,+,+,+,+,+,+,+,+,+{+{+{+{+{+{+{++.,+,+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.c.c.3.{+I c.c.c.X.,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+f c.c.c.c.c.+.:+V.,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+c.c.c.c.c.c.c.N {+g+,+{+m ,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.c.c.c.c.c.c.N {+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+f c.c.c.c.c.+.:+V.,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+f c.c.c.c.c.N {+g+,+c.c.c.c.c.c.c.N {+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+f c.c.c.c.c.E.,+,+,+:+J c.c.c.c.c.+.:+V.,+{+m ,+,+,+,+,+,+,+,+,+{+f c.c.c.c.c.E.,+,+,+{+f c.c.c.c.c.c.c.X.,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+c.c.c.c.c.c.c.N {+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,++.{+g+,+{+m ,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+m ,+,+,+,+,++.{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,++.{+g+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+6 m m m m m b {+g+,+{+6 m m m m m b {+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+6 m m m m m b {+g+,+m m m m m m m b {+g+,+{+m ,+,+{+6 m m m m m m m |.,+{+m ,+,+,+,+,+,+,+,+m m m m m m m b {+g+,+{+6 m m m m m b {+g+,+{+6 m m m m m b {+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+6 m m m $.{+b m m m 9 {+E.,+{+m ,+,+,+,+,++.{+g+,+m m m m m m m b {+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+6 m m m m m b {+g+,+,+,+,+,+,+,+{+6 m m m m m m m |.,+{+m ,+,+,+,+,++.{+g+,+{+6 m m m m m m m |.,+{+6 m m m m m m m |.,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+6 m m m m m b {+g+,+{+m ,+,+,+,+,++.{+g+,+m m m m m m m b {+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+m ,+,+,+g+{++.,+,+,+:+{+E.,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+{+{+{+{+E.,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+,+,+,+,+,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+c.{+N ,+,+,+,+,+{+m ,+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,++.{+g+,+{+{+{+{+{+{+{+{+{+g+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+{+m ,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; { } 9 i t D S +.~.1.d.m.v.J.S.`.$+*+-+-+>+>+>+>+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+,+>+>+>+>+-+*+$+%+S.X.v.m.d.e.~.+.S D v i 9 } { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i t D S +.!.|.c.m.u.J.R.Z.#+&+*+-+;+;+;+;+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+;+;+;+;+*+&+#+@+R.J.u.m.d.6.!.+.S D t i 9 [ { > ",
-"; ~ [ 9 i s C Q ..'.}.b.k.s.H.P.=+`.%+#+$+*+*+*+*+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*+*+*+*+#+%+`.=+P.H.s.k.b.}.)...R C s i 9 [ ~ ; ",
-"; ~ [ 9 h s B P .'.}.a.j.r.G.O.S.Z.@+%+#+&+&+&+&+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+&+&+&+&+%+@+Z.S.O.G.r.j.a.}.'. .Q C s h 9 [ ~ ; ",
-"; ~ [ 9 h s A O .,.[.9..+q.++J.Y.S.Z.`.@+#+#+#+#+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+#+#+#+#+`.Z.S.Y.J.++q.i.9.[.,. .Q A s h 9 [ ~ ; ",
-"; ~ [ 8 g r A O Z B+:.8.h.p.n+H.P.Y.S.=+Z.@+@+@+@+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+%+@+@+@+@+=+S.Y.P.H.n+6+h.8.:.B+Z P A r g 8 [ ~ ; ",
-"; ~ < 7 f K.z L.@.;.M.N.g.w.s.E.H.J.O.P.Q.R.R.R.R.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.R.R.R.R.P.O.J.H.E.s.w.g.N.M.;.@.L.z T.f 7 < ~ ; ",
-"- ! : 6 j q s+z.A.-.C.e.a.h. +s.n+++G.H.H.J.J.J.J.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.J.J.J.J.H.G.++n+s. +h.a.e.C.-.A.z.s+q j 6 : ! - ",
-"- ! _ 5 $.F x K n.o.).5.7.b.h.l.p.q.r.s.t.u.u.u.u.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.u.u.u.u.s.r.q.p.w.h.x.7.5.).o.#.K x F $.5 _ ! - ",
-"= ) ( 4 l f.w J S Z ;.4.[.7.a.g.h.i.j.k.l.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.k.j.i.h.g.a.7.[.4.;.` S J w f.l 4 ( ) = ",
-"= ' / 3 a m v B V {.=.3.4.5.6.7.8.9.0.a.b.c.c.c.c.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.c.c.c.c.a.0.9.8.7.e.5.4.3.=.{.V B v m a 3 / ' = ",
-"* ] ^ 2 ].g q x U Q A.o.;.'.C.'+:.[.}.}.|.6.6.6.6.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.6.6.6.6.}.}.[.:.M.C.).;.o.A.Q U x q g ].2 ^ ] * ",
-"& > { < 0 $.%.G z &.Q *.Z =.-.;.>.,.'.'.).!.!.!.!.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.~.!.!.!.!.'.'.,.>.;.-.=.Z {.Q K z G %.$.0 < { > & ",
-"% - ) 1 3 k g F T z U V R W X Y Z ` . ...+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+. . .` Z @.X #.R V U z T F g k 3 1 ) - % ",
-"$ = ] ^ [ 5 E i F G H I J K L M N O P P Q R R R R S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S R R R R P P O N M L K J I x G F i E 5 [ ^ ] = $ ",
-"# & ; ! / 2 6 u g n p v w x y z A A B B C C C C C D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D D C C C C C B A A z y x w v p n g u 6 2 / ! ; & # ",
-"@ $ = , { ( 2 0 _+c g m %.F p K.r s s t t t t t t v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v v t t t t t s s r K.p F %.m g c _+0 2 ( { , = $ @ ",
-"+ # % - , ~ 1 [ 3 0 9 a l $.j e g g h h h i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i i h h g g e j $.l a 9 0 3 [ 1 ~ ] - % # + ",
-". + # & - , ! | 1 < 2 3 4 5 6 7 7 8 8 8 8 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 8 8 8 7 7 6 5 4 3 2 < 1 | ! , - & # + . ",
-" . @ # % = ; ] ! { ^ / ( _ : : < < [ [ [ [ [ [ [ } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } [ [ [ [ [ [ < < < : _ ( / ^ { ! ] ; = % # @ . ",
-" . @ # $ & = - > ] ' ) ! ! ~ ~ ~ ~ ~ ~ { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { ~ ~ ~ ~ ~ ! ! ) ' ] > - = & $ # @ . ",
-" . + @ # $ % & * = = - - ; ; ; ; ; ; ; ; ; ; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > ; ; ; ; ; ; ; ; ; - - = = * & % $ # @ + . "};
diff --git a/src/libaudgui/confirm.c b/src/libaudgui/confirm.c
index 1b9c474..2330c07 100644
--- a/src/libaudgui/confirm.c
+++ b/src/libaudgui/confirm.c
@@ -1,6 +1,6 @@
/*
* libaudgui/confirm.c
- * Copyright 2010 John Lindgren
+ * Copyright 2010-2011 John Lindgren
*
* This file is part of Audacious.
*
@@ -19,7 +19,10 @@
* using our public API to be a derived work.
*/
+#include <gtk/gtk.h>
+
#include <audacious/audconfig.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/playlist.h>
@@ -86,9 +89,7 @@ void audgui_confirm_playlist_delete (gint playlist)
button = gtk_button_new_from_stock (GTK_STOCK_YES);
gtk_box_pack_end ((GtkBox *) hbox, button, FALSE, FALSE, 0);
-#if GTK_CHECK_VERSION (2, 18, 0)
gtk_widget_set_can_default (button, TRUE);
-#endif
gtk_widget_grab_default (button);
gtk_widget_grab_focus (button);
g_signal_connect ((GObject *) button, "clicked", (GCallback)
@@ -98,3 +99,32 @@ void audgui_confirm_playlist_delete (gint playlist)
gtk_widget_show_all (window);
}
+
+static void rename_cb (GtkDialog * dialog, gint resp, void * list)
+{
+ if (resp == GTK_RESPONSE_ACCEPT && GPOINTER_TO_INT (list) <
+ aud_playlist_count ())
+ aud_playlist_set_title (GPOINTER_TO_INT (list), gtk_entry_get_text
+ ((GtkEntry *) g_object_get_data ((GObject *) dialog, "entry")));
+
+ gtk_widget_destroy ((GtkWidget *) dialog);
+}
+
+void audgui_show_playlist_rename (gint playlist)
+{
+ GtkWidget * dialog = gtk_dialog_new_with_buttons (_("Rename Playlist"),
+ NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT, NULL);
+ gtk_dialog_set_default_response ((GtkDialog *) dialog, GTK_RESPONSE_ACCEPT);
+
+ GtkWidget * entry = gtk_entry_new ();
+ gtk_entry_set_text ((GtkEntry *) entry, aud_playlist_get_title (playlist));
+ gtk_entry_set_activates_default ((GtkEntry *) entry, TRUE);
+ gtk_box_pack_start ((GtkBox *) gtk_dialog_get_content_area ((GtkDialog *)
+ dialog), entry, FALSE, FALSE, 0);
+ g_object_set_data ((GObject *) dialog, "entry", entry);
+
+ g_signal_connect (dialog, "response", (GCallback) rename_cb, GINT_TO_POINTER
+ (playlist));
+ gtk_widget_show_all (dialog);
+}
diff --git a/src/libaudgui/effects-menu.c b/src/libaudgui/effects-menu.c
index 93fc18f..67cc118 100644
--- a/src/libaudgui/effects-menu.c
+++ b/src/libaudgui/effects-menu.c
@@ -27,13 +27,26 @@
#include "libaudgui-gtk.h"
-static void enable_cb (GtkCheckMenuItem * item, PluginHandle * plugin)
+static gboolean watch_cb (PluginHandle * plugin, GtkCheckMenuItem * item)
{
- aud_effect_plugin_enable (plugin, gtk_check_menu_item_get_active (item));
+ gboolean enabled = aud_plugin_get_enabled (plugin);
+ gtk_check_menu_item_set_active (item, enabled);
GtkWidget * settings = g_object_get_data ((GObject *) item, "settings");
if (settings != NULL)
- gtk_widget_set_sensitive (settings, gtk_check_menu_item_get_active (item));
+ gtk_widget_set_sensitive (settings, enabled);
+
+ return TRUE;
+}
+
+static void enable_cb (GtkCheckMenuItem * item, PluginHandle * plugin)
+{
+ aud_plugin_enable (plugin, gtk_check_menu_item_get_active (item));
+}
+
+static void destroy_cb (GtkCheckMenuItem * item, PluginHandle * plugin)
+{
+ aud_plugin_remove_watch (plugin, (PluginForEachFunc) watch_cb, item);
}
static void settings_cb (GtkMenuItem * settings, PluginHandle * plugin)
@@ -53,7 +66,9 @@ static gboolean add_item_cb (PluginHandle * plugin, GtkWidget * menu)
gtk_check_menu_item_set_active ((GtkCheckMenuItem *) item,
aud_plugin_get_enabled (plugin));
gtk_menu_shell_append ((GtkMenuShell *) menu, item);
+ aud_plugin_add_watch (plugin, (PluginForEachFunc) watch_cb, item);
g_signal_connect (item, "toggled", (GCallback) enable_cb, plugin);
+ g_signal_connect (item, "destroy", (GCallback) destroy_cb, plugin);
gtk_widget_show (item);
if (aud_plugin_has_configure (plugin))
diff --git a/src/libaudgui/icons-stock.c b/src/libaudgui/icons-stock.c
index c96daf3..fd25c94 100644
--- a/src/libaudgui/icons-stock.c
+++ b/src/libaudgui/icons-stock.c
@@ -23,21 +23,25 @@
#include <gdk/gdk.h>
#include <gtk/gtk.h>
+#include <audacious/misc.h>
-static void
-load_stock_icon(gchar *id, gchar *filename, GtkIconFactory *iconfactory)
+static void load_stock_icon (gchar * id, gchar * filename,
+ GtkIconFactory * iconfactory)
{
- GtkIconSet *iconset;
- GdkPixbuf *pixbuf;
+ gchar * path = g_strdup_printf ("%s/images/%s",
+ aud_get_path (AUD_PATH_DATA_DIR), filename);
- pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
+ GdkPixbuf * pixbuf = gdk_pixbuf_new_from_file (path, NULL);
if (pixbuf == NULL)
- return;
+ goto ERR;
- iconset = gtk_icon_set_new_from_pixbuf(pixbuf);
+ GtkIconSet * iconset = gtk_icon_set_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
gtk_icon_factory_add(iconfactory, id, iconset);
+
+ERR:
+ g_free (path);
}
void
@@ -46,14 +50,13 @@ audgui_register_stock_icons(void)
GtkIconFactory *iconfactory = gtk_icon_factory_new();
load_stock_icon(AUD_STOCK_PLAYLIST,
- DATA_DIR "/images/menu_playlist.png", iconfactory);
+ "menu_playlist.png", iconfactory);
load_stock_icon(AUD_STOCK_PLUGIN,
- DATA_DIR "/images/menu_plugin.png", iconfactory);
+ "menu_plugin.png", iconfactory);
load_stock_icon(AUD_STOCK_QUEUETOGGLE,
- DATA_DIR "/images/menu_queue_toggle.png", iconfactory);
+ "menu_queue_toggle.png", iconfactory);
load_stock_icon(AUD_STOCK_RANDOMIZEPL,
- DATA_DIR "/images/menu_randomize_playlist.png", iconfactory);
-
+ "menu_randomize_playlist.png", iconfactory);
gtk_icon_factory_add_default( iconfactory );
g_object_unref( iconfactory );
diff --git a/src/libaudgui/iface-menu.c b/src/libaudgui/iface-menu.c
index 3a9b76d..24b2834 100644
--- a/src/libaudgui/iface-menu.c
+++ b/src/libaudgui/iface-menu.c
@@ -28,13 +28,12 @@
static void switch_cb (GtkMenuItem * item, PluginHandle * plugin)
{
if (gtk_check_menu_item_get_active ((GtkCheckMenuItem *) item))
- aud_iface_plugin_set_active (plugin);
+ aud_plugin_enable (plugin, TRUE);
}
typedef struct {
GtkWidget * menu;
GSList * group;
- PluginHandle * active_plugin;
} IfaceMenuAddState;
static gboolean add_item_cb (PluginHandle * plugin, IfaceMenuAddState * state)
@@ -42,7 +41,7 @@ static gboolean add_item_cb (PluginHandle * plugin, IfaceMenuAddState * state)
GtkWidget * item = gtk_radio_menu_item_new_with_label (state->group,
aud_plugin_get_name (plugin));
state->group = gtk_radio_menu_item_get_group ((GtkRadioMenuItem *) item);
- if (plugin == state->active_plugin)
+ if (aud_plugin_get_enabled (plugin))
gtk_check_menu_item_set_active ((GtkCheckMenuItem *) item, TRUE);
gtk_menu_shell_append ((GtkMenuShell *) state->menu, item);
g_signal_connect (item, "activate", (GCallback) switch_cb, plugin);
@@ -52,8 +51,7 @@ static gboolean add_item_cb (PluginHandle * plugin, IfaceMenuAddState * state)
GtkWidget * audgui_create_iface_menu (void)
{
- IfaceMenuAddState state = {gtk_menu_new (), NULL,
- aud_iface_plugin_get_active ()};
+ IfaceMenuAddState state = {gtk_menu_new (), NULL};
aud_plugin_for_each (PLUGIN_TYPE_IFACE, (PluginForEachFunc) add_item_cb,
& state);
return state.menu;
diff --git a/src/libaudgui/infopopup.c b/src/libaudgui/infopopup.c
index 55110af..f9c42eb 100644
--- a/src/libaudgui/infopopup.c
+++ b/src/libaudgui/infopopup.c
@@ -25,8 +25,8 @@
#include <string.h>
#include <audacious/audconfig.h>
-#include <audacious/compatibility.h>
#include <audacious/drct.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/misc.h>
#include <audacious/playlist.h>
@@ -35,7 +35,16 @@
#include "libaudgui.h"
#include "libaudgui-gtk.h"
-#define DEFAULT_ARTWORK DATA_DIR "/images/audio.png"
+static const gchar * get_default_artwork (void)
+{
+ static gchar * path = NULL;
+ if (! path)
+ path = g_strdup_printf ("%s/images/audio.png",
+ aud_get_path (AUD_PATH_DATA_DIR));
+ return path;
+}
+
+#define DEFAULT_ARTWORK (get_default_artwork ())
static GtkWidget * infopopup = NULL;
@@ -246,8 +255,6 @@ static void infopopup_create (void)
/* track progress */
infopopup_progress = gtk_progress_bar_new ();
- gtk_progress_bar_set_orientation ((GtkProgressBar *) infopopup_progress,
- GTK_PROGRESS_LEFT_TO_RIGHT);
gtk_progress_bar_set_text ((GtkProgressBar *) infopopup_progress, "");
gtk_table_attach ((GtkTable *) infopopup_data_table, infopopup_progress, 0,
2, 7, 8, GTK_FILL, 0, 0, 0);
diff --git a/src/libaudgui/infowin.c b/src/libaudgui/infowin.c
index c103aba..13d1c47 100644
--- a/src/libaudgui/infowin.c
+++ b/src/libaudgui/infowin.c
@@ -26,6 +26,7 @@
#include <stdarg.h>
#include <audacious/audconfig.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/misc.h>
#include <audacious/playlist.h>
@@ -36,7 +37,7 @@
#include "libaudgui.h"
#include "libaudgui-gtk.h"
-#define STATUS_TIMEOUT 3000
+#define AUDGUI_STATUS_TIMEOUT 3000
static GtkWidget * infowin = NULL;
@@ -51,14 +52,11 @@ static GtkWidget * entry_genre;
static GtkWidget * image_artwork;
-static GtkWidget * image_fileicon;
static GtkWidget * label_format_name;
static GtkWidget * label_quality;
static GtkWidget * label_bitrate;
static GtkWidget * btn_apply;
static GtkWidget * label_mini_status;
-static GtkWidget * arrow_rawdata;
-static GtkWidget * treeview_rawdata;
enum
{
@@ -68,55 +66,53 @@ enum
};
static gchar * current_file = NULL;
-static InputPlugin * current_decoder = NULL;
+static PluginHandle * current_decoder = NULL;
static gboolean can_write = FALSE, something_changed = FALSE;
-static const gchar * genre_table[] =
-{
- N_("Blues"), N_("Classic Rock"), N_("Country"), N_("Dance"),
- N_("Disco"), N_("Funk"), N_("Grunge"), N_("Hip-Hop"),
- N_("Jazz"), N_("Metal"), N_("New Age"), N_("Oldies"),
- N_("Other"), N_("Pop"), N_("R&B"), N_("Rap"), N_("Reggae"),
- N_("Rock"), N_("Techno"), N_("Industrial"), N_("Alternative"),
- N_("Ska"), N_("Death Metal"), N_("Pranks"), N_("Soundtrack"),
- N_("Euro-Techno"), N_("Ambient"), N_("Trip-Hop"), N_("Vocal"),
- N_("Jazz+Funk"), N_("Fusion"), N_("Trance"), N_("Classical"),
- N_("Instrumental"), N_("Acid"), N_("House"), N_("Game"),
- N_("Sound Clip"), N_("Gospel"), N_("Noise"), N_("AlternRock"),
- N_("Bass"), N_("Soul"), N_("Punk"), N_("Space"),
- N_("Meditative"), N_("Instrumental Pop"),
- N_("Instrumental Rock"), N_("Ethnic"), N_("Gothic"),
- N_("Darkwave"), N_("Techno-Industrial"), N_("Electronic"),
- N_("Pop-Folk"), N_("Eurodance"), N_("Dream"),
- N_("Southern Rock"), N_("Comedy"), N_("Cult"),
- N_("Gangsta Rap"), N_("Top 40"), N_("Christian Rap"),
- N_("Pop/Funk"), N_("Jungle"), N_("Native American"),
- N_("Cabaret"), N_("New Wave"), N_("Psychedelic"), N_("Rave"),
- N_("Showtunes"), N_("Trailer"), N_("Lo-Fi"), N_("Tribal"),
- N_("Acid Punk"), N_("Acid Jazz"), N_("Polka"), N_("Retro"),
- N_("Musical"), N_("Rock & Roll"), N_("Hard Rock"), N_("Folk"),
- N_("Folk/Rock"), N_("National Folk"), N_("Swing"),
- N_("Fast-Fusion"), N_("Bebob"), N_("Latin"), N_("Revival"),
- N_("Celtic"), N_("Bluegrass"), N_("Avantgarde"),
- N_("Gothic Rock"), N_("Progressive Rock"),
- N_("Psychedelic Rock"), N_("Symphonic Rock"), N_("Slow Rock"),
- N_("Big Band"), N_("Chorus"), N_("Easy Listening"),
- N_("Acoustic"), N_("Humour"), N_("Speech"), N_("Chanson"),
- N_("Opera"), N_("Chamber Music"), N_("Sonata"), N_("Symphony"),
- N_("Booty Bass"), N_("Primus"), N_("Porn Groove"),
- N_("Satire"), N_("Slow Jam"), N_("Club"), N_("Tango"),
- N_("Samba"), N_("Folklore"), N_("Ballad"), N_("Power Ballad"),
- N_("Rhythmic Soul"), N_("Freestyle"), N_("Duet"),
- N_("Punk Rock"), N_("Drum Solo"), N_("A Cappella"),
- N_("Euro-House"), N_("Dance Hall"), N_("Goa"),
- N_("Drum & Bass"), N_("Club-House"), N_("Hardcore"),
- N_("Terror"), N_("Indie"), N_("BritPop"), N_("Negerpunk"),
- N_("Polsk Punk"), N_("Beat"), N_("Christian Gangsta Rap"),
- N_("Heavy Metal"), N_("Black Metal"), N_("Crossover"),
- N_("Contemporary Christian"), N_("Christian Rock"),
- N_("Merengue"), N_("Salsa"), N_("Thrash Metal"),
- N_("Anime"), N_("JPop"), N_("Synthpop")
-};
+/* This is by no means intended to be a complete list. If it is not short, it
+ * is useless: scrolling through ten pages of dropdown list is more work than
+ * typing out the genre. */
+
+static const gchar * genre_table[] = {
+ N_("Acid Jazz"),
+ N_("Acid Rock"),
+ N_("Ambient"),
+ N_("Bebop"),
+ N_("Bluegrass"),
+ N_("Blues"),
+ N_("Chamber Music"),
+ N_("Classical"),
+ N_("Country"),
+ N_("Death Metal"),
+ N_("Disco"),
+ N_("Easy Listening"),
+ N_("Folk"),
+ N_("Funk"),
+ N_("Gangsta Rap"),
+ N_("Gospel"),
+ N_("Grunge"),
+ N_("Hard Rock"),
+ N_("Heavy Metal"),
+ N_("Hip-hop"),
+ N_("House"),
+ N_("Jazz"),
+ N_("Jungle"),
+ N_("Metal"),
+ N_("New Age"),
+ N_("New Wave"),
+ N_("Noise"),
+ N_("Pop"),
+ N_("Punk Rock"),
+ N_("Rap"),
+ N_("Reggae"),
+ N_("Rock"),
+ N_("Rock and Roll"),
+ N_("Rhythm and Blues"),
+ N_("Ska"),
+ N_("Soul"),
+ N_("Swing"),
+ N_("Techno"),
+ N_("Trip-hop")};
static void set_entry_str_from_field (GtkWidget * widget, const Tuple * tuple,
gint fieldn, gboolean editable)
@@ -181,18 +177,14 @@ static void infowin_label_set_text (GtkWidget * widget, const gchar * text)
gtk_label_set_use_markup ((GtkLabel *) widget, TRUE);
}
-static void infowin_entry_set_image (GtkWidget * widget, const char * text)
+static void infowin_entry_set_image (GtkWidget * widget, gint list, gint entry)
{
- GdkPixbuf * pixbuf;
-
- pixbuf = gdk_pixbuf_new_from_file (text, NULL);
- g_return_if_fail (pixbuf != NULL);
-
- if (strcmp (DATA_DIR "/images/audio.png", text))
- audgui_pixbuf_scale_within (& pixbuf, aud_cfg->filepopup_pixelsize);
+ GdkPixbuf * p = audgui_pixbuf_for_entry (list, entry);
+ g_return_if_fail (p);
- gtk_image_set_from_pixbuf ((GtkImage *) widget, pixbuf);
- g_object_unref (pixbuf);
+ audgui_pixbuf_scale_within (& p, aud_cfg->filepopup_pixelsize);
+ gtk_image_set_from_pixbuf ((GtkImage *) widget, p);
+ g_object_unref ((GObject *) p);
}
static void clear_infowin (void)
@@ -221,8 +213,7 @@ static void clear_infowin (void)
something_changed = FALSE;
can_write = FALSE;
gtk_widget_set_sensitive (btn_apply, FALSE);
-
- infowin_entry_set_image (image_artwork, DATA_DIR "/images/audio.png");
+ gtk_image_clear ((GtkImage *) image_artwork);
}
static void entry_changed (GtkEditable * editable, void * unused)
@@ -252,7 +243,7 @@ static void ministatus_display_message (const gchar * text)
gtk_label_set_use_markup ((GtkLabel *) label_mini_status, TRUE);
g_free (tmp);
- g_timeout_add (STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc,
+ g_timeout_add (AUDGUI_STATUS_TIMEOUT, (GSourceFunc) ministatus_timeout_proc,
label_mini_status);
}
@@ -281,80 +272,6 @@ static void infowin_update_tuple (void * unused)
mowgli_object_unref (tuple);
}
-/**
- * Looks up an icon from a NULL-terminated list of icon names.
- *
- * size: the requested size
- * name: the default name
- * ... : a NULL-terminated list of alternates
- */
-static GdkPixbuf * themed_icon_lookup (gint size, const gchar * name, ...)
-{
- GtkIconTheme * icon_theme;
- GdkPixbuf * pixbuf;
- const gchar * n;
- va_list par;
-
- icon_theme = gtk_icon_theme_get_default ();
- pixbuf = gtk_icon_theme_load_icon (icon_theme, name, size, 0, NULL);
-
- if (pixbuf != NULL)
- return pixbuf;
-
- /* fallback */
- va_start (par, name);
-
- while ((n = va_arg (par, const gchar *)) != NULL)
- {
- pixbuf = gtk_icon_theme_load_icon (icon_theme, n, size, 0, NULL);
-
- if (pixbuf)
- {
- va_end (par);
- return pixbuf;
- }
- }
-
- va_end (par);
- return NULL;
-}
-
-/**
- * Intelligently looks up an icon for a mimetype. Supports
- * HIDEOUSLY BROKEN gnome icon naming scheme too.
- *
- * size : the requested size
- * mime_type: the mime type.
- */
-static GdkPixbuf * mime_icon_lookup (gint size, const gchar * mime_type)
-{
- gchar * mime_as_is; /* audio-x-mp3 */
- gchar * mime_gnome; /* gnome-mime-audio-x-mp3 */
- gchar * mime_generic; /* audio-x-generic */
- gchar * mime_gnome_generic; /* gnome-mime-audio */
- GdkPixbuf * icon = NULL;
- gchar * * s = g_strsplit (mime_type, "/", 2);
-
- if (s[1] != NULL)
- {
- mime_as_is = g_strdup_printf ("%s-%s", s[0], s[1]);
- mime_gnome = g_strdup_printf ("gnome-mime-%s-%s", s[0], s[1]);
- mime_generic = g_strdup_printf ("%s-x-generic", s[0]);
- mime_gnome_generic = g_strdup_printf ("gnome-mime-%s", s[0]);
-
- icon = themed_icon_lookup (size, mime_as_is, mime_gnome, mime_generic,
- mime_gnome_generic, s[0], NULL); /* s[0] is category */
-
- g_free (mime_gnome_generic);
- g_free (mime_generic);
- g_free (mime_gnome);
- g_free (mime_as_is);
- }
-
- g_strfreev (s);
- return icon;
-}
-
gboolean genre_fill (GtkWidget * combo)
{
GList * list = NULL;
@@ -367,7 +284,7 @@ gboolean genre_fill (GtkWidget * combo)
list = g_list_sort (list, (GCompareFunc) strcmp);
for (node = list; node != NULL; node = node->next)
- gtk_combo_box_append_text ((GtkComboBox *) combo, node->data);
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) combo, node->data);
g_list_free (list);
return FALSE;
@@ -378,9 +295,7 @@ void create_infowin (void)
GtkWidget * hbox;
GtkWidget * hbox_status_and_bbox;
GtkWidget * vbox0;
- GtkWidget * vbox1;
GtkWidget * vbox2;
- GtkWidget * vbox3;
GtkWidget * label_title;
GtkWidget * label_artist;
GtkWidget * label_album;
@@ -388,8 +303,6 @@ void create_infowin (void)
GtkWidget * label_genre;
GtkWidget * label_year;
GtkWidget * label_track;
- GtkWidget * label_location;
- GtkWidget * label_general;
GtkWidget * label_format;
GtkWidget * label_quality_label;
GtkWidget * label_bitrate_label;
@@ -399,10 +312,6 @@ void create_infowin (void)
GtkWidget * bbox_close;
GtkWidget * btn_close;
GtkWidget * alignment;
- GtkWidget * separator;
- GtkWidget * scrolledwindow;
- GtkTreeViewColumn * column;
- GtkCellRenderer * renderer;
infowin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width ((GtkContainer *) infowin, 6);
@@ -416,47 +325,25 @@ void create_infowin (void)
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start ((GtkBox *) vbox0, hbox, TRUE, TRUE, 0);
- image_artwork = gtk_image_new ();
- gtk_box_pack_start ((GtkBox *) hbox, image_artwork, FALSE, FALSE, 0);
- gtk_misc_set_alignment ((GtkMisc *) image_artwork, 0.5, 0);
- gtk_image_set_from_file ((GtkImage *) image_artwork, DATA_DIR
- "/images/audio.png");
- separator = gtk_vseparator_new ();
- gtk_box_pack_start ((GtkBox *) hbox, separator, FALSE, FALSE, 0);
-
- vbox1 = gtk_vbox_new (FALSE, 0);
- gtk_box_pack_start ((GtkBox *) hbox, vbox1, TRUE, TRUE, 0);
-
- alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start ((GtkBox *) vbox1, alignment, TRUE, TRUE, 0);
+ vbox2 = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start ((GtkBox *) hbox, vbox2, TRUE, TRUE, 0);
- vbox2 = gtk_vbox_new (FALSE, 0);
- gtk_container_add ((GtkContainer *) alignment, vbox2);
-
- alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_box_pack_start ((GtkBox *) vbox1, alignment, TRUE, TRUE, 0);
-
- vbox3 = gtk_vbox_new(FALSE, 0);
- gtk_container_add ((GtkContainer *) alignment, vbox3);
-
- label_general = gtk_label_new (_("<span size=\"small\">General</span>"));
- gtk_box_pack_start ((GtkBox *) vbox2, label_general, FALSE, FALSE, 0);
- gtk_label_set_use_markup ((GtkLabel *) label_general, TRUE);
- gtk_misc_set_alignment ((GtkMisc *) label_general, 0, 0.5);
+ image_artwork = gtk_image_new ();
+ gtk_box_pack_start ((GtkBox *) vbox2, image_artwork, TRUE, TRUE, 0);
- alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_alignment_set_padding ((GtkAlignment *) alignment, 6, 6, 0, 0);
- gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0);
+ location_text = gtk_label_new ("");
+ gtk_widget_set_size_request (location_text, 200, -1);
+ gtk_label_set_line_wrap ((GtkLabel *) location_text, TRUE);
+ gtk_label_set_line_wrap_mode ((GtkLabel *) location_text,
+ PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_selectable ((GtkLabel *) location_text, TRUE);
+ gtk_box_pack_start ((GtkBox *) vbox2, location_text, FALSE, FALSE, 0);
codec_hbox = gtk_hbox_new (FALSE, 6);
- gtk_container_add ((GtkContainer *) alignment, codec_hbox);
-
- image_fileicon = gtk_image_new_from_stock (GTK_STOCK_MISSING_IMAGE,
- GTK_ICON_SIZE_DIALOG);
- gtk_box_pack_start ((GtkBox *) codec_hbox, image_fileicon, FALSE, FALSE, 0);
+ gtk_box_pack_start ((GtkBox *) vbox2, codec_hbox, FALSE, FALSE, 0);
codec_table = gtk_table_new(3, 2, FALSE);
- gtk_table_set_row_spacings ((GtkTable *) codec_table, 6);
+ gtk_table_set_row_spacings ((GtkTable *) codec_table, 3);
gtk_table_set_col_spacings ((GtkTable *) codec_table, 12);
gtk_box_pack_start ((GtkBox *) codec_hbox, codec_table, FALSE, FALSE, 0);
@@ -494,6 +381,9 @@ void create_infowin (void)
gtk_table_attach ((GtkTable *) codec_table, label_bitrate, 1, 2, 2, 3,
GTK_EXPAND | GTK_FILL, 0, 0, 0);
+ vbox2 = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start ((GtkBox *) hbox, vbox2, TRUE, TRUE, 0);
+
label_title = gtk_label_new (_("<span size=\"small\">Title</span>"));
gtk_box_pack_start ((GtkBox *) vbox2, label_title, FALSE, FALSE, 0);
gtk_label_set_use_markup ((GtkLabel *) label_title, TRUE);
@@ -550,8 +440,8 @@ void create_infowin (void)
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0);
gtk_alignment_set_padding ((GtkAlignment *) alignment, 0, 6, 0, 0);
- entry_genre = gtk_combo_box_entry_new_text ();
+ entry_genre = gtk_combo_box_text_new_with_entry ();
gtk_container_add ((GtkContainer *) alignment, entry_genre);
g_signal_connect (entry_genre, "changed", (GCallback) entry_changed, NULL);
g_idle_add ((GSourceFunc) genre_fill, entry_genre);
@@ -585,77 +475,6 @@ void create_infowin (void)
GTK_FILL, 0, 0, 0);
g_signal_connect (entry_track, "changed", (GCallback) entry_changed, NULL);
- label_location = gtk_label_new (_("<span size=\"small\">Location</span>"));
- gtk_box_pack_start ((GtkBox *) vbox2, label_location, FALSE, FALSE, 0);
- gtk_label_set_use_markup ((GtkLabel *) label_location, TRUE);
- gtk_misc_set_alignment ((GtkMisc *) label_location, 0, 0.5);
-
- alignment = gtk_alignment_new (0, 0, 0, 0);
- gtk_alignment_set_padding ((GtkAlignment *) alignment, 3, 6, 25, 0);
- gtk_box_pack_start ((GtkBox *) vbox2, alignment, FALSE, FALSE, 0);
-
- location_text = gtk_label_new ("");
- gtk_widget_set_size_request (location_text, 375, -1);
- gtk_label_set_line_wrap ((GtkLabel *) location_text, TRUE);
-#if GTK_CHECK_VERSION (2, 10, 0)
- gtk_label_set_line_wrap_mode ((GtkLabel *) location_text,
- PANGO_WRAP_WORD_CHAR);
-#endif
- gtk_label_set_selectable ((GtkLabel *) location_text, TRUE);
- gtk_container_add ((GtkContainer *) alignment, location_text);
-
- alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
- hbox = gtk_hbox_new (FALSE, 0);
- gtk_container_add ((GtkContainer *) alignment, hbox);
- gtk_box_pack_start ((GtkBox *) vbox3, alignment, TRUE, TRUE, 0);
-
- alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
- gtk_alignment_set_padding ((GtkAlignment *) (alignment), 0, 6, 0, 0);
- arrow_rawdata = gtk_expander_new
- (_("<span size=\"small\">Raw Metadata</span>"));
- gtk_expander_set_use_markup ((GtkExpander *) arrow_rawdata, TRUE);
- gtk_container_add ((GtkContainer *) alignment, arrow_rawdata);
- gtk_box_pack_start ((GtkBox *) hbox, alignment, TRUE, TRUE, 0);
-
- scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy ((GtkScrolledWindow *) scrolledwindow,
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) scrolledwindow,
- GTK_SHADOW_IN);
- gtk_container_add ((GtkContainer *) arrow_rawdata, scrolledwindow);
-
- treeview_rawdata = gtk_tree_view_new ();
- gtk_container_add ((GtkContainer *) scrolledwindow, treeview_rawdata);
- gtk_tree_view_set_rules_hint ((GtkTreeView *) treeview_rawdata, TRUE);
- gtk_tree_view_set_reorderable ((GtkTreeView *) treeview_rawdata, TRUE);
- gtk_widget_set_size_request (treeview_rawdata, -1, 130);
-
- column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, _("Key"));
- gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
- gtk_tree_view_column_set_spacing (column, 4);
- gtk_tree_view_column_set_resizable (column, FALSE);
- gtk_tree_view_column_set_fixed_width (column, 50);
-
- renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column, renderer, "text", RAWDATA_KEY,
- NULL);
- gtk_tree_view_append_column ((GtkTreeView *) treeview_rawdata, column);
-
- column = gtk_tree_view_column_new ();
- gtk_tree_view_column_set_title (column, _("Value"));
- gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
- gtk_tree_view_column_set_spacing (column, 4);
- gtk_tree_view_column_set_resizable (column, FALSE);
- gtk_tree_view_column_set_fixed_width (column, 50);
-
- renderer = gtk_cell_renderer_text_new ();
- gtk_tree_view_column_pack_start (column, renderer, FALSE);
- gtk_tree_view_column_set_attributes (column, renderer, "text",
- RAWDATA_VALUE, NULL);
- gtk_tree_view_append_column ((GtkTreeView *) treeview_rawdata, column);
-
hbox_status_and_bbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start ((GtkBox *) vbox0, hbox_status_and_bbox, FALSE, FALSE, 0);
@@ -686,73 +505,13 @@ void create_infowin (void)
audgui_hide_on_escape (infowin);
gtk_widget_show_all (vbox0);
+ gtk_widget_grab_focus (entry_title);
}
-/* Converts filenames (in place) for easy reading, thus:
- *
- * file:///home/me/Music/My song.ogg -> Music
- * My song.ogg
- *
- * file:///media/disk/My song.ogg -> /
- * media
- * disk
- * My song.ogg
- */
-static gchar * easy_read_filename (gchar * file)
-{
- const gchar * home;
- gint len;
-
- if (strncmp (file, "file:///", 8))
- return file;
-
- home = getenv ("HOME");
- len = (home == NULL) ? 0 : strlen (home);
- len = (len > 0 && home[len - 1] == '/') ? len - 1 : len;
-
- if (len > 0 && ! strncmp (file + 7, home, len) && file[len + 7] == '/')
- {
- string_replace_char (file + len + 8, '/', '\n');
- return file + len + 8;
- }
-
- string_replace_char (file + 7, '/', '\n');
- return file + 6;
-}
-
-static gboolean set_image_from_album_art (const gchar * filename, InputPlugin *
- decoder)
+static void infowin_show (gint list, gint entry, const gchar * filename,
+ const Tuple * tuple, PluginHandle * decoder, gboolean updating_enabled)
{
- GdkPixbuf * pixbuf = NULL;
- void * data;
- gint size;
-
- if (aud_file_read_image (filename, decoder, & data, & size))
- {
- pixbuf = audgui_pixbuf_from_data (data, size);
- g_free (data);
- }
-
- if (pixbuf == NULL)
- return FALSE;
-
- audgui_pixbuf_scale_within (& pixbuf, aud_cfg->filepopup_pixelsize);
- gtk_image_set_from_pixbuf ((GtkImage *) image_artwork, pixbuf);
- g_object_unref (pixbuf);
- return TRUE;
-}
-
-static void infowin_show (const gchar * filename, const Tuple * tuple,
- InputPlugin * decoder, gboolean updating_enabled)
-{
- const gchar * string;
gchar * tmp;
- GdkPixbuf * icon;
- GtkTreeIter iter;
- GtkListStore * store;
- mowgli_dictionary_iteration_state_t state;
- TupleValue * tvalue;
- gint i;
if (infowin == NULL)
create_infowin ();
@@ -772,18 +531,8 @@ static void infowin_show (const gchar * filename, const Tuple * tuple,
set_entry_str_from_field (gtk_bin_get_child ((GtkBin *) entry_genre), tuple,
FIELD_GENRE, updating_enabled);
- tmp = g_strdup (filename);
- string_decode_percent (tmp);
-
- /* Convert invalid UTF-8 URI's quietly. */
- if (! g_utf8_validate (tmp, -1, NULL))
- {
- gchar * copy = str_to_utf8 (tmp);
- g_free (tmp);
- tmp = copy;
- }
-
- gtk_label_set_text ((GtkLabel *) location_text, easy_read_filename (tmp));
+ tmp = uri_to_display (filename);
+ gtk_label_set_text ((GtkLabel *) location_text, tmp);
g_free (tmp);
set_entry_int_from_field (entry_year, tuple, FIELD_YEAR, updating_enabled);
@@ -805,69 +554,7 @@ static void infowin_show (const gchar * filename, const Tuple * tuple,
else
infowin_label_set_text (label_bitrate, NULL);
- string = tuple_get_string (tuple, FIELD_MIMETYPE, NULL);
- icon = mime_icon_lookup (48, string != NULL ? string : "audio/x-generic");
-
- if (icon != NULL)
- {
- gtk_image_set_from_pixbuf ((GtkImage *) image_fileicon, icon);
- g_object_unref (icon);
- }
-
- if (! set_image_from_album_art (filename, decoder))
- {
- tmp = aud_get_associated_image_file (filename);
-
- if (tmp != NULL)
- {
- infowin_entry_set_image (image_artwork, tmp);
- g_free (tmp);
- }
- }
-
- store = gtk_list_store_new (RAWDATA_N_COLS, G_TYPE_STRING, G_TYPE_STRING);
-
- for (i = 0; i < FIELD_LAST; i ++)
- {
- gchar * value;
-
- if (tuple->values[i] == NULL)
- continue;
-
- if (tuple->values[i]->type == TUPLE_INT)
- value = g_strdup_printf ("%d", tuple->values[i]->value.integer);
- else if (tuple->values[i]->value.string != NULL)
- value = g_strdup (tuple->values[i]->value.string);
- else
- continue;
-
- gtk_list_store_append (store, & iter);
- gtk_list_store_set (store, & iter, RAWDATA_KEY, tuple_fields[i].name,
- RAWDATA_VALUE, value, -1);
- g_free (value);
- }
-
- /* non-standard values are stored in a dictionary. */
- MOWGLI_DICTIONARY_FOREACH (tvalue, & state, tuple->dict)
- {
- gchar * value;
-
- if (tvalue->type == TUPLE_INT)
- value = g_strdup_printf ("%d", tvalue->value.integer);
- else if (tvalue->value.string != NULL)
- value = g_strdup (tvalue->value.string);
- else
- continue;
-
- gtk_list_store_append (store, & iter);
- gtk_list_store_set (store, & iter, RAWDATA_KEY, state.cur->key,
- RAWDATA_VALUE, value, -1);
- g_free (value);
- }
-
- gtk_tree_view_set_model ((GtkTreeView *) treeview_rawdata, (GtkTreeModel *)
- store);
- g_object_unref (store);
+ infowin_entry_set_image (image_artwork, list, entry);
gtk_window_present ((GtkWindow *) infowin);
}
@@ -877,7 +564,8 @@ void audgui_infowin_show (gint playlist, gint entry)
const gchar * filename = aud_playlist_entry_get_filename (playlist, entry);
g_return_if_fail (filename != NULL);
- InputPlugin * decoder = aud_file_find_decoder (filename, FALSE);
+ PluginHandle * decoder = aud_playlist_entry_get_decoder (playlist, entry,
+ FALSE);
if (decoder == NULL)
return;
@@ -895,8 +583,8 @@ void audgui_infowin_show (gint playlist, gint entry)
return;
}
- infowin_show (filename, tuple, decoder, aud_file_can_write_tuple (filename,
- decoder));
+ infowin_show (playlist, entry, filename, tuple, decoder,
+ aud_file_can_write_tuple (filename, decoder));
}
void audgui_infowin_show_current (void)
diff --git a/src/libaudgui/libaudgui-gtk.h b/src/libaudgui/libaudgui-gtk.h
index f9316eb..f093851 100644
--- a/src/libaudgui/libaudgui-gtk.h
+++ b/src/libaudgui/libaudgui-gtk.h
@@ -34,17 +34,6 @@ void audgui_playlist_manager_update(void);
void audgui_playlist_manager_ui_show(GtkWidget *mainwin);
void audgui_playlist_manager_destroy(void);
-/* library-store.c */
-enum
-{
- AUDGUI_LIBRARY_STORE_TITLE, /* G_TYPE_STRING */
- AUDGUI_LIBRARY_STORE_FONT_WEIGHT, /* PANGO_TYPE_WEIGHT */
- AUDGUI_LIBRARY_STORE_ENTRY_COUNT, /* G_TYPE_INT */
- AUDGUI_LIBRARY_STORE_COLUMNS
-};
-
-GtkTreeModel * audgui_get_library_store (void);
-
/* util.c */
void audgui_hide_on_delete (GtkWidget * widget);
void audgui_hide_on_escape (GtkWidget * widget);
@@ -54,7 +43,8 @@ void audgui_simple_message (GtkWidget * * widget, GtkMessageType type,
void audgui_connect_check_box (GtkWidget * box, gboolean * setting);
GdkPixbuf * audgui_pixbuf_from_data (void * data, gint size);
-GdkPixbuf * audgui_pixbuf_for_file (const gchar * filename);
+GdkPixbuf * audgui_pixbuf_for_entry (gint playlist, gint entry);
+GdkPixbuf * audgui_pixbuf_for_current (void);
void audgui_pixbuf_scale_within (GdkPixbuf * * pixbuf, gint size);
#endif
diff --git a/src/libaudgui/libaudgui.h b/src/libaudgui/libaudgui.h
index 7fc4b1c..d96c933 100644
--- a/src/libaudgui/libaudgui.h
+++ b/src/libaudgui/libaudgui.h
@@ -45,6 +45,7 @@ void audgui_hide_about_window(void);
/* confirm.c */
void audgui_confirm_playlist_delete (gint playlist);
+void audgui_show_playlist_rename (gint playlist);
/* equalizer.c */
void audgui_show_equalizer_window (void);
diff --git a/src/libaudgui/library-store.c b/src/libaudgui/library-store.c
deleted file mode 100644
index 4439e44..0000000
--- a/src/libaudgui/library-store.c
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * libaudgui/library-store.c
- * Copyright 2010 John Lindgren
- *
- * This file is part of Audacious.
- *
- * Audacious 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, version 2 or version 3 of the License.
- *
- * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * Audacious. If not, see <http://www.gnu.org/licenses/>.
- *
- * The Audacious team does not consider modular code linking to Audacious or
- * using our public API to be a derived work.
- */
-
-#include <audacious/playlist.h>
-#include <libaudcore/hook.h>
-
-#include "libaudgui-gtk.h"
-
-typedef GObjectClass LibraryStoreClass;
-
-typedef struct
-{
- GObject parent;
- gint rows, active;
-}
-LibraryStore;
-
-static void library_store_init (LibraryStore * store)
-{
- store->rows = aud_playlist_count ();
- store->active = aud_playlist_get_active ();
-}
-
-static GtkTreeModelFlags library_store_get_flags (GtkTreeModel * model)
-{
- return GTK_TREE_MODEL_LIST_ONLY;
-}
-
-static gint library_store_get_n_columns (GtkTreeModel * model)
-{
- return AUDGUI_LIBRARY_STORE_COLUMNS;
-}
-
-static GType library_store_get_column_type (GtkTreeModel * model, gint column)
-{
- switch (column)
- {
- case AUDGUI_LIBRARY_STORE_TITLE:
- return G_TYPE_STRING;
- case AUDGUI_LIBRARY_STORE_FONT_WEIGHT:
- return PANGO_TYPE_WEIGHT;
- case AUDGUI_LIBRARY_STORE_ENTRY_COUNT:
- return G_TYPE_INT;
- default:
- return G_TYPE_INVALID;
- }
-}
-
-static gboolean library_store_get_iter (GtkTreeModel * model, GtkTreeIter *
- iter, GtkTreePath * path)
-{
- LibraryStore * store = (LibraryStore *) model;
- gint playlist = gtk_tree_path_get_indices (path)[0];
-
- if (playlist < 0 || playlist >= store->rows)
- return FALSE;
-
- iter->user_data = GINT_TO_POINTER (playlist);
- return TRUE;
-}
-
-static GtkTreePath * library_store_get_path (GtkTreeModel * model, GtkTreeIter *
- iter)
-{
- return gtk_tree_path_new_from_indices (GPOINTER_TO_INT (iter->user_data), -1);
-}
-
-static void library_store_get_value (GtkTreeModel * model, GtkTreeIter * iter,
- gint column, GValue * value)
-{
- LibraryStore * store = (LibraryStore *) model;
- gint playlist = GPOINTER_TO_INT (iter->user_data);
-
- switch (column)
- {
- case AUDGUI_LIBRARY_STORE_TITLE:
- g_value_init (value, G_TYPE_STRING);
- g_value_set_string (value, aud_playlist_get_title (playlist));
- break;
- case AUDGUI_LIBRARY_STORE_FONT_WEIGHT:
- g_value_init (value, PANGO_TYPE_WEIGHT);
- g_value_set_enum (value, (playlist == store->active) ? PANGO_WEIGHT_BOLD
- : PANGO_WEIGHT_NORMAL);
- break;
- case AUDGUI_LIBRARY_STORE_ENTRY_COUNT:
- g_value_init (value, G_TYPE_INT);
- g_value_set_int (value, aud_playlist_entry_count (playlist));
- break;
- }
-}
-
-static gboolean library_store_iter_next (GtkTreeModel * model, GtkTreeIter *
- iter)
-{
- if (GPOINTER_TO_INT (iter->user_data) + 1 < aud_playlist_count ())
- {
- iter->user_data = GINT_TO_POINTER (GPOINTER_TO_INT (iter->user_data) + 1);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean library_store_iter_children (GtkTreeModel * model, GtkTreeIter *
- iter, GtkTreeIter * parent)
-{
- if (parent == NULL) /* top level */
- {
- /* there is always at least one playlist */
- iter->user_data = GINT_TO_POINTER (0);
- return TRUE;
- }
-
- return FALSE;
-}
-
-static gboolean library_store_iter_has_child (GtkTreeModel * model,
- GtkTreeIter * iter)
-{
- return FALSE;
-}
-
-static gint library_store_iter_n_children (GtkTreeModel * model, GtkTreeIter *
- iter)
-{
- LibraryStore * store = (LibraryStore *) model;
-
- if (iter == NULL) /* top level */
- return store->rows;
-
- return 0;
-}
-
-static gboolean library_store_iter_nth_child (GtkTreeModel * model,
- GtkTreeIter * iter, GtkTreeIter * parent, gint n)
-{
- LibraryStore * store = (LibraryStore *) model;
-
- if (parent != NULL) /* not top level */
- return FALSE;
-
- if (n < 0 || n >= store->rows)
- return FALSE;
-
- iter->user_data = GINT_TO_POINTER (n);
- return TRUE;
-}
-
-static gboolean library_store_iter_parent (GtkTreeModel * model, GtkTreeIter *
- iter, GtkTreeIter * child)
-{
- return FALSE;
-}
-
-static void interface_init (GtkTreeModelIface * interface)
-{
- interface->get_flags = library_store_get_flags;
- interface->get_n_columns = library_store_get_n_columns;
- interface->get_column_type = library_store_get_column_type;
- interface->get_iter = library_store_get_iter;
- interface->get_path = library_store_get_path;
- interface->get_value = library_store_get_value;
- interface->iter_next = library_store_iter_next;
- interface->iter_children = library_store_iter_children;
- interface->iter_has_child = library_store_iter_has_child;
- interface->iter_n_children = library_store_iter_n_children;
- interface->iter_nth_child = library_store_iter_nth_child;
- interface->iter_parent = library_store_iter_parent;
-}
-
-static const GInterfaceInfo interface_info =
-{
- .interface_init = (GInterfaceInitFunc) interface_init,
- .interface_finalize = NULL,
- .interface_data = NULL,
-};
-
-static gboolean library_store_drag_data_get (GtkTreeDragSource * source,
- GtkTreePath * path, GtkSelectionData * data)
-{
- return gtk_tree_set_row_drag_data (data, (GtkTreeModel *) source, path);
-}
-
-static gboolean library_store_drag_data_delete (GtkTreeDragSource * source,
- GtkTreePath * path)
-{
- return TRUE;
-}
-
-static void source_init (GtkTreeDragSourceIface * interface)
-{
- interface->drag_data_get = library_store_drag_data_get;
- interface->drag_data_delete = library_store_drag_data_delete;
-}
-
-static const GInterfaceInfo source_info =
-{
- .interface_init = (GInterfaceInitFunc) source_init,
- .interface_finalize = NULL,
- .interface_data = NULL,
-};
-
-static gboolean library_store_drag_data_received (GtkTreeDragDest * dest,
- GtkTreePath * dest_path, GtkSelectionData * data)
-{
- LibraryStore * store = (LibraryStore *) dest;
- GtkTreeModel * model;
- GtkTreePath * source_path, * top;
- gint from, to, count;
- gint order[store->rows];
-
- if (! gtk_tree_get_row_drag_data (data, & model, & source_path))
- return FALSE;
-
- from = gtk_tree_path_get_indices (source_path)[0];
- to = gtk_tree_path_get_indices (dest_path)[0];
-
- /* GTK gives us the number of the row before which we are to put the row.
- * We want the number of the row where the row will end up. */
- if (to > from)
- to --;
-
- if (from < 0 || from >= store->rows || to < 0 || to >= store->rows)
- return FALSE;
-
- aud_playlist_reorder (from, to, 1);
-
- for (count = 0; count < from; count ++)
- order[count] = count;
-
- if (from < to)
- {
- for (count = from; count < to; count ++)
- order[count] = count + 1;
- }
- else
- {
- for (count = to; count < from; count ++)
- order[count + 1] = count;
- }
-
- order[to] = from;
-
- top = gtk_tree_path_new ();
- gtk_tree_model_rows_reordered (model, top, NULL, order);
- gtk_tree_path_free (top);
-
- return TRUE;
-}
-
-gboolean library_store_row_drop_possible (GtkTreeDragDest * dest,
- GtkTreePath * path, GtkSelectionData * selection_data)
-{
- LibraryStore * store = (LibraryStore *) dest;
- gint before = gtk_tree_path_get_indices (path)[0];
-
- return (before >= 0 && before <= store->rows);
-}
-
-static void dest_init (GtkTreeDragDestIface * interface)
-{
- interface->drag_data_received = library_store_drag_data_received;
- interface->row_drop_possible = library_store_row_drop_possible;
-}
-
-static const GInterfaceInfo dest_info =
-{
- .interface_init = (GInterfaceInitFunc) dest_init,
- .interface_finalize = NULL,
- .interface_data = NULL,
-};
-
-static GType library_store_get_type (void)
-{
- static GType type = 0;
-
- if (! type)
- {
- type = g_type_register_static_simple (G_TYPE_OBJECT, "LibraryStore",
- sizeof (LibraryStoreClass), NULL, sizeof (LibraryStore),
- (GInstanceInitFunc) library_store_init, 0);
- g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, & interface_info);
- g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_SOURCE,
- & source_info);
- g_type_add_interface_static (type, GTK_TYPE_TREE_DRAG_DEST, & dest_info);
- }
-
- return type;
-}
-
-static void library_store_update (GtkTreeModel * model)
-{
- LibraryStore * store = (LibraryStore *) model;
- gint old_rows = store->rows;
- GtkTreePath * path;
- GtkTreeIter iter;
- gint row;
-
- store->rows = aud_playlist_count ();
- store->active = aud_playlist_get_active ();
-
- if (store->rows < old_rows)
- {
- path = gtk_tree_path_new_from_indices (store->rows, -1);
-
- for (row = store->rows; row < old_rows; row ++)
- gtk_tree_model_row_deleted (model, path);
-
- gtk_tree_path_free (path);
- old_rows = store->rows;
- }
-
- path = gtk_tree_path_new_first ();
-
- for (row = 0; row < old_rows; row ++)
- {
- iter.user_data = GINT_TO_POINTER (row);
- gtk_tree_model_row_changed (model, path, & iter);
- gtk_tree_path_next (path);
- }
-
- for (; row < store->rows; row ++)
- {
- iter.user_data = GINT_TO_POINTER (row);
- gtk_tree_model_row_inserted (model, path, & iter);
- gtk_tree_path_next (path);
- }
-
- gtk_tree_path_free (path);
-}
-
-static void update_cb (void * data, void * user_data)
-{
- if (GPOINTER_TO_INT (data) >= PLAYLIST_UPDATE_STRUCTURE)
- library_store_update ((GtkTreeModel *) user_data);
-}
-
-GtkTreeModel * audgui_get_library_store (void)
-{
- static GtkTreeModel * store = NULL;
-
- if (store == NULL)
- {
- store = (GtkTreeModel *) g_object_new (library_store_get_type (), NULL);
- hook_associate ("playlist update", update_cb, store);
- }
-
- return store;
-}
diff --git a/src/libaudgui/list.c b/src/libaudgui/list.c
new file mode 100755
index 0000000..7a39cde
--- /dev/null
+++ b/src/libaudgui/list.c
@@ -0,0 +1,758 @@
+/*
+ * list.c
+ * Copyright 2011 John Lindgren
+ *
+ * This file is part of Audacious.
+ *
+ * Audacious 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, version 2 or version 3 of the License.
+ *
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
+ */
+
+#include "list.h"
+
+#include <audacious/gtk-compat.h>
+
+enum {HIGHLIGHT_COLUMN, RESERVED_COLUMNS};
+
+#define PATH_IS_SELECTED(w, p) (gtk_tree_selection_path_is_selected \
+ (gtk_tree_view_get_selection ((GtkTreeView *) (w)), (p)))
+
+typedef struct {
+ GObject parent;
+ const AudguiListCallbacks * cbs;
+ void * user;
+ gint rows, highlight;
+ gint columns;
+ GList * column_types;
+ gboolean frozen, blocked;
+ gboolean dragging;
+ gboolean clicked_row, receive_row;
+ gint scroll_source, scroll_speed;
+} ListModel;
+
+/* ==== MODEL ==== */
+
+static GtkTreeModelFlags list_model_get_flags (GtkTreeModel * model)
+{
+ return GTK_TREE_MODEL_LIST_ONLY;
+}
+
+static gint list_model_get_n_columns (GtkTreeModel * model)
+{
+ return ((ListModel *) model)->columns;
+}
+
+static GType list_model_get_column_type (GtkTreeModel * _model, gint column)
+{
+ ListModel * model = (ListModel *) _model;
+ g_return_val_if_fail (column >= 0 && column < model->columns, G_TYPE_INVALID);
+
+ if (column == HIGHLIGHT_COLUMN)
+ return PANGO_TYPE_WEIGHT;
+
+ return GPOINTER_TO_INT (g_list_nth_data (model->column_types, column -
+ RESERVED_COLUMNS));
+}
+
+static gboolean list_model_get_iter (GtkTreeModel * model, GtkTreeIter * iter,
+ GtkTreePath * path)
+{
+ gint row = gtk_tree_path_get_indices (path)[0];
+ if (row < 0 || row >= ((ListModel *) model)->rows)
+ return FALSE;
+ iter->user_data = GINT_TO_POINTER (row);
+ return TRUE;
+}
+
+static GtkTreePath * list_model_get_path (GtkTreeModel * model,
+ GtkTreeIter * iter)
+{
+ gint row = GPOINTER_TO_INT (iter->user_data);
+ g_return_val_if_fail (row >= 0 && row < ((ListModel *) model)->rows, NULL);
+ return gtk_tree_path_new_from_indices (row, -1);
+}
+
+static void list_model_get_value (GtkTreeModel * _model, GtkTreeIter * iter,
+ gint column, GValue * value)
+{
+ ListModel * model = (ListModel *) _model;
+ gint row = GPOINTER_TO_INT (iter->user_data);
+ g_return_if_fail (column >= 0 && column < model->columns);
+ g_return_if_fail (row >= 0 && row < model->rows);
+
+ if (column == HIGHLIGHT_COLUMN)
+ {
+ g_value_init (value, PANGO_TYPE_WEIGHT);
+ g_value_set_enum (value, row == model->highlight ? PANGO_WEIGHT_BOLD :
+ PANGO_WEIGHT_NORMAL);
+ return;
+ }
+
+ g_value_init (value, GPOINTER_TO_INT (g_list_nth_data (model->column_types,
+ column - RESERVED_COLUMNS)));
+ model->cbs->get_value (model->user, row, column - RESERVED_COLUMNS, value);
+}
+
+static gboolean list_model_iter_next (GtkTreeModel * _model, GtkTreeIter * iter)
+{
+ ListModel * model = (ListModel *) _model;
+ gint row = GPOINTER_TO_INT (iter->user_data);
+ g_return_val_if_fail (row >= 0 && row < model->rows, FALSE);
+ if (row + 1 >= model->rows)
+ return FALSE;
+ iter->user_data = GINT_TO_POINTER (row + 1);
+ return TRUE;
+}
+
+static gboolean list_model_iter_children (GtkTreeModel * model,
+ GtkTreeIter * iter, GtkTreeIter * parent)
+{
+ if (parent || ((ListModel *) model)->rows < 1)
+ return FALSE;
+ iter->user_data = GINT_TO_POINTER (0);
+ return TRUE;
+}
+
+static gboolean list_model_iter_has_child (GtkTreeModel * model,
+ GtkTreeIter * iter)
+{
+ return FALSE;
+}
+
+static gint list_model_iter_n_children (GtkTreeModel * model, GtkTreeIter * iter)
+{
+ return iter ? 0 : ((ListModel *) model)->rows;
+}
+
+static gboolean list_model_iter_nth_child (GtkTreeModel * model,
+ GtkTreeIter * iter, GtkTreeIter * parent, gint n)
+{
+ if (parent || n < 0 || n >= ((ListModel *) model)->rows)
+ return FALSE;
+ iter->user_data = GINT_TO_POINTER (n);
+ return TRUE;
+}
+
+static gboolean list_model_iter_parent (GtkTreeModel * model,
+ GtkTreeIter * iter, GtkTreeIter * child)
+{
+ return FALSE;
+}
+
+static void iface_init (GtkTreeModelIface * iface)
+{
+ iface->get_flags = list_model_get_flags;
+ iface->get_n_columns = list_model_get_n_columns;
+ iface->get_column_type = list_model_get_column_type;
+ iface->get_iter = list_model_get_iter;
+ iface->get_path = list_model_get_path;
+ iface->get_value = list_model_get_value;
+ iface->iter_next = list_model_iter_next;
+ iface->iter_children = list_model_iter_children;
+ iface->iter_has_child = list_model_iter_has_child;
+ iface->iter_n_children = list_model_iter_n_children;
+ iface->iter_nth_child = list_model_iter_nth_child;
+ iface->iter_parent = list_model_iter_parent;
+}
+
+static const GInterfaceInfo iface_info =
+{
+ .interface_init = (GInterfaceInitFunc) iface_init,
+ .interface_finalize = NULL,
+ .interface_data = NULL,
+};
+
+static GType list_model_get_type (void)
+{
+ static GType type = G_TYPE_INVALID;
+ if (type == G_TYPE_INVALID)
+ {
+ type = g_type_register_static_simple (G_TYPE_OBJECT, "AudguiListModel",
+ sizeof (GObjectClass), NULL, sizeof (ListModel), NULL, 0);
+ g_type_add_interface_static (type, GTK_TYPE_TREE_MODEL, & iface_info);
+ }
+ return type;
+}
+
+/* ==== CALLBACKS ==== */
+
+static gboolean select_allow_cb (GtkTreeSelection * sel, GtkTreeModel * model,
+ GtkTreePath * path, gboolean was, void * user)
+{
+ return ! ((ListModel *) model)->frozen;
+}
+
+static void select_row_cb (GtkTreeModel * _model, GtkTreePath * path,
+ GtkTreeIter * iter, void * user)
+{
+ ListModel * model = (ListModel *) _model;
+ gint row = gtk_tree_path_get_indices (path)[0];
+ g_return_if_fail (row >= 0 && row < model->rows);
+ model->cbs->set_selected (model->user, row, TRUE);
+}
+
+static void select_cb (GtkTreeSelection * sel, ListModel * model)
+{
+ if (model->blocked)
+ return;
+ model->cbs->select_all (model->user, FALSE);
+ gtk_tree_selection_selected_foreach (sel, select_row_cb, NULL);
+}
+
+static void activate_cb (GtkTreeView * tree, GtkTreePath * path,
+ GtkTreeViewColumn * col, ListModel * model)
+{
+ gint row = gtk_tree_path_get_indices (path)[0];
+ g_return_if_fail (row >= 0 && row < model->rows);
+ model->cbs->activate_row (model->user, row);
+}
+
+static gboolean button_press_cb (GtkWidget * widget, GdkEventButton * event,
+ ListModel * model)
+{
+ GtkTreePath * path = NULL;
+ gtk_tree_view_get_path_at_pos ((GtkTreeView *) widget, event->x, event->y,
+ & path, NULL, NULL, NULL);
+
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3 &&
+ model->cbs->right_click)
+ {
+ /* Only allow GTK to select this row if it is not already selected. We
+ * don't want to clear a multiple selection. */
+ if (path)
+ {
+ if (PATH_IS_SELECTED (widget, path))
+ model->frozen = TRUE;
+ gtk_tree_view_set_cursor ((GtkTreeView *) widget, path, NULL, FALSE);
+ model->frozen = FALSE;
+ }
+
+ model->cbs->right_click (model->user, event);
+
+ if (path)
+ gtk_tree_path_free (path);
+ return TRUE;
+ }
+
+ /* Only allow GTK to select this row if it is not already selected. If we
+ * are going to be dragging, we don't want to clear a multiple selection.
+ * If this is just a simple click, we will clear the multiple selection in
+ * button_release_cb. */
+ if (event->type == GDK_BUTTON_PRESS && event->button == 1 && ! (event->state
+ & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) && path && PATH_IS_SELECTED (widget,
+ path))
+ model->frozen = TRUE;
+
+ if (path)
+ model->clicked_row = gtk_tree_path_get_indices (path)[0];
+ else
+ model->clicked_row = -1;
+
+ if (path)
+ gtk_tree_path_free (path);
+ return FALSE;
+}
+
+static gboolean button_release_cb (GtkWidget * widget, GdkEventButton * event,
+ ListModel * model)
+{
+ /* If button_press_cb set "frozen", and we were not dragging, we need to
+ * clear a multiple selection. */
+ if (model->frozen && model->clicked_row >= 0 && model->clicked_row <
+ model->rows)
+ {
+ model->frozen = FALSE;
+ GtkTreePath * path = gtk_tree_path_new_from_indices (model->clicked_row,
+ -1);
+ gtk_tree_view_set_cursor ((GtkTreeView *) widget, path, NULL, FALSE);
+ gtk_tree_path_free (path);
+ }
+
+ return FALSE;
+}
+
+/* ==== DRAG AND DROP ==== */
+
+static void drag_begin (GtkWidget * widget, GdkDragContext * context,
+ ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-begin");
+
+ model->dragging = TRUE;
+}
+
+static void drag_end (GtkWidget * widget, GdkDragContext * context,
+ ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-end");
+
+ model->dragging = FALSE;
+ model->clicked_row = -1;
+}
+
+static void drag_data_get (GtkWidget * widget, GdkDragContext * context,
+ GtkSelectionData * sel, guint info, guint time, ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-data-get");
+
+ void * data = NULL;
+ gint length = 0;
+ model->cbs->get_data (model->user, & data, & length);
+ gtk_selection_data_set (sel, gdk_atom_intern (model->cbs->data_type, FALSE),
+ 8, data, length);
+ g_free (data);
+}
+
+static gint calc_drop_row (ListModel * model, GtkWidget * widget, gint x, gint y)
+{
+ gint row = audgui_list_row_at_point (widget, x, y);
+ if (row < 0)
+ row = model->rows;
+ return row;
+}
+
+static void stop_autoscroll (ListModel * model)
+{
+ if (! model->scroll_source)
+ return;
+
+ g_source_remove (model->scroll_source);
+ model->scroll_source = 0;
+ model->scroll_speed = 0;
+}
+
+static gboolean autoscroll (GtkWidget * widget)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) widget);
+
+ GtkAdjustment * adj = gtk_tree_view_get_vadjustment ((GtkTreeView *) widget);
+ if (! adj)
+ return FALSE;
+
+ gint new = gtk_adjustment_get_value (adj) + model->scroll_speed;
+ gint clamped = CLAMP (new, 0, gtk_adjustment_get_upper (adj) -
+ gtk_adjustment_get_page_size (adj));
+ gtk_adjustment_set_value (adj, clamped);
+
+ if (clamped != new) /* reached top or bottom? */
+ return FALSE;
+
+ if (model->scroll_speed > 0)
+ model->scroll_speed = MIN (model->scroll_speed + 2, 100);
+ else
+ model->scroll_speed = MAX (model->scroll_speed - 2, -100);
+
+ return TRUE;
+}
+
+static void start_autoscroll (ListModel * model, GtkWidget * widget, gint speed)
+{
+ if (model->scroll_source)
+ return;
+
+ model->scroll_source = g_timeout_add (50, (GSourceFunc) autoscroll, widget);
+ model->scroll_speed = speed;
+}
+
+static gboolean drag_motion (GtkWidget * widget, GdkDragContext * context,
+ gint x, gint y, guint time, ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-motion");
+
+ /* If button_press_cb preserved a multiple selection, tell button_release_cb
+ * not to clear it. */
+ model->frozen = FALSE;
+
+ if (model->dragging && model->cbs->shift_rows) /* dragging within same list */
+ gdk_drag_status (context, GDK_ACTION_MOVE, time);
+ else if (model->cbs->data_type) /* cross-widget dragging */
+ gdk_drag_status (context, GDK_ACTION_COPY, time);
+ else
+ return FALSE;
+
+ if (model->rows > 0)
+ {
+ gint row = calc_drop_row (model, widget, x, y);
+ if (row == model->rows)
+ {
+ GtkTreePath * path = gtk_tree_path_new_from_indices (row - 1, -1);
+ gtk_tree_view_set_drag_dest_row ((GtkTreeView *) widget, path,
+ GTK_TREE_VIEW_DROP_AFTER);
+ gtk_tree_path_free (path);
+ }
+ else
+ {
+ GtkTreePath * path = gtk_tree_path_new_from_indices (row, -1);
+ gtk_tree_view_set_drag_dest_row ((GtkTreeView *) widget, path,
+ GTK_TREE_VIEW_DROP_BEFORE);
+ gtk_tree_path_free (path);
+ }
+ }
+
+ gint height;
+ gdk_window_get_geometry (gtk_tree_view_get_bin_window ((GtkTreeView *)
+ widget), NULL, NULL, NULL, & height);
+ gtk_tree_view_convert_widget_to_bin_window_coords ((GtkTreeView *) widget,
+ x, y, & x, & y);
+
+ if (y >= 0 && y < 48)
+ start_autoscroll (model, widget, -2);
+ else if (y >= height - 48 && y < height)
+ start_autoscroll (model, widget, 2);
+ else
+ stop_autoscroll (model);
+
+ return TRUE;
+}
+
+static void drag_leave (GtkWidget * widget, GdkDragContext * context,
+ guint time, ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-leave");
+
+ gtk_tree_view_set_drag_dest_row ((GtkTreeView *) widget, NULL, 0);
+ stop_autoscroll (model);
+}
+
+static gboolean drag_drop (GtkWidget * widget, GdkDragContext * context, gint x,
+ gint y, guint time, ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-drop");
+
+ gboolean success = TRUE;
+ gint row = calc_drop_row (model, widget, x, y);
+
+ if (model->dragging && model->cbs->shift_rows) /* dragging within same list */
+ {
+ if (model->clicked_row >= 0 && model->clicked_row < model->rows)
+ model->cbs->shift_rows (model->user, model->clicked_row, row);
+ else
+ success = FALSE;
+ }
+ else if (model->cbs->data_type) /* cross-widget dragging */
+ {
+ model->receive_row = row;
+ gtk_drag_get_data (widget, context, gdk_atom_intern
+ (model->cbs->data_type, FALSE), time);
+ }
+ else
+ success = FALSE;
+
+ gtk_drag_finish (context, success, FALSE, time);
+ gtk_tree_view_set_drag_dest_row ((GtkTreeView *) widget, NULL, 0);
+ stop_autoscroll (model);
+ return TRUE;
+}
+
+static void drag_data_received (GtkWidget * widget, GdkDragContext * context, gint x,
+ gint y, GtkSelectionData * sel, guint info, guint time, ListModel * model)
+{
+ g_signal_stop_emission_by_name (widget, "drag-data-received");
+
+ g_return_if_fail (model->receive_row >= 0 && model->receive_row <=
+ model->rows);
+
+ const guchar * data = gtk_selection_data_get_data (sel);
+ gint length = gtk_selection_data_get_length (sel);
+
+ if (data && length)
+ model->cbs->receive_data (model->user, model->receive_row, data, length);
+
+ model->receive_row = -1;
+}
+
+/* ==== PUBLIC FUNCS ==== */
+
+static void destroy_cb (ListModel * model)
+{
+ stop_autoscroll (model);
+ g_object_unref (model);
+}
+
+static void update_selection (GtkWidget * list, ListModel * model, gint at,
+ gint rows)
+{
+ model->blocked = TRUE;
+ GtkTreeSelection * sel = gtk_tree_view_get_selection ((GtkTreeView *) list);
+
+ for (gint i = at; i < at + rows; i ++)
+ {
+ GtkTreeIter iter = {.user_data = GINT_TO_POINTER (i)};
+ if (model->cbs->get_selected (model->user, i))
+ gtk_tree_selection_select_iter (sel, & iter);
+ else
+ gtk_tree_selection_unselect_iter (sel, & iter);
+ }
+
+ model->blocked = FALSE;
+}
+
+GtkWidget * audgui_list_new (const AudguiListCallbacks * cbs, void * user,
+ gint rows)
+{
+ g_return_val_if_fail (cbs->get_value, NULL);
+ if (cbs->get_selected)
+ g_return_val_if_fail (cbs->set_selected && cbs->select_all, NULL);
+ if (cbs->data_type)
+ g_return_val_if_fail (cbs->get_data && cbs->receive_data, NULL);
+
+ ListModel * model = (ListModel *) g_object_new (list_model_get_type (), NULL);
+ model->cbs = cbs;
+ model->user = user;
+ model->rows = rows;
+ model->highlight = -1;
+ model->columns = RESERVED_COLUMNS;
+ model->column_types = NULL;
+ model->frozen = FALSE;
+ model->blocked = FALSE;
+ model->dragging = FALSE;
+ model->clicked_row = -1;
+ model->receive_row = -1;
+ model->scroll_source = 0;
+ model->scroll_speed = 0;
+
+ GtkWidget * list = gtk_tree_view_new_with_model ((GtkTreeModel *) model);
+ g_signal_connect_swapped (list, "destroy", (GCallback) destroy_cb, model);
+
+ if (cbs->get_selected)
+ {
+ GtkTreeSelection * sel = gtk_tree_view_get_selection
+ ((GtkTreeView *) list);
+ gtk_tree_selection_set_mode (sel, GTK_SELECTION_MULTIPLE);
+ gtk_tree_selection_set_select_function (sel, select_allow_cb, NULL, NULL);
+ g_signal_connect (sel, "changed", (GCallback) select_cb, model);
+
+ update_selection (list, model, 0, rows);
+ }
+
+ if (cbs->activate_row)
+ g_signal_connect (list, "row-activated", (GCallback) activate_cb, model);
+
+ g_signal_connect (list, "button-press-event", (GCallback) button_press_cb,
+ model);
+ g_signal_connect (list, "button-release-event", (GCallback)
+ button_release_cb, model);
+
+ if (cbs->data_type)
+ {
+ const GtkTargetEntry target = {(gchar *) cbs->data_type, 0, 0};
+
+ gtk_drag_source_set (list, GDK_BUTTON1_MASK, & target, 1,
+ GDK_ACTION_COPY);
+ gtk_drag_dest_set (list, 0, & target, 1, GDK_ACTION_COPY);
+
+ g_signal_connect (list, "drag-data-get", (GCallback) drag_data_get,
+ model);
+ g_signal_connect (list, "drag-data-received", (GCallback)
+ drag_data_received, model);
+ }
+ else if (cbs->shift_rows)
+ {
+ gtk_drag_source_set (list, GDK_BUTTON1_MASK, NULL, 0, GDK_ACTION_COPY);
+ gtk_drag_dest_set (list, 0, NULL, 0, GDK_ACTION_COPY);
+ }
+
+ if (cbs->data_type || cbs->shift_rows)
+ {
+ g_signal_connect (list, "drag-begin", (GCallback) drag_begin, model);
+ g_signal_connect (list, "drag-end", (GCallback) drag_end, model);
+ g_signal_connect (list, "drag-motion", (GCallback) drag_motion, model);
+ g_signal_connect (list, "drag-leave", (GCallback) drag_leave, model);
+ g_signal_connect (list, "drag-drop", (GCallback) drag_drop, model);
+ }
+
+ return list;
+}
+
+void * audgui_list_get_user (GtkWidget * list)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ return model->user;
+}
+
+void audgui_list_add_column (GtkWidget * list, const gchar * title,
+ gint column, GType type, gboolean expand)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (RESERVED_COLUMNS + column == model->columns);
+
+ model->columns ++;
+ model->column_types = g_list_append (model->column_types, GINT_TO_POINTER
+ (type));
+
+ GtkCellRenderer * renderer = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn * tree_column = gtk_tree_view_column_new_with_attributes
+ (title, renderer, "text", RESERVED_COLUMNS + column, "weight",
+ HIGHLIGHT_COLUMN, NULL);
+
+ if (expand)
+ {
+ gtk_tree_view_column_set_resizable (tree_column, TRUE);
+ gtk_tree_view_column_set_expand (tree_column, TRUE);
+ g_object_set ((GObject *) renderer, "ellipsize-set", TRUE, "ellipsize",
+ PANGO_ELLIPSIZE_END, NULL);
+ }
+ else
+ {
+ gtk_tree_view_column_set_sizing (tree_column,
+ GTK_TREE_VIEW_COLUMN_GROW_ONLY);
+ g_object_set ((GObject *) renderer, "xalign", (gfloat) 1, NULL);
+ }
+
+ gtk_tree_view_append_column ((GtkTreeView *) list, tree_column);
+}
+
+gint audgui_list_row_count (GtkWidget * list)
+{
+ return ((ListModel *) gtk_tree_view_get_model ((GtkTreeView *) list))->rows;
+}
+
+void audgui_list_insert_rows (GtkWidget * list, gint at, gint rows)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (at >= 0 && at <= model->rows && rows >= 0);
+
+ model->rows += rows;
+ if (model->highlight >= at)
+ model->highlight += rows;
+
+ GtkTreeIter iter = {.user_data = GINT_TO_POINTER (at)};
+ GtkTreePath * path = gtk_tree_path_new_from_indices (at, -1);
+
+ for (gint i = rows; i --; )
+ gtk_tree_model_row_inserted ((GtkTreeModel *) model, path, & iter);
+
+ gtk_tree_path_free (path);
+
+ update_selection (list, model, at, rows);
+}
+
+void audgui_list_update_rows (GtkWidget * list, gint at, gint rows)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (at >= 0 && rows >= 0 && at + rows <= model->rows);
+
+ GtkTreeIter iter = {.user_data = GINT_TO_POINTER (at)};
+ GtkTreePath * path = gtk_tree_path_new_from_indices (at, -1);
+
+ while (rows --)
+ {
+ gtk_tree_model_row_changed ((GtkTreeModel *) model, path, & iter);
+ iter.user_data = GINT_TO_POINTER (GPOINTER_TO_INT (iter.user_data) + 1);
+ gtk_tree_path_next (path);
+ }
+
+ gtk_tree_path_free (path);
+}
+
+void audgui_list_delete_rows (GtkWidget * list, gint at, gint rows)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (at >= 0 && rows >= 0 && at + rows <= model->rows);
+
+ model->rows -= rows;
+ if (model->highlight >= at + rows)
+ model->highlight -= rows;
+ else if (model->highlight >= at)
+ model->highlight = -1;
+
+ model->blocked = TRUE;
+ GtkTreePath * path = gtk_tree_path_new_from_indices (at, -1);
+
+ while (rows --)
+ gtk_tree_model_row_deleted ((GtkTreeModel *) model, path);
+
+ gtk_tree_path_free (path);
+ model->blocked = FALSE;
+}
+
+void audgui_list_update_selection (GtkWidget * list, gint at, gint rows)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (model->cbs->get_selected);
+ g_return_if_fail (at >= 0 && rows >= 0 && at + rows <= model->rows);
+ update_selection (list, model, at, rows);
+}
+
+void audgui_list_set_highlight (GtkWidget * list, gint row)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (row >= -1 && row < model->rows);
+
+ gint old = model->highlight;
+ if (row == old)
+ return;
+ model->highlight = row;
+
+ if (old >= 0)
+ audgui_list_update_rows (list, old, 1);
+ if (row >= 0)
+ audgui_list_update_rows (list, row, 1);
+}
+
+void audgui_list_set_focus (GtkWidget * list, gint row)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model
+ ((GtkTreeView *) list);
+ g_return_if_fail (row >= -1 && row < model->rows);
+
+ if (row < 0)
+ {
+ if (model->rows < 1)
+ return;
+ row = 0;
+ }
+
+ model->frozen = TRUE;
+ GtkTreePath * path = gtk_tree_path_new_from_indices (row, -1);
+ gtk_tree_view_set_cursor ((GtkTreeView *) list, path, NULL, FALSE);
+ gtk_tree_view_scroll_to_cell ((GtkTreeView *) list, path, NULL, FALSE, 0, 0);
+ gtk_tree_path_free (path);
+ model->frozen = FALSE;
+}
+
+gint audgui_list_row_at_point (GtkWidget * list, gint x, gint y)
+{
+ ListModel * model = (ListModel *) gtk_tree_view_get_model ((GtkTreeView *)
+ list);
+
+ GtkTreePath * path = NULL;
+ gtk_tree_view_convert_widget_to_bin_window_coords ((GtkTreeView *) list, x,
+ y, & x, & y);
+ gtk_tree_view_get_path_at_pos ((GtkTreeView *) list, x, y, & path, NULL,
+ NULL, NULL);
+
+ if (! path)
+ return -1;
+
+ gint row = gtk_tree_path_get_indices (path)[0];
+ g_return_val_if_fail (row >= 0 && row < model->rows, -1);
+
+ GdkRectangle rect;
+ gtk_tree_view_get_background_area ((GtkTreeView *) list, path, NULL,
+ & rect);
+ if (y > rect.y + rect.height / 2)
+ row ++;
+
+ gtk_tree_path_free (path);
+ return row;
+}
diff --git a/src/libaudgui/list.h b/src/libaudgui/list.h
new file mode 100644
index 0000000..0eb1cef
--- /dev/null
+++ b/src/libaudgui/list.h
@@ -0,0 +1,61 @@
+/*
+ * list.h
+ * Copyright 2011 John Lindgren
+ *
+ * This file is part of Audacious.
+ *
+ * Audacious 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, version 2 or version 3 of the License.
+ *
+ * Audacious is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * Audacious. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The Audacious team does not consider modular code linking to Audacious or
+ * using our public API to be a derived work.
+ */
+
+#ifndef AUDGUI_LIST_H
+#define AUDGUI_LIST_H
+
+#include <gtk/gtk.h>
+
+typedef struct {
+ void (* get_value) (void * user, gint row, gint column, GValue * value);
+
+ /* selection (optional) */
+ gboolean (* get_selected) (void * user, gint row);
+ void (* set_selected) (void * user, gint row, gboolean selected);
+ void (* select_all) (void * user, gboolean selected);
+
+ void (* activate_row) (void * user, gint row); /* optional */
+ void (* right_click) (void * user, GdkEventButton * event); /* optional */
+ void (* shift_rows) (void * user, gint row, gint before); /* optional */
+
+ /* cross-widget drag and drop (optional) */
+ const gchar * data_type;
+ void (* get_data) (void * user, void * * data, gint * length); /* data will
+ be freed */
+ void (* receive_data) (void * user, gint row, const void * data, gint length);
+} AudguiListCallbacks;
+
+GtkWidget * audgui_list_new (const AudguiListCallbacks * cbs, void * user,
+ gint rows);
+void * audgui_list_get_user (GtkWidget * list);
+void audgui_list_add_column (GtkWidget * list, const gchar * title,
+ gint column, GType type, gboolean expand);
+
+gint audgui_list_row_count (GtkWidget * list);
+void audgui_list_insert_rows (GtkWidget * list, gint at, gint rows);
+void audgui_list_update_rows (GtkWidget * list, gint at, gint rows);
+void audgui_list_delete_rows (GtkWidget * list, gint at, gint rows);
+void audgui_list_update_selection (GtkWidget * list, gint at, gint rows);
+void audgui_list_set_highlight (GtkWidget * list, gint row);
+void audgui_list_set_focus (GtkWidget * list, gint row);
+gint audgui_list_row_at_point (GtkWidget * list, gint x, gint y);
+
+#endif
diff --git a/src/libaudgui/ui_about.c b/src/libaudgui/ui_about.c
index 29a2a3d..caeac03 100644
--- a/src/libaudgui/ui_about.c
+++ b/src/libaudgui/ui_about.c
@@ -24,6 +24,8 @@
* Audacious or using our public API to be a derived work.
*/
+#include <limits.h>
+
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
@@ -34,79 +36,22 @@
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/misc.h>
-#include "audacious/compatibility.h"
+#include "libaudgui-gtk.h"
-#include "ui_credits.h"
+/* ui_credits.c */
+GtkWidget * audgui_get_credits_widget (void);
static GtkWidget *about_window = NULL;
-static GdkPixbuf *about_pixbuf = NULL;
-static GdkPixmap *mask_pixmap_window1 = NULL,
- *mask_pixmap_window2 = NULL;
-static GdkBitmap *mask_bitmap_window1 = NULL,
- *mask_bitmap_window2 = NULL;
-
-static gboolean
-on_about_window_expose(GtkWidget *widget, GdkEventExpose *expose, gpointer data)
-{
- GdkWindow *window;
-
- g_return_val_if_fail(widget != NULL, FALSE);
- g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
- window = gtk_widget_get_window(widget);
- gdk_window_set_back_pixmap(window, mask_pixmap_window2, 0);
- gdk_window_clear(window);
-
- return FALSE;
-}
-
-static gboolean
-on_about_window_key_press (GtkWidget *widget, GdkEventKey *event, gpointer data)
-{
- g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
- if (event->keyval == GDK_Escape)
- {
- gtk_widget_hide(widget);
- }
-
- return FALSE;
-}
-
-static gboolean
-on_close_button_clicked (GtkWidget *widget, gpointer data)
-{
- g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
- gtk_widget_hide(about_window);
-
- return FALSE;
-}
-
-static gboolean
-on_credits_button_clicked (GtkWidget *widget, gpointer data)
-{
- g_return_val_if_fail(GTK_IS_WIDGET (widget), FALSE);
-
- audgui_show_credits_window();
-
- return FALSE;
-}
void
audgui_show_about_window(void)
{
- GtkWidget *about_fixedbox;
- GtkWidget *close_button;
- GtkWidget *credits_button , *credits_button_hbox, *credits_button_image, *credits_button_label;
GtkWidget *brief_label;
- gchar *filename = DATA_DIR G_DIR_SEPARATOR_S "images" G_DIR_SEPARATOR_S "about-logo.png";
gchar *text;
- PangoAttrList *brief_label_attrs;
- PangoAttribute *brief_label_foreground;
static const gchar *audacious_brief;
if (about_window != NULL)
@@ -118,99 +63,38 @@ audgui_show_about_window(void)
aud_get_audacious_credits(&audacious_brief, NULL, NULL);
about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_container_set_border_width ((GtkContainer *) about_window, 3);
g_signal_connect(about_window, "destroy",
G_CALLBACK(gtk_widget_destroyed), &about_window);
- gtk_widget_realize(about_window);
-
- about_pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
-
- gtk_widget_set_size_request(GTK_WIDGET (about_window),
- gdk_pixbuf_get_width (about_pixbuf),
- gdk_pixbuf_get_height (about_pixbuf));
-
- gtk_widget_set_app_paintable(about_window, TRUE);
gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
- gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
gtk_window_set_resizable(GTK_WINDOW(about_window), FALSE);
- gtk_window_set_decorated(GTK_WINDOW(about_window), FALSE);
-
- gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
- &mask_pixmap_window1,
- &mask_bitmap_window1,
- 0);
-
- gdk_pixbuf_render_pixmap_and_mask(about_pixbuf,
- &mask_pixmap_window2,
- &mask_bitmap_window2,
- 128);
-
- gtk_widget_add_events(about_window, GDK_ALL_EVENTS_MASK);
-
- g_signal_connect(about_window, "expose-event",
- G_CALLBACK(on_about_window_expose), &about_window);
-
- g_signal_connect(about_window, "key-press-event",
- G_CALLBACK(on_about_window_key_press), &about_window);
-
- gtk_widget_shape_combine_mask(GTK_WIDGET(about_window), mask_bitmap_window2, 0, 0);
-
- /* GtkFixed hasn't got its GdkWindow, this means that it can be used to
- display widgets while the logo below will be displayed anyway;
- however fixed positions are not that great, cause the button sizes may (will)
- vary depending on the gtk style used, so it's not possible to center
- them unless a fixed width and heigth is forced (and this may bring to cutted
- text if someone, i.e., uses a big font for gtk widgets);
- other types of container most likely have their GdkWindow, this simply
- means that the logo must be drawn on the container widget, instead of the
- window; otherwise, it won't be displayed correctly */
- about_fixedbox = gtk_fixed_new();
- gtk_container_add( GTK_CONTAINER(about_window) , about_fixedbox );
-
- close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
-
- g_signal_connect(close_button, "clicked",
- G_CALLBACK(on_close_button_clicked), NULL);
-
- gtk_fixed_put( GTK_FIXED(about_fixedbox) , close_button , 375 , 220 );
- gtk_widget_set_size_request( close_button , 100 , -1 );
-
- credits_button = gtk_button_new();
- credits_button_hbox = gtk_hbox_new( FALSE , 0 );
- credits_button_image = gtk_image_new_from_stock( GTK_STOCK_DIALOG_INFO , GTK_ICON_SIZE_BUTTON );
- gtk_misc_set_alignment( GTK_MISC(credits_button_image) , 1 , 0.5 );
- credits_button_label = gtk_label_new( _("Credits") );
- gtk_misc_set_alignment( GTK_MISC(credits_button_label) , 0 , 0.5 );
- gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_image ,
- TRUE , TRUE , 2 );
- gtk_box_pack_start( GTK_BOX(credits_button_hbox) , credits_button_label ,
- TRUE , TRUE , 2 );
- gtk_container_add( GTK_CONTAINER(credits_button) , credits_button_hbox );
-
- g_signal_connect(credits_button, "clicked",
- G_CALLBACK(on_credits_button_clicked), NULL);
-
- gtk_fixed_put( GTK_FIXED(about_fixedbox) , credits_button , 25 , 220 );
- gtk_widget_set_size_request( credits_button , 100 , -1 );
+ audgui_destroy_on_escape (about_window);
+
+ GtkWidget * vbox = gtk_vbox_new (FALSE, 6);
+ gtk_container_add ((GtkContainer *) about_window, vbox);
+
+ gchar name[PATH_MAX];
+ snprintf (name, sizeof name, "%s/images/about-logo.png", aud_get_path
+ (AUD_PATH_DATA_DIR));
+ GtkWidget * image = gtk_image_new_from_file (name);
+ gtk_box_pack_start ((GtkBox *) vbox, image, FALSE, FALSE, 0);
brief_label = gtk_label_new(NULL);
text = g_strdup_printf(_(audacious_brief), VERSION);
- brief_label_foreground = pango_attr_foreground_new(0, 0, 0);
- brief_label_attrs = pango_attr_list_new();
- pango_attr_list_insert(brief_label_attrs, brief_label_foreground);
-
gtk_label_set_markup(GTK_LABEL(brief_label), text);
gtk_label_set_justify(GTK_LABEL(brief_label), GTK_JUSTIFY_CENTER);
- gtk_label_set_attributes(GTK_LABEL(brief_label), brief_label_attrs);
g_free(text);
+
+ gtk_box_pack_start ((GtkBox *) vbox, brief_label, FALSE, FALSE, 0);
- gtk_fixed_put(GTK_FIXED(about_fixedbox), brief_label, 20, 145);
- gtk_widget_set_size_request( brief_label , 460 , -1 );
+ GtkWidget * exp = gtk_expander_new (_("Credits"));
+ gtk_container_add ((GtkContainer *) exp, audgui_get_credits_widget ());
+ gtk_box_pack_start ((GtkBox *) vbox, exp, TRUE, TRUE, 0);
gtk_widget_show_all(about_window);
- gtk_window_present(GTK_WINDOW(about_window));
}
void
diff --git a/src/libaudgui/ui_credits.c b/src/libaudgui/ui_credits.c
index 4f3732f..ec7f0f6 100644
--- a/src/libaudgui/ui_credits.c
+++ b/src/libaudgui/ui_credits.c
@@ -30,14 +30,10 @@
#include <glib.h>
#include <gtk/gtk.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/misc.h>
-#include "audacious/compatibility.h"
-
-#include "ui_credits.h"
-#include "audacious_logo.xpm"
-
enum {
COL_LEFT,
COL_RIGHT,
@@ -104,81 +100,22 @@ generate_credit_list(const gchar * text[], gboolean sec_space)
GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin), GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(scrollwin), treeview);
- gtk_container_set_border_width(GTK_CONTAINER(scrollwin), 10);
-
- gtk_widget_show_all(scrollwin);
+ gtk_container_set_border_width ((GtkContainer *) scrollwin, 4);
return scrollwin;
}
-void
-audgui_show_credits_window(void)
+GtkWidget * audgui_get_credits_widget (void)
{
- static GtkWidget *about_window = NULL;
-
- GdkPixbuf *logo_pixbuf;
- GtkWidget *about_vbox;
- GtkWidget *about_credits_logo_box, *about_credits_logo_frame;
- GtkWidget *about_credits_logo;
GtkWidget *about_notebook;
GtkWidget *list;
- GtkWidget *bbox, *close_btn;
- GtkWidget *label;
- gchar *text;
- static const gchar *audacious_brief;
- static const gchar **credit_text;
- static const gchar **translators;
-
- if (about_window)
- return;
-
- aud_get_audacious_credits(&audacious_brief, &credit_text, &translators);
-
- about_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- gtk_window_set_type_hint(GTK_WINDOW(about_window),
- GDK_WINDOW_TYPE_HINT_DIALOG);
-
- gtk_window_set_default_size(GTK_WINDOW(about_window), -1, 512);
- gtk_window_set_title(GTK_WINDOW(about_window), _("About Audacious"));
- gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_CENTER);
- gtk_window_set_resizable(GTK_WINDOW(about_window), TRUE);
- gtk_container_set_border_width(GTK_CONTAINER(about_window), 10);
-
- g_signal_connect(about_window, "destroy",
- G_CALLBACK(gtk_widget_destroyed), &about_window);
-
- gtk_widget_realize(about_window);
+ const gchar **credit_text;
+ const gchar **translators;
- about_vbox = gtk_vbox_new(FALSE, 5);
- gtk_container_add(GTK_CONTAINER(about_window), about_vbox);
-
- logo_pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)audacious_logo_xpm);
-
- about_credits_logo_box = gtk_hbox_new(TRUE, 0);
- gtk_box_pack_start(GTK_BOX(about_vbox), about_credits_logo_box,
- FALSE, FALSE, 0);
-
- about_credits_logo_frame = gtk_frame_new(NULL);
- gtk_frame_set_shadow_type(GTK_FRAME(about_credits_logo_frame),
- GTK_SHADOW_ETCHED_OUT);
- gtk_box_pack_start(GTK_BOX(about_credits_logo_box),
- about_credits_logo_frame, FALSE, FALSE, 0);
-
- about_credits_logo = gtk_image_new_from_pixbuf(logo_pixbuf);
- gtk_container_add(GTK_CONTAINER(about_credits_logo_frame),
- about_credits_logo);
- g_object_unref(logo_pixbuf);
-
- label = gtk_label_new(NULL);
- text = g_strdup_printf(_(audacious_brief), VERSION);
- gtk_label_set_markup(GTK_LABEL(label), text);
- gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
- g_free(text);
-
- gtk_box_pack_start(GTK_BOX(about_vbox), label, FALSE, FALSE, 0);
+ aud_get_audacious_credits (NULL, &credit_text, &translators);
about_notebook = gtk_notebook_new();
- gtk_box_pack_start(GTK_BOX(about_vbox), about_notebook, TRUE, TRUE, 0);
+ gtk_widget_set_size_request (about_notebook, -1, 250);
list = generate_credit_list(credit_text, TRUE);
gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
@@ -188,18 +125,5 @@ audgui_show_credits_window(void)
gtk_notebook_append_page(GTK_NOTEBOOK(about_notebook), list,
gtk_label_new(_("Translators")));
- bbox = gtk_hbutton_box_new();
- gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
- gtk_box_set_spacing(GTK_BOX(bbox), 5);
- gtk_box_pack_start(GTK_BOX(about_vbox), bbox, FALSE, FALSE, 0);
-
- close_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
- g_signal_connect_swapped(close_btn, "clicked",
- G_CALLBACK(gtk_widget_destroy), about_window);
-
- gtk_widget_set_can_default(close_btn, TRUE);
- gtk_box_pack_start(GTK_BOX(bbox), close_btn, TRUE, TRUE, 0);
- gtk_widget_grab_default(close_btn);
-
- gtk_widget_show_all(about_window);
+ return about_notebook;
}
diff --git a/src/libaudgui/ui_credits.h b/src/libaudgui/ui_credits.h
deleted file mode 100644
index fe30775..0000000
--- a/src/libaudgui/ui_credits.h
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#ifndef AUDACIOUS_UI_CREDITS_H
-#define AUDACIOUS_UI_CREDITS_H
-
-void audgui_show_about_window(void);
-void audgui_hide_about_window(void);
-void audgui_show_credits_window(void);
-
-#endif /* AUDACIOUS_UI_CREDITS_H */
diff --git a/src/libaudgui/ui_fileopener.c b/src/libaudgui/ui_fileopener.c
index a0eb83b..b7d6794 100644..100755
--- a/src/libaudgui/ui_fileopener.c
+++ b/src/libaudgui/ui_fileopener.c
@@ -22,6 +22,7 @@
#include <audacious/audconfig.h>
#include <audacious/i18n.h>
#include <audacious/drct.h>
+#include <audacious/gtk-compat.h>
#include "config.h"
#include "libaudgui.h"
@@ -144,6 +145,9 @@ run_filebrowser_gtk2style(gboolean play_button, gboolean show)
gtk_container_add(GTK_CONTAINER(bbox), close_button);
gtk_container_add(GTK_CONTAINER(bbox), action_button);
+ gtk_widget_set_can_default (action_button, TRUE);
+ gtk_widget_grab_default (action_button);
+
/* this storage object holds several other objects which are used in the
* callback functions
*/
diff --git a/src/libaudgui/ui_gtk.c b/src/libaudgui/ui_gtk.c
index fa8d4e8..24d2fe5 100644
--- a/src/libaudgui/ui_gtk.c
+++ b/src/libaudgui/ui_gtk.c
@@ -19,8 +19,14 @@
#include <gtk/gtk.h>
+#include <audacious/misc.h>
+
void audgui_set_default_icon (void)
{
+#ifdef _WIN32
+ gtk_window_set_default_icon_from_file (aud_get_path (AUD_PATH_ICON_FILE),
+ NULL);
+#else
gtk_window_set_default_icon_name ("audacious");
+#endif
}
-
diff --git a/src/libaudgui/ui_jumptotrack.c b/src/libaudgui/ui_jumptotrack.c
index a97d30e..52f3f24 100644
--- a/src/libaudgui/ui_jumptotrack.c
+++ b/src/libaudgui/ui_jumptotrack.c
@@ -27,38 +27,25 @@
# include "config.h"
#endif
-
-#include <glib.h>
-#include <glib/gprintf.h>
-#include <gtk/gtk.h>
-
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
-#if defined(USE_REGEX_ONIGURUMA)
- #include <onigposix.h>
-#elif defined(USE_REGEX_PCRE)
- #include <pcreposix.h>
-#else
- #include <regex.h>
-#endif
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
#include <audacious/audconfig.h>
#include <audacious/drct.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/playlist.h>
#include <libaudcore/hook.h>
-#include "audacious/compatibility.h"
-
#include "icons-stock.h"
#include "ui_jumptotrack_cache.h"
+#include "ui_regex.h"
static void watchdog (void * hook_data, void * user_data);
diff --git a/src/libaudgui/ui_jumptotrack_cache.c b/src/libaudgui/ui_jumptotrack_cache.c
index 9d4fd8a..97202d0 100644
--- a/src/libaudgui/ui_jumptotrack_cache.c
+++ b/src/libaudgui/ui_jumptotrack_cache.c
@@ -28,18 +28,11 @@
# include "sys/types.h"
#endif
-#if defined(USE_REGEX_ONIGURUMA)
- #include <onigposix.h>
-#elif defined(USE_REGEX_PCRE)
- #include <pcreposix.h>
-#else
- #include <regex.h>
-#endif
-
#include <audacious/debug.h>
#include <audacious/playlist.h>
#include "ui_jumptotrack_cache.h"
+#include "ui_regex.h"
// Struct to keep information about matches from searches.
typedef struct
diff --git a/src/libaudgui/ui_playlist_manager.c b/src/libaudgui/ui_playlist_manager.c
index e554812..09ec102 100644
--- a/src/libaudgui/ui_playlist_manager.c
+++ b/src/libaudgui/ui_playlist_manager.c
@@ -1,5 +1,5 @@
/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2010 Audacious development team.
+ * Copyright (C) 2005-2011 Audacious development team.
*
* 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
@@ -17,7 +17,10 @@
* Audacious or using our public API to be a derived work.
*/
+#include <gtk/gtk.h>
+
#include <audacious/audconfig.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/playlist.h>
#include <libaudcore/hook.h>
@@ -25,38 +28,9 @@
#include "config.h"
#include "libaudgui.h"
#include "libaudgui-gtk.h"
+#include "list.h"
-static gint iter_to_row (GtkTreeModel * model, GtkTreeIter * iter)
-{
- GtkTreePath * path = gtk_tree_model_get_path (model, iter);
- gint row = gtk_tree_path_get_indices (path)[0];
-
- gtk_tree_path_free (path);
- return row;
-}
-
-static gint get_selected_row (GtkWidget * list)
-{
- GtkTreeSelection * selection = gtk_tree_view_get_selection ((GtkTreeView *)
- list);
- GtkTreeModel * model;
- GtkTreeIter iter;
-
- if (! gtk_tree_selection_get_selected (selection, & model, & iter))
- return -1;
-
- return iter_to_row (model, & iter);
-}
-
-static void set_selected_row (GtkWidget * list, gint row)
-{
- GtkTreeSelection * selection = gtk_tree_view_get_selection ((GtkTreeView *)
- list);
- GtkTreePath * path = gtk_tree_path_new_from_indices (row, -1);
-
- gtk_tree_selection_select_path (selection, path);
- gtk_tree_path_free (path);
-}
+static GtkWidget * playman_win = NULL;
static void save_position (GtkWidget * window)
{
@@ -73,13 +47,9 @@ static gboolean hide_cb (GtkWidget * window)
return TRUE;
}
-static void activate_cb (GtkTreeView * list, GtkTreePath * path,
- GtkTreeViewColumn * column, GtkWidget * window)
+static void rename_cb (void)
{
- aud_playlist_set_active (gtk_tree_path_get_indices (path)[0]);
-
- if (aud_cfg->playlist_manager_close_on_activate)
- hide_cb (window);
+ audgui_show_playlist_rename (aud_playlist_get_active ());
}
static void new_cb (GtkButton * button, void * unused)
@@ -89,65 +59,115 @@ static void new_cb (GtkButton * button, void * unused)
static void delete_cb (GtkButton * button, GtkWidget * list)
{
- gint playlist = get_selected_row (list);
-
- if (playlist != -1)
- audgui_confirm_playlist_delete (playlist);
+ audgui_confirm_playlist_delete (aud_playlist_get_active ());
}
-static void rename_cb (GtkButton * button, GtkWidget * lv)
+static void save_config_cb (void * hook_data, void * user_data)
{
- GtkTreeSelection *listsel = gtk_tree_view_get_selection( GTK_TREE_VIEW(lv) );
- GtkTreeModel *store;
- GtkTreeIter iter;
+ if (gtk_widget_get_visible ((GtkWidget *) user_data))
+ save_position ((GtkWidget *) user_data);
+}
- if ( gtk_tree_selection_get_selected( listsel , &store , &iter ) == TRUE )
+static void get_value (void * user, gint row, gint column, GValue * value)
+{
+ switch (column)
{
- GtkTreePath *path = gtk_tree_model_get_path( GTK_TREE_MODEL(store) , &iter );
- GtkCellRenderer *rndrname = g_object_get_data( G_OBJECT(lv) , "rn" );
- /* set the name renderer to editable and start editing */
- g_object_set( G_OBJECT(rndrname) , "editable" , TRUE , NULL );
- gtk_tree_view_set_cursor_on_cell ((GtkTreeView *) lv, path,
- gtk_tree_view_get_column ((GtkTreeView *) lv,
- AUDGUI_LIBRARY_STORE_TITLE), rndrname, TRUE);
- gtk_tree_path_free( path );
+ case 0:
+ g_value_set_string (value, aud_playlist_get_title (row));
+ break;
+ case 1:
+ g_value_set_int (value, aud_playlist_entry_count (row));
+ break;
}
}
-static void
-playlist_manager_cb_lv_name_edited ( GtkCellRendererText *cell , gchar *path_string ,
- gchar *new_text , gpointer listview )
+static gboolean get_selected (void * user, gint row)
+{
+ return (row == aud_playlist_get_active ());
+}
+
+static void set_selected (void * user, gint row, gboolean selected)
{
- /* this is currently used to change playlist names */
- GtkTreeModel *store = gtk_tree_view_get_model( GTK_TREE_VIEW(listview) );
- GtkTreeIter iter;
+ if (selected)
+ aud_playlist_set_active (row);
+}
- if ( gtk_tree_model_get_iter_from_string( store , &iter , path_string ) == TRUE )
- aud_playlist_set_title (iter_to_row (store, & iter), new_text);
+static void select_all (void * user, gboolean selected)
+{
+}
- /* set the renderer uneditable again */
- g_object_set( G_OBJECT(cell) , "editable" , FALSE , NULL );
+static void activate_row (void * user, gint row)
+{
+ aud_playlist_set_active (row);
+
+ if (aud_cfg->playlist_manager_close_on_activate)
+ hide_cb (playman_win);
}
-static void save_config_cb (void * hook_data, void * user_data)
+static void shift_rows (void * user, gint row, gint before)
{
-#if GTK_CHECK_VERSION (2, 18, 0)
- if (gtk_widget_get_visible ((GtkWidget *) user_data))
-#else
- if (GTK_WIDGET_VISIBLE ((GtkWidget *) user_data))
-#endif
- save_position ((GtkWidget *) user_data);
+ if (before < row)
+ aud_playlist_reorder (row, before, 1);
+ else if (before - 1 > row)
+ aud_playlist_reorder (row, before - 1, 1);
}
-static GtkWidget * playman_win = NULL;
+static const AudguiListCallbacks callbacks = {
+ .get_value = get_value,
+ .get_selected = get_selected,
+ .set_selected = set_selected,
+ .select_all = select_all,
+ .activate_row = activate_row,
+ .right_click = NULL,
+ .shift_rows = shift_rows,
+ .data_type = NULL,
+ .get_data = NULL,
+ .receive_data = NULL};
+
+static gboolean position_changed = FALSE;
+
+static void update_hook (void * data, void * list)
+{
+ if (GPOINTER_TO_INT (data) >= PLAYLIST_UPDATE_STRUCTURE)
+ {
+ gint old_rows = audgui_list_row_count (list);
+ gint rows = aud_playlist_count ();
+
+ if (rows < old_rows)
+ {
+ audgui_list_delete_rows (list, rows, old_rows - rows);
+ old_rows = rows;
+ }
+
+ audgui_list_update_rows (list, 0, old_rows);
+ audgui_list_update_selection (list, 0, old_rows);
+
+ if (rows > old_rows)
+ audgui_list_insert_rows (list, old_rows, rows - old_rows);
+
+ audgui_list_set_focus (list, aud_playlist_get_active ());
+ }
+
+ if (GPOINTER_TO_INT (data) >= PLAYLIST_UPDATE_STRUCTURE || position_changed)
+ {
+ audgui_list_set_highlight (list, aud_playlist_get_playing ());
+ position_changed = FALSE;
+ }
+}
+
+static void position_hook (void * data, void * list)
+{
+ if (aud_playlist_update_pending ())
+ position_changed = TRUE;
+ else
+ audgui_list_set_highlight (list, aud_playlist_get_playing ());
+}
void
audgui_playlist_manager_ui_show (GtkWidget *mainwin)
{
GtkWidget *playman_vbox;
GtkWidget * playman_pl_lv, * playman_pl_lv_sw;
- GtkCellRenderer *playman_pl_lv_textrndr_name, *playman_pl_lv_textrndr_entriesnum;
- GtkTreeViewColumn *playman_pl_lv_col_name, *playman_pl_lv_col_entriesnum;
GtkWidget *playman_bbar_hbbox;
GtkWidget * rename_button, * new_button, * delete_button;
GtkWidget * hbox, * button;
@@ -179,34 +199,17 @@ audgui_playlist_manager_ui_show (GtkWidget *mainwin)
g_signal_connect ((GObject *) playman_win, "delete-event", (GCallback)
hide_cb, NULL);
+ audgui_hide_on_escape (playman_win);
playman_vbox = gtk_vbox_new (FALSE, 6);
gtk_container_add( GTK_CONTAINER(playman_win) , playman_vbox );
- playman_pl_lv = gtk_tree_view_new_with_model (audgui_get_library_store ());
- gtk_tree_view_set_reorderable ((GtkTreeView *) playman_pl_lv, TRUE);
-
- playman_pl_lv_textrndr_entriesnum = gtk_cell_renderer_text_new(); /* uneditable */
- playman_pl_lv_textrndr_name = gtk_cell_renderer_text_new(); /* can become editable */
- g_object_set( G_OBJECT(playman_pl_lv_textrndr_entriesnum) , "weight-set" , TRUE , NULL );
- g_object_set( G_OBJECT(playman_pl_lv_textrndr_name) , "weight-set" , TRUE , NULL );
- g_signal_connect( G_OBJECT(playman_pl_lv_textrndr_name) , "edited" ,
- G_CALLBACK(playlist_manager_cb_lv_name_edited) , playman_pl_lv );
- g_object_set_data( G_OBJECT(playman_pl_lv) , "rn" , playman_pl_lv_textrndr_name );
-
- playman_pl_lv_col_name = gtk_tree_view_column_new_with_attributes
- (_("Playlist"), playman_pl_lv_textrndr_name, "text",
- AUDGUI_LIBRARY_STORE_TITLE, "weight", AUDGUI_LIBRARY_STORE_FONT_WEIGHT,
- NULL);
- gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_name) , TRUE );
- gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_name );
-
- playman_pl_lv_col_entriesnum = gtk_tree_view_column_new_with_attributes
- (_("Entries"), playman_pl_lv_textrndr_entriesnum, "text",
- AUDGUI_LIBRARY_STORE_ENTRY_COUNT, "weight",
- AUDGUI_LIBRARY_STORE_FONT_WEIGHT, NULL);
- gtk_tree_view_column_set_expand( GTK_TREE_VIEW_COLUMN(playman_pl_lv_col_entriesnum) , FALSE );
- gtk_tree_view_append_column( GTK_TREE_VIEW(playman_pl_lv), playman_pl_lv_col_entriesnum );
+ playman_pl_lv = audgui_list_new (& callbacks, NULL, aud_playlist_count ());
+ audgui_list_add_column (playman_pl_lv, _("Title"), 0, G_TYPE_STRING, TRUE);
+ audgui_list_add_column (playman_pl_lv, _("Entries"), 1, G_TYPE_INT, FALSE);
+ audgui_list_set_highlight (playman_pl_lv, aud_playlist_get_playing ());
+ hook_associate ("playlist update", update_hook, playman_pl_lv);
+ hook_associate ("playlist position", position_hook, playman_pl_lv);
playman_pl_lv_sw = gtk_scrolled_window_new( NULL , NULL );
gtk_scrolled_window_set_shadow_type ((GtkScrolledWindow *) playman_pl_lv_sw,
@@ -235,8 +238,6 @@ audgui_playlist_manager_ui_show (GtkWidget *mainwin)
gtk_box_pack_start( GTK_BOX(playman_vbox) , playman_bbar_hbbox , FALSE , FALSE , 0 );
- g_signal_connect ((GObject *) playman_pl_lv, "row-activated", (GCallback)
- activate_cb, playman_win);
g_signal_connect ((GObject *) rename_button, "clicked", (GCallback)
rename_cb, playman_pl_lv);
g_signal_connect ((GObject *) new_button, "clicked", (GCallback) new_cb,
@@ -244,8 +245,6 @@ audgui_playlist_manager_ui_show (GtkWidget *mainwin)
g_signal_connect ((GObject *) delete_button, "clicked", (GCallback)
delete_cb, playman_pl_lv);
- set_selected_row (playman_pl_lv, aud_playlist_get_active ());
-
hbox = gtk_hbox_new (FALSE, 6);
gtk_box_pack_start ((GtkBox *) playman_vbox, hbox, FALSE, FALSE, 0);
button = gtk_check_button_new_with_mnemonic
diff --git a/src/audacious/chardet.h b/src/libaudgui/ui_regex.h
index 7311037..587f8d3 100644
--- a/src/audacious/chardet.h
+++ b/src/libaudgui/ui_regex.h
@@ -1,31 +1,39 @@
-/* Audacious - Cross-platform multimedia player
- * Copyright (C) 2005-2009 Audacious development team
- *
- * 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; under version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses>.
- *
- * The Audacious team does not consider modular code linking to
- * Audacious or using our public API to be a derived work.
- */
-
-#ifndef AUDACIOUS_CHARDET_H
-#define AUDACIOUS_CHARDET_H
-
-#include <glib.h>
-
-gchar * cd_str_to_utf8(const gchar *str);
-gchar * cd_chardet_to_utf8(const gchar *str, gssize len,
- gsize *arg_bytes_read, gsize *arg_bytes_write,
- GError **arg_error);
-void chardet_init(void);
-
-#endif /* AUDACIOUS_CHARDET_H */
+/* Audacious - Cross-platform multimedia player
+ * Copyright (C) 2005-2006 Audacious development team.
+ *
+ * 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; under version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses>.
+ *
+ * The Audacious team does not consider modular code linking to
+ * Audacious or using our public API to be a derived work.
+ */
+
+#ifndef __UI_REGEX_H__
+#define __UI_REGEX_H__
+
+#if defined USE_REGEX_ONIGURUMA
+ #include <onigposix.h>
+
+#elif defined USE_REGEX_PCRE
+ #include <pcreposix.h>
+
+#elif defined HAVE_REGEX_H
+ #include <regex.h>
+
+#elif defined HAVE_RXPOSIX_H
+ #include <rxposix.h>
+
+#elif defined HAVE_RX_RXPOSIX_H
+ #include <rx/rxposix.h>
+#endif
+
+#endif
diff --git a/src/libaudgui/ui_urlopener.c b/src/libaudgui/ui_urlopener.c
index c6f9ca5..45e39c0 100644
--- a/src/libaudgui/ui_urlopener.c
+++ b/src/libaudgui/ui_urlopener.c
@@ -31,6 +31,7 @@
#include <gtk/gtk.h>
#include <audacious/audconfig.h>
+#include <audacious/gtk-compat.h>
#include <audacious/i18n.h>
#include <audacious/drct.h>
#include <audacious/misc.h>
@@ -63,7 +64,7 @@ GtkWidget * urlopener_add_url_dialog_new (GCallback func, gboolean open)
vbox = gtk_vbox_new(FALSE, 10);
gtk_container_add(GTK_CONTAINER(win), vbox);
- combo = gtk_combo_box_entry_new_text();
+ combo = gtk_combo_box_text_new_with_entry ();
gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
entry = gtk_bin_get_child(GTK_BIN(combo));
@@ -71,8 +72,8 @@ GtkWidget * urlopener_add_url_dialog_new (GCallback func, gboolean open)
gtk_entry_set_text(GTK_ENTRY(entry), "");
for (url = aud_cfg->url_history; url; url = g_list_next(url))
- gtk_combo_box_append_text(GTK_COMBO_BOX(combo),
- (const gchar *) url->data);
+ gtk_combo_box_text_append_text ((GtkComboBoxText *) combo,
+ (const gchar *) url->data);
g_signal_connect(entry, "activate",
G_CALLBACK(urlopener_add_url_callback),
diff --git a/src/libaudgui/util.c b/src/libaudgui/util.c
index fe2f141..ac3667a 100644
--- a/src/libaudgui/util.c
+++ b/src/libaudgui/util.c
@@ -24,8 +24,12 @@
#include <gtk/gtk.h>
#include <audacious/debug.h>
+#include <audacious/gtk-compat.h>
+#include <audacious/playlist.h>
#include <audacious/plugin.h>
#include <audacious/misc.h>
+#include <libaudcore/audstrings.h>
+#include <libaudcore/hook.h>
#include "libaudgui.h"
#include "libaudgui-gtk.h"
@@ -74,19 +78,34 @@ void audgui_connect_check_box (GtkWidget * box, gboolean * setting)
void audgui_simple_message (GtkWidget * * widget, GtkMessageType type,
const gchar * title, const gchar * text)
{
- if (* widget == NULL)
+ AUDDBG ("%s\n", text);
+
+ if (* widget != NULL)
{
- * widget = gtk_message_dialog_new (NULL, 0, type, GTK_BUTTONS_OK, "%s",
- text);
- gtk_window_set_title ((GtkWindow *) * widget, title);
-
- g_signal_connect (* widget, "response", (GCallback) gtk_widget_destroy,
- NULL);
- audgui_destroy_on_escape (* widget);
- g_signal_connect (* widget, "destroy", (GCallback) gtk_widget_destroyed,
- widget);
+#if GTK_CHECK_VERSION (2, 10, 0)
+ const gchar * old = NULL;
+ g_object_get ((GObject *) * widget, "text", & old, NULL);
+ g_return_if_fail (old);
+
+ if (! strcmp (old, text))
+ goto CREATED;
+
+ gchar both[strlen (old) + strlen (text) + 2];
+ snprintf (both, sizeof both, "%s\n%s", old, text);
+ g_object_set ((GObject *) * widget, "text", both, NULL);
+#endif
+ goto CREATED;
}
+ * widget = gtk_message_dialog_new (NULL, 0, type, GTK_BUTTONS_OK, "%s", text);
+ gtk_window_set_title ((GtkWindow *) * widget, title);
+
+ g_signal_connect (* widget, "response", (GCallback) gtk_widget_destroy, NULL);
+ audgui_destroy_on_escape (* widget);
+ g_signal_connect (* widget, "destroy", (GCallback) gtk_widget_destroyed,
+ widget);
+
+CREATED:
gtk_window_present ((GtkWindow *) * widget);
}
@@ -105,16 +124,20 @@ GdkPixbuf * audgui_pixbuf_from_data (void * data, gint size)
return pixbuf;
}
-GdkPixbuf * audgui_pixbuf_for_file (const gchar * name)
+GdkPixbuf * audgui_pixbuf_for_entry (gint list, gint entry)
{
- /* MMS is slow. Skip it. */
- if (! strncmp (name, "mms://", 6))
- return NULL;
+ const gchar * name = aud_playlist_entry_get_filename (list, entry);
+ g_return_val_if_fail (name, NULL);
- InputPlugin * decoder = aud_file_find_decoder (name, FALSE);
+ /* Don't get album art for network files -- too slow. */
+ if (! strncmp (name, "http://", 7) || ! strncmp (name, "https://", 8) ||
+ ! strncmp (name, "mms://", 6))
+ goto FALLBACK;
+ AUDDBG ("Trying to load pixbuf for %s.\n", name);
+ PluginHandle * decoder = aud_playlist_entry_get_decoder (list, entry, FALSE);
if (! decoder)
- return NULL;
+ goto FALLBACK;
void * data;
gint size;
@@ -123,17 +146,67 @@ GdkPixbuf * audgui_pixbuf_for_file (const gchar * name)
{
GdkPixbuf * p = audgui_pixbuf_from_data (data, size);
g_free (data);
- return p;
+ if (p)
+ return p;
}
gchar * assoc = aud_get_associated_image_file (name);
- if (! assoc)
- return NULL;
+ if (assoc)
+ {
+ GdkPixbuf * p = gdk_pixbuf_new_from_file (assoc, NULL);
+ g_free (assoc);
+ if (p)
+ return p;
+ }
+
+FALLBACK:;
+ AUDDBG ("Using fallback pixbuf.\n");
+ static GdkPixbuf * fallback = NULL;
+ if (! fallback)
+ {
+ gchar * path = g_strdup_printf ("%s/images/album.png",
+ aud_get_path (AUD_PATH_DATA_DIR));
+ fallback = gdk_pixbuf_new_from_file (path, NULL);
+ g_free (path);
+ }
+ if (fallback)
+ g_object_ref ((GObject *) fallback);
+ return fallback;
+}
+
+
+static void clear_cached_pixbuf (void * list, GdkPixbuf * * pixbuf)
+{
+ if (GPOINTER_TO_INT (list) != aud_playlist_get_playing () || ! * pixbuf)
+ return;
- GdkPixbuf * p = gdk_pixbuf_new_from_file (assoc, NULL);
- g_free (assoc);
- return p;
+ AUDDBG ("Clearing cached pixbuf.\n");
+ g_object_unref ((GObject *) * pixbuf);
+ * pixbuf = NULL;
+}
+
+GdkPixbuf * audgui_pixbuf_for_current (void)
+{
+ static GdkPixbuf * pixbuf = NULL;
+ static gboolean hooked = FALSE;
+
+ if (! hooked)
+ {
+ hook_associate ("playlist position", (HookFunction) clear_cached_pixbuf,
+ & pixbuf);
+ hooked = TRUE;
+ }
+
+ if (! pixbuf)
+ {
+ gint list = aud_playlist_get_playing ();
+ pixbuf = audgui_pixbuf_for_entry (list, aud_playlist_get_position (list));
+ }
+
+ if (pixbuf)
+ g_object_ref ((GObject *) pixbuf);
+ return pixbuf;
}
void audgui_pixbuf_scale_within (GdkPixbuf * * pixbuf, gint size)
diff --git a/src/libaudtag/Makefile b/src/libaudtag/Makefile
index a440424..db21388 100644
--- a/src/libaudtag/Makefile
+++ b/src/libaudtag/Makefile
@@ -16,6 +16,6 @@ INCLUDES = audtag.h
include ../../buildsys.mk
include ../../extra.mk
-CPPFLAGS += ${LIB_CPPFLAGS} ${GLIB_CFLAGS} ${MOWGLI_CFLAGS} -D_AUDACIOUS_CORE -I.. -I../..
+CPPFLAGS += ${GLIB_CFLAGS} ${MOWGLI_CFLAGS} -D_AUDACIOUS_CORE -I.. -I../..
CFLAGS += ${LIB_CFLAGS}
LIBS += ${GLIB_LIBS} ${MOWGLI_LIBS} -L../libaudcore -laudcore
diff --git a/src/libaudtag/aac/aac.c b/src/libaudtag/aac/aac.c
index 0053cd5..8751d8a 100644
--- a/src/libaudtag/aac/aac.c
+++ b/src/libaudtag/aac/aac.c
@@ -79,8 +79,8 @@ void writeAtom(VFSFile * fd, Atom * atom)
void printAtom(Atom * atom)
{
- AUDDBG("size = %x\n", atom->size);
- AUDDBG("name = %s\n", atom->name);
+ TAGDBG("size = %x\n", atom->size);
+ TAGDBG("name = %s\n", atom->name);
}
StrDataAtom *readStrDataAtom(VFSFile * fd)
@@ -119,7 +119,7 @@ Atom *findAtom(VFSFile * fd, gchar * name)
if (vfs_feof(fd))
{
g_free(atom);
- AUDDBG("The atom %s could not be found\n", name);
+ TAGDBG("The atom %s could not be found\n", name);
return NULL;
}
return atom;
@@ -140,7 +140,7 @@ Atom *getilstAtom(VFSFile * fd)
vfs_fseek(fd, -(meta->size - 11), SEEK_CUR);
Atom *ilst = findAtom(fd, ILST);
- AUDDBG("zzz = %d\n", vfs_ftell(fd));
+ TAGDBG("zzz = %d\n", vfs_ftell(fd));
ilstFileOffset = vfs_ftell(fd) - ilst->size;
vfs_fseek(fd, -(ilst->size - 7), SEEK_CUR);
@@ -191,7 +191,7 @@ void writeAtomListToFile(VFSFile * from, VFSFile * to, int offset, mowgli_list_t
g_free(atom);
if (vfs_feof(from))
{
- AUDDBG("No free atoms\n");
+ TAGDBG("No free atoms\n");
g_free(atom);
atom = NULL;
}
diff --git a/src/libaudtag/ape/ape.c b/src/libaudtag/ape/ape.c
index 36c55a3..f1f5d8e 100755
--- a/src/libaudtag/ape/ape.c
+++ b/src/libaudtag/ape/ape.c
@@ -84,7 +84,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if (ape_read_header (handle, header))
{
- AUDDBG ("Found header at 0, length = %d, version = %d.\n", (gint)
+ TAGDBG ("Found header at 0, length = %d, version = %d.\n", (gint)
header->length, (gint) header->version);
* start = 0;
* length = header->length;
@@ -94,7 +94,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if (! (header->flags & APE_FLAG_HAS_HEADER) || ! (header->flags &
APE_FLAG_IS_HEADER))
{
- AUDDBG ("Invalid header flags (%u).\n", (guint) header->flags);
+ TAGDBG ("Invalid header flags (%u).\n", (guint) header->flags);
return FALSE;
}
@@ -105,7 +105,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if (! ape_read_header (handle, & secondary))
{
- AUDDBG ("Expected footer, but found none.\n");
+ TAGDBG ("Expected footer, but found none.\n");
return FALSE;
}
@@ -120,7 +120,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if (ape_read_header (handle, header))
{
- AUDDBG ("Found footer at %d, length = %d, version = %d.\n", (gint)
+ TAGDBG ("Found footer at %d, length = %d, version = %d.\n", (gint)
vfs_ftell (handle) - (gint) sizeof (APEHeader), (gint) header->length,
(gint) header->version);
* start = vfs_ftell (handle) - header->length;
@@ -131,7 +131,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if ((header->flags & APE_FLAG_HAS_NO_FOOTER) || (header->flags &
APE_FLAG_IS_HEADER))
{
- AUDDBG ("Invalid footer flags (%u).\n", (guint) header->flags);
+ TAGDBG ("Invalid footer flags (%u).\n", (guint) header->flags);
return FALSE;
}
@@ -143,7 +143,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
if (! ape_read_header (handle, & secondary))
{
- AUDDBG ("Expected header, but found none.\n");
+ TAGDBG ("Expected header, but found none.\n");
return FALSE;
}
@@ -154,7 +154,7 @@ static gboolean ape_find_header (VFSFile * handle, APEHeader * header, gint *
return TRUE;
}
- AUDDBG ("No header found.\n");
+ TAGDBG ("No header found.\n");
return FALSE;
}
@@ -175,7 +175,7 @@ static ValuePair * ape_read_item (void * * data, gint length)
if (length < 8)
{
- AUDDBG ("Expected item, but only %d bytes remain in tag.\n", length);
+ TAGDBG ("Expected item, but only %d bytes remain in tag.\n", length);
return NULL;
}
@@ -183,7 +183,7 @@ static ValuePair * ape_read_item (void * * data, gint length)
if (value == NULL)
{
- AUDDBG ("Unterminated item key (max length = %d).\n", length - 8);
+ TAGDBG ("Unterminated item key (max length = %d).\n", length - 8);
return NULL;
}
@@ -191,7 +191,7 @@ static ValuePair * ape_read_item (void * * data, gint length)
if (header[0] > (gchar *) (* data) + length - value)
{
- AUDDBG ("Item value of length %d, but only %d bytes remain in tag.\n",
+ TAGDBG ("Item value of length %d, but only %d bytes remain in tag.\n",
(gint) header[0], (gint) ((gchar *) (* data) + length - value));
return NULL;
}
@@ -227,7 +227,7 @@ static GList * ape_read_items (VFSFile * handle)
return NULL;
}
- AUDDBG ("Reading %d items:\n", header.items);
+ TAGDBG ("Reading %d items:\n", header.items);
item = data;
while (header.items --)
@@ -238,7 +238,7 @@ static GList * ape_read_items (VFSFile * handle)
if (pair == NULL)
break;
- AUDDBG ("Read: %s = %s.\n", pair->key, pair->value);
+ TAGDBG ("Read: %s = %s.\n", pair->key, pair->value);
list = g_list_prepend (list, pair);
}
@@ -354,7 +354,7 @@ static gboolean ape_write_item (VFSFile * handle, const gchar * key,
gint value_len = strlen (value);
guint32 header[2];
- AUDDBG ("Write: %s = %s.\n", key, value);
+ TAGDBG ("Write: %s = %s.\n", key, value);
header[0] = GUINT32_TO_LE (value_len);
header[1] = 0;
@@ -433,24 +433,24 @@ static gboolean ape_write_tag (const Tuple * tuple, VFSFile * handle)
{
if (start + length != vfs_fsize (handle))
{
- AUDDBG ("Writing tags is only supported at end of file.\n");
- goto ERROR;
+ TAGDBG ("Writing tags is only supported at end of file.\n");
+ goto ERR;
}
if (vfs_ftruncate (handle, start))
- goto ERROR;
+ goto ERR;
}
else
{
start = vfs_fsize (handle);
if (start < 0)
- goto ERROR;
+ goto ERR;
}
if (vfs_fseek (handle, start, SEEK_SET) || ! write_header (0, 0, TRUE,
handle))
- goto ERROR;
+ goto ERR;
length = 0;
items = 0;
@@ -463,7 +463,7 @@ static gboolean ape_write_tag (const Tuple * tuple, VFSFile * handle)
FIELD_GENRE, handle, "Genre", & length, & items) || ! write_integer_item
(tuple, FIELD_TRACK_NUMBER, handle, "Track", & length, & items) ||
! write_integer_item (tuple, FIELD_YEAR, handle, "Year", & length, & items))
- goto ERROR;
+ goto ERR;
for (node = list; node != NULL; node = node->next)
{
@@ -476,21 +476,21 @@ static gboolean ape_write_tag (const Tuple * tuple, VFSFile * handle)
continue;
if (! ape_write_item (handle, key, value, & length))
- goto ERROR;
+ goto ERR;
items ++;
}
- AUDDBG ("Wrote %d items, %d bytes.\n", items, length);
+ TAGDBG ("Wrote %d items, %d bytes.\n", items, length);
if (! write_header (length, items, FALSE, handle) || vfs_fseek (handle,
start, SEEK_SET) || ! write_header (length, items, TRUE, handle))
- goto ERROR;
+ goto ERR;
free_tag_list (list);
return TRUE;
-ERROR:
+ERR:
free_tag_list (list);
return FALSE;
}
diff --git a/src/libaudtag/audtag.c b/src/libaudtag/audtag.c
index 31c8b73..6db71d9 100644
--- a/src/libaudtag/audtag.c
+++ b/src/libaudtag/audtag.c
@@ -23,11 +23,18 @@
#include "tag_module.h"
#include "util.h"
+gboolean tag_verbose = FALSE;
+
void tag_init(void)
{
init_tag_modules();
}
+void tag_set_verbose (gboolean verbose)
+{
+ tag_verbose = verbose;
+}
+
/* The tuple's file-related attributes are already set */
gboolean tag_tuple_read (Tuple * tuple, VFSFile * handle)
diff --git a/src/libaudtag/audtag.h b/src/libaudtag/audtag.h
index df20961..725cf5c 100644
--- a/src/libaudtag/audtag.h
+++ b/src/libaudtag/audtag.h
@@ -37,8 +37,8 @@ enum
TAG_TYPE_APE,
};
-void tag_init(void);
-void tag_terminate(void);
+void tag_init (void);
+void tag_set_verbose (gboolean verbose);
gboolean tag_tuple_read (Tuple * tuple, VFSFile *fd);
gboolean tag_image_read (VFSFile * handle, void * * data, gint * size);
diff --git a/src/libaudtag/id3/id3-common.c b/src/libaudtag/id3/id3-common.c
index 9a07ba6..ea7c587 100644
--- a/src/libaudtag/id3/id3-common.c
+++ b/src/libaudtag/id3/id3-common.c
@@ -34,7 +34,7 @@ gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
gchar * buffer = NULL;
gsize converted = 0;
- AUDDBG ("length = %d, encoding = %d, nulled = %d\n", length, encoding,
+ TAGDBG ("length = %d, encoding = %d, nulled = %d\n", length, encoding,
nulled);
if (nulled)
@@ -50,7 +50,7 @@ gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
return NULL;
length = null - text;
- AUDDBG ("length before null = %d\n", length);
+ TAGDBG ("length before null = %d\n", length);
if (after != NULL)
* after = null + 1;
@@ -62,7 +62,7 @@ gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
return NULL;
length = null - text;
- AUDDBG ("length before null = %d\n", length);
+ TAGDBG ("length before null = %d\n", length);
if (after != NULL)
* after = null + 2;
@@ -75,7 +75,7 @@ gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
{
case 0:
case 3:
- buffer = chardet_to_utf8 (text, length, NULL, & converted, NULL);
+ buffer = str_to_utf8_full (text, length, NULL, & converted, NULL);
break;
case 1:
if (text[0] == (gchar) 0xff)
@@ -92,8 +92,8 @@ gchar * convert_text (const gchar * text, gint length, gint encoding, gboolean
break;
}
- AUDDBG ("length converted: %d\n", (gint) converted);
- AUDDBG ("string: %s\n", buffer);
+ TAGDBG ("length converted: %d\n", (gint) converted);
+ TAGDBG ("string: %s\n", buffer);
if (_converted != NULL)
* _converted = converted;
diff --git a/src/libaudtag/id3/id3v1.c b/src/libaudtag/id3/id3v1.c
index 6897d3e..f6426ef 100644
--- a/src/libaudtag/id3/id3v1.c
+++ b/src/libaudtag/id3/id3v1.c
@@ -123,9 +123,8 @@ gboolean id3v1_read_tag (Tuple * tuple, VFSFile * f)
{
tuple_associate_string(tuple, FIELD_GENRE, NULL, ext_genre);
genre_set = TRUE;
+ g_free(ext_genre);
}
-
- g_free(ext_genre);
}
tuple_associate_string(tuple, FIELD_TITLE, NULL, title);
@@ -159,6 +158,7 @@ ERR:
static gboolean id3v1_write_tag (const Tuple * tuple, VFSFile * handle)
{
+ fprintf (stderr, "Writing ID3v1 tags is not implemented yet, sorry.\n");
return FALSE;
}
diff --git a/src/libaudtag/id3/id3v22.c b/src/libaudtag/id3/id3v22.c
index 331b366..65e6796 100644
--- a/src/libaudtag/id3/id3v22.c
+++ b/src/libaudtag/id3/id3v22.c
@@ -97,12 +97,12 @@ static gboolean validate_header (ID3v2Header * header)
header->size = unsyncsafe32(GUINT32_FROM_BE(header->size));
- AUDDBG ("Found ID3v2 header:\n");
- AUDDBG (" magic = %.3s\n", header->magic);
- AUDDBG (" version = %d\n", (gint) header->version);
- AUDDBG (" revision = %d\n", (gint) header->revision);
- AUDDBG (" flags = %x\n", (gint) header->flags);
- AUDDBG (" size = %d\n", (gint) header->size);
+ TAGDBG ("Found ID3v2 header:\n");
+ TAGDBG (" magic = %.3s\n", header->magic);
+ TAGDBG (" version = %d\n", (gint) header->version);
+ TAGDBG (" revision = %d\n", (gint) header->revision);
+ TAGDBG (" flags = %x\n", (gint) header->flags);
+ TAGDBG (" size = %d\n", (gint) header->size);
return TRUE;
}
@@ -128,7 +128,7 @@ static gboolean read_header (VFSFile * handle, gint * version, gboolean *
* syncsafe = (header.flags & ID3_HEADER_SYNCSAFE) ? TRUE : FALSE;
- AUDDBG ("Offset = %d, header size = %d, data size = %d\n",
+ TAGDBG ("Offset = %d, header size = %d, data size = %d\n",
(gint) * offset, * header_size, * data_size);
return TRUE;
@@ -154,16 +154,16 @@ static gboolean read_frame (VFSFile * handle, gint max_size, gint version,
for (i = 0; i < 3; i++)
{
hdrsz |= (guint32) header.size[i] << ((2 - i) * 8);
- AUDDBG("header.size[%d] = %d hdrsz %d slot %d\n", i, header.size[i], hdrsz, 2 - i);
+ TAGDBG("header.size[%d] = %d hdrsz %d slot %d\n", i, header.size[i], hdrsz, 2 - i);
}
// hdrsz = GUINT32_TO_BE(hdrsz);
if (hdrsz > max_size || hdrsz == 0)
return FALSE;
- AUDDBG ("Found frame:\n");
- AUDDBG (" key = %.3s\n", header.key);
- AUDDBG (" size = %d\n", (gint) hdrsz);
+ TAGDBG ("Found frame:\n");
+ TAGDBG (" key = %.3s\n", header.key);
+ TAGDBG (" size = %d\n", (gint) hdrsz);
* frame_size = sizeof (ID3v2FrameHeader) + hdrsz;
sprintf (key, "%.3s", header.key);
@@ -174,7 +174,7 @@ static gboolean read_frame (VFSFile * handle, gint max_size, gint version,
if (vfs_fread (* data, 1, * size, handle) != * size)
return FALSE;
- AUDDBG ("Data size = %d.\n", * size);
+ TAGDBG ("Data size = %d.\n", * size);
return TRUE;
}
@@ -226,9 +226,9 @@ static void associate_string (Tuple * tuple, gint field, const gchar *
return;
if (customfield != NULL)
- AUDDBG ("Custom field %s = %s.\n", customfield, text);
+ TAGDBG ("Custom field %s = %s.\n", customfield, text);
else
- AUDDBG ("Field %i = %s.\n", field, text);
+ TAGDBG ("Field %i = %s.\n", field, text);
tuple_associate_string (tuple, field, customfield, text);
g_free (text);
@@ -243,9 +243,9 @@ static void associate_int (Tuple * tuple, gint field, const gchar *
return;
if (customfield != NULL)
- AUDDBG ("Custom field %s = %s.\n", customfield, text);
+ TAGDBG ("Custom field %s = %s.\n", customfield, text);
else
- AUDDBG ("Field %i = %s.\n", field, text);
+ TAGDBG ("Field %i = %s.\n", field, text);
tuple_associate_int (tuple, field, customfield, atoi (text));
g_free (text);
@@ -258,7 +258,7 @@ static void decode_comment (Tuple * tuple, const guchar * data, gint size)
if (! decode_comment_frame (data, size, & lang, & type, & value))
return;
- AUDDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value);
+ TAGDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value);
if (! type[0]) /* blank type == actual comment */
tuple_associate_string (tuple, FIELD_COMMENT, NULL, value);
@@ -281,7 +281,7 @@ static void decode_txx (Tuple * tuple, const guchar * data, gint size)
return;
gchar * value = separator + 1;
- AUDDBG ("TXX: %s = %s.\n", text, value);
+ TAGDBG ("TXX: %s = %s.\n", text, value);
tuple_associate_string (tuple, -1, text, value);
g_free (text);
@@ -307,7 +307,7 @@ static gboolean decode_rva_block (const guchar * * _data, gint * _size, gint *
data += 4;
size -= 4;
- AUDDBG ("RVA block: channel = %d, adjustment = %d/%d, peak bits = %d\n",
+ TAGDBG ("RVA block: channel = %d, adjustment = %d/%d, peak bits = %d\n",
* channel, * adjustment, * adjustment_unit, peak_bits);
if (peak_bits > 0 && peak_bits < sizeof (gint) * 8)
@@ -327,7 +327,7 @@ static gboolean decode_rva_block (const guchar * * _data, gint * _size, gint *
data += bytes;
size -= count;
- AUDDBG ("RVA block: peak = %d/%d\n", * peak, * peak_unit);
+ TAGDBG ("RVA block: peak = %d/%d\n", * peak, * peak_unit);
}
else
{
@@ -350,7 +350,7 @@ static void decode_rva (Tuple * tuple, const guchar * data, gint size)
domain = (const gchar *) data;
- AUDDBG ("RVA domain: %s\n", domain);
+ TAGDBG ("RVA domain: %s\n", domain);
size -= strlen (domain) + 1;
data += strlen (domain) + 1;
@@ -444,7 +444,7 @@ gboolean id3v22_read_tag (Tuple * tuple, VFSFile * handle)
& data_size))
return FALSE;
- AUDDBG("Reading tags from %i bytes of ID3 data in %s\n", data_size, handle->uri);
+ TAGDBG("Reading tags from %i bytes of ID3 data in %s\n", data_size, handle->uri);
for (pos = 0; pos < data_size; )
{
@@ -455,7 +455,7 @@ gboolean id3v22_read_tag (Tuple * tuple, VFSFile * handle)
if (! read_frame (handle, data_size - pos, version, syncsafe,
& frame_size, key, & data, & size))
{
- AUDDBG("read_frame failed at pos %i\n", pos);
+ TAGDBG("read_frame failed at pos %i\n", pos);
break;
}
@@ -507,7 +507,7 @@ gboolean id3v22_read_tag (Tuple * tuple, VFSFile * handle)
decode_rva (tuple, data, size);
break;
default:
- AUDDBG ("Ignoring unsupported ID3 frame %s.\n", key);
+ TAGDBG ("Ignoring unsupported ID3 frame %s.\n", key);
break;
}
@@ -533,7 +533,7 @@ static gboolean parse_pic (const guchar * data, gint size, gchar * * mime,
* image_data = g_memdup (after, data + size - after);
* image_size = data + size - after;
- AUDDBG ("PIC: mime = %s, type = %d, size = %d.\n", * mime,
+ TAGDBG ("PIC: mime = %s, type = %d, size = %d.\n", * mime,
* type, * image_size);
return TRUE;
}
@@ -589,6 +589,7 @@ static gboolean id3v22_read_image (VFSFile * handle, void * * image_data, gint *
static gboolean id3v22_write_tag (const Tuple * tuple, VFSFile * f)
{
+ fprintf (stderr, "Writing ID3v2.2 tags is not implemented yet, sorry.\n");
return FALSE;
}
diff --git a/src/libaudtag/id3/id3v24.c b/src/libaudtag/id3/id3v24.c
index da1de0a..d655ce8 100644
--- a/src/libaudtag/id3/id3v24.c
+++ b/src/libaudtag/id3/id3v24.c
@@ -118,7 +118,7 @@ static gboolean skip_extended_header_3 (VFSFile * handle, gint * _size)
size = GUINT32_FROM_BE (size);
- AUDDBG ("Found v2.3 extended header, size = %d.\n", (gint) size);
+ TAGDBG ("Found v2.3 extended header, size = %d.\n", (gint) size);
if (vfs_fseek (handle, size, SEEK_CUR))
return FALSE;
@@ -136,7 +136,7 @@ static gboolean skip_extended_header_4 (VFSFile * handle, gint * _size)
size = unsyncsafe32 (GUINT32_FROM_BE (size));
- AUDDBG ("Found v2.4 extended header, size = %d.\n", (gint) size);
+ TAGDBG ("Found v2.4 extended header, size = %d.\n", (gint) size);
if (vfs_fseek (handle, size - 4, SEEK_CUR))
return FALSE;
@@ -155,12 +155,12 @@ static gboolean validate_header (ID3v2Header * header, gboolean is_footer)
header->size = unsyncsafe32 (GUINT32_FROM_BE (header->size));
- AUDDBG ("Found ID3v2 %s:\n", is_footer ? "footer" : "header");
- AUDDBG (" magic = %.3s\n", header->magic);
- AUDDBG (" version = %d\n", (gint) header->version);
- AUDDBG (" revision = %d\n", (gint) header->revision);
- AUDDBG (" flags = %x\n", (gint) header->flags);
- AUDDBG (" size = %d\n", (gint) header->size);
+ TAGDBG ("Found ID3v2 %s:\n", is_footer ? "footer" : "header");
+ TAGDBG (" magic = %.3s\n", header->magic);
+ TAGDBG (" version = %d\n", (gint) header->version);
+ TAGDBG (" revision = %d\n", (gint) header->revision);
+ TAGDBG (" flags = %x\n", (gint) header->flags);
+ TAGDBG (" size = %d\n", (gint) header->size);
return TRUE;
}
@@ -256,7 +256,7 @@ static gboolean read_header (VFSFile * handle, gint * version, gboolean *
* data_size -= extended_size;
}
- AUDDBG ("Offset = %d, header size = %d, data size = %d, footer size = "
+ TAGDBG ("Offset = %d, header size = %d, data size = %d, footer size = "
"%d.\n", (gint) * offset, * header_size, * data_size, * footer_size);
return TRUE;
@@ -303,17 +303,17 @@ static gboolean read_frame (VFSFile * handle, gint max_size, gint version,
if (header.size > max_size || header.size == 0)
return FALSE;
- AUDDBG ("Found frame:\n");
- AUDDBG (" key = %.4s\n", header.key);
- AUDDBG (" size = %d\n", (gint) header.size);
- AUDDBG (" flags = %x\n", (gint) header.flags);
+ TAGDBG ("Found frame:\n");
+ TAGDBG (" key = %.4s\n", header.key);
+ TAGDBG (" size = %d\n", (gint) header.size);
+ TAGDBG (" flags = %x\n", (gint) header.flags);
* frame_size = sizeof (ID3v2FrameHeader) + header.size;
sprintf (key, "%.4s", header.key);
if (header.flags & (ID3_FRAME_COMPRESSED | ID3_FRAME_ENCRYPTED))
{
- AUDDBG ("Hit compressed/encrypted frame %s.\n", key);
+ TAGDBG ("Hit compressed/encrypted frame %s.\n", key);
return FALSE;
}
@@ -334,7 +334,7 @@ static gboolean read_frame (VFSFile * handle, gint max_size, gint version,
if (syncsafe || (header.flags & ID3_FRAME_SYNCSAFE))
* size = unsyncsafe (* data, * size);
- AUDDBG ("Data size = %d.\n", * size);
+ TAGDBG ("Data size = %d.\n", * size);
return TRUE;
}
@@ -390,7 +390,7 @@ static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe,
if (mowgli_dictionary_retrieve (dict, key) != NULL)
{
- AUDDBG ("Discarding duplicate frame %s.\n", key);
+ TAGDBG ("Discarding duplicate frame %s.\n", key);
g_free (data);
continue;
}
@@ -407,7 +407,7 @@ static void read_all_frames (VFSFile * handle, gint version, gboolean syncsafe,
static gboolean write_frame (VFSFile * handle, GenericFrame * frame, gint *
frame_size)
{
- AUDDBG ("Writing frame %s, size %d\n", frame->key, frame->size);
+ TAGDBG ("Writing frame %s, size %d\n", frame->key, frame->size);
ID3v2FrameHeader header;
@@ -447,7 +447,7 @@ static gint writeAllFramesToFile (VFSFile * fd, mowgli_dictionary_t * dict)
WriteState state = {fd, 0};
mowgli_dictionary_foreach (dict, write_frame_cb, & state);
- AUDDBG ("Total frame bytes written = %d.\n", state.written_size);
+ TAGDBG ("Total frame bytes written = %d.\n", state.written_size);
return state.written_size;
}
@@ -485,12 +485,15 @@ static void associate_string (Tuple * tuple, gint field, const gchar *
gchar * text = decode_text_frame (data, size);
if (text == NULL || ! text[0])
+ {
+ g_free (text);
return;
+ }
if (customfield != NULL)
- AUDDBG ("Custom field %s = %s.\n", customfield, text);
+ TAGDBG ("Custom field %s = %s.\n", customfield, text);
else
- AUDDBG ("Field %i = %s.\n", field, text);
+ TAGDBG ("Field %i = %s.\n", field, text);
tuple_associate_string (tuple, field, customfield, text);
g_free (text);
@@ -505,9 +508,9 @@ static void associate_int (Tuple * tuple, gint field, const gchar *
return;
if (customfield != NULL)
- AUDDBG ("Custom field %s = %s.\n", customfield, text);
+ TAGDBG ("Custom field %s = %s.\n", customfield, text);
else
- AUDDBG ("Field %i = %s.\n", field, text);
+ TAGDBG ("Field %i = %s.\n", field, text);
tuple_associate_int (tuple, field, customfield, atoi (text));
g_free (text);
@@ -545,10 +548,10 @@ static void decode_private_info (Tuple * tuple, const guchar * data, gint size)
if (!memcmp(value, SECONDARY_CLASS_GAMES_SONG, 16))
tuple_associate_string (tuple, -1, "media-class", "Game Soundtrack");
} else {
- AUDDBG("Unrecognised tag %s (Windows Media) ignored\n", text);
+ TAGDBG("Unrecognised tag %s (Windows Media) ignored\n", text);
}
} else {
- AUDDBG("Unable to decode private data, skipping: %s\n", text);
+ TAGDBG("Unable to decode private data, skipping: %s\n", text);
}
DONE:
@@ -562,7 +565,7 @@ static void decode_comment (Tuple * tuple, const guchar * data, gint size)
if (! decode_comment_frame (data, size, & lang, & type, & value))
return;
- AUDDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value);
+ TAGDBG ("Comment: lang = %s, type = %s, value = %s.\n", lang, type, value);
if (! type[0]) /* blank type == actual comment */
tuple_associate_string (tuple, FIELD_COMMENT, NULL, value);
@@ -585,7 +588,7 @@ static void decode_txxx (Tuple * tuple, const guchar * data, gint size)
return;
gchar * value = separator + 1;
- AUDDBG ("TXXX: %s = %s.\n", text, value);
+ TAGDBG ("TXXX: %s = %s.\n", text, value);
tuple_associate_string (tuple, -1, text, value);
g_free (text);
@@ -611,7 +614,7 @@ static gboolean decode_rva2_block (const guchar * * _data, gint * _size, gint *
data += 4;
size -= 4;
- AUDDBG ("RVA2 block: channel = %d, adjustment = %d/%d, peak bits = %d\n",
+ TAGDBG ("RVA2 block: channel = %d, adjustment = %d/%d, peak bits = %d\n",
* channel, * adjustment, * adjustment_unit, peak_bits);
if (peak_bits > 0 && peak_bits < sizeof (gint) * 8)
@@ -631,7 +634,7 @@ static gboolean decode_rva2_block (const guchar * * _data, gint * _size, gint *
data += bytes;
size -= count;
- AUDDBG ("RVA2 block: peak = %d/%d\n", * peak, * peak_unit);
+ TAGDBG ("RVA2 block: peak = %d/%d\n", * peak, * peak_unit);
}
else
{
@@ -654,7 +657,7 @@ static void decode_rva2 (Tuple * tuple, const guchar * data, gint size)
domain = (const gchar *) data;
- AUDDBG ("RVA2 domain: %s\n", domain);
+ TAGDBG ("RVA2 domain: %s\n", domain);
size -= strlen (domain) + 1;
data += strlen (domain) + 1;
@@ -718,11 +721,11 @@ static void decode_genre (Tuple * tuple, const guchar * data, gint size)
numericgenre = atoi (text);
if (numericgenre > 0)
- {
- tuple_associate_string(tuple, FIELD_GENRE, NULL, convert_numericgenre_to_text(numericgenre));
- return;
- }
- tuple_associate_string(tuple, FIELD_GENRE, NULL, text);
+ tuple_associate_string (tuple, FIELD_GENRE, NULL,
+ convert_numericgenre_to_text (numericgenre));
+ else
+ tuple_associate_string (tuple, FIELD_GENRE, NULL, text);
+
g_free (text);
return;
}
@@ -752,7 +755,7 @@ static void remove_frame (gint id, mowgli_dictionary_t * dict)
if (frame == NULL)
return;
- AUDDBG ("Deleting frame %s.\n", id3_frames[id]);
+ TAGDBG ("Deleting frame %s.\n", id3_frames[id]);
mowgli_dictionary_delete (dict, id3_frames[id]);
free_generic_frame (frame);
}
@@ -766,7 +769,7 @@ static void add_text_frame (gint id, const gchar * text, mowgli_dictionary_t *
return;
}
- AUDDBG ("Adding text frame %s = %s.\n", id3_frames[id], text);
+ TAGDBG ("Adding text frame %s = %s.\n", id3_frames[id], text);
gint length = strlen (text);
GenericFrame * frame = add_generic_frame (id, length + 1, dict);
@@ -782,7 +785,7 @@ static void add_comment_frame (const gchar * text, mowgli_dictionary_t * dict)
return;
}
- AUDDBG ("Adding comment frame = %s.\n", text);
+ TAGDBG ("Adding comment frame = %s.\n", text);
gint length = strlen (text);
GenericFrame * frame = add_generic_frame (ID3_COMMENT, length + 5, dict);
@@ -896,7 +899,7 @@ static gboolean id3v24_read_tag (Tuple * tuple, VFSFile * handle)
decode_rva2 (tuple, data, size);
break;
default:
- AUDDBG ("Ignoring unsupported ID3 frame %s.\n", key);
+ TAGDBG ("Ignoring unsupported ID3 frame %s.\n", key);
break;
}
@@ -925,7 +928,7 @@ static gboolean parse_apic (const guchar * _data, gint size, gchar * * mime,
* image_data = g_memdup (after, data + size - after);
* image_size = data + size - after;
- AUDDBG ("APIC: mime = %s, type = %d, desc = %s, size = %d.\n", * mime,
+ TAGDBG ("APIC: mime = %s, type = %d, desc = %s, size = %d.\n", * mime,
* type, * desc, * image_size);
return TRUE;
}
@@ -1008,32 +1011,32 @@ static gboolean id3v24_write_tag (const Tuple * tuple, VFSFile * f)
if (! offset)
{
if (! cut_beginning_tag (f, header_size + data_size + footer_size))
- goto ERROR;
+ goto ERR;
}
else
{
if (offset + header_size + data_size + footer_size != vfs_fsize (f))
- goto ERROR;
+ goto ERR;
if (vfs_ftruncate (f, offset))
- goto ERROR;
+ goto ERR;
}
offset = vfs_fsize (f);
if (offset < 0 || vfs_fseek (f, offset, SEEK_SET) || ! write_header (f, 0,
FALSE))
- goto ERROR;
+ goto ERR;
data_size = writeAllFramesToFile (f, dict);
if (! write_header (f, data_size, TRUE) || vfs_fseek (f, offset, SEEK_SET)
|| ! write_header (f, data_size, FALSE))
- goto ERROR;
+ goto ERR;
mowgli_dictionary_destroy (dict, free_frame_cb, NULL);
return TRUE;
-ERROR:
+ERR:
mowgli_dictionary_destroy (dict, free_frame_cb, NULL);
return FALSE;
}
diff --git a/src/libaudtag/tag_module.c b/src/libaudtag/tag_module.c
index bba9f64..0b2f743 100644
--- a/src/libaudtag/tag_module.c
+++ b/src/libaudtag/tag_module.c
@@ -47,13 +47,13 @@ tag_module_t * find_tag_module (VFSFile * fd, gint new_type)
{
if (vfs_fseek(fd, 0, SEEK_SET))
{
- AUDDBG("not a seekable file\n");
+ TAGDBG("not a seekable file\n");
return NULL;
}
if (((tag_module_t *) mod->data)->can_handle_file (fd))
{
- AUDDBG ("Module %s accepted file.\n", ((tag_module_t *)
+ TAGDBG ("Module %s accepted file.\n", ((tag_module_t *)
mod->data)->name);
return mod->data;
}
@@ -69,6 +69,6 @@ tag_module_t * find_tag_module (VFSFile * fd, gint new_type)
}
}
- AUDDBG("no module found\n");
+ TAGDBG("no module found\n");
return NULL;
}
diff --git a/src/libaudtag/util.c b/src/libaudtag/util.c
index 73b33c1..5d75777 100644
--- a/src/libaudtag/util.c
+++ b/src/libaudtag/util.c
@@ -61,66 +61,66 @@ const gchar *get_complete_filepath(Tuple * tuple)
dir = tuple_get_string(tuple, FIELD_FILE_PATH, NULL);
file = tuple_get_string(tuple, FIELD_FILE_NAME, NULL);
filepath = g_strdup_printf("%s/%s", dir, file);
- AUDDBG("file path = %s\n", filepath);
+ TAGDBG("file path = %s\n", filepath);
return filepath;
}
void print_tuple(Tuple * tuple)
{
#if WMA_DEBUG
- AUDDBG("--------------TUPLE PRINT --------------------\n");
+ TAGDBG("--------------TUPLE PRINT --------------------\n");
const gchar *title = tuple_get_string(tuple, FIELD_TITLE, NULL);
- AUDDBG("title = %s\n", title);
+ TAGDBG("title = %s\n", title);
/* artist */
const gchar *artist = tuple_get_string(tuple, FIELD_ARTIST, NULL);
- AUDDBG("artist = %s\n", artist);
+ TAGDBG("artist = %s\n", artist);
/* copyright */
const gchar *copyright = tuple_get_string(tuple, FIELD_COPYRIGHT, NULL);
- AUDDBG("copyright = %s\n", copyright);
+ TAGDBG("copyright = %s\n", copyright);
/* comment / description */
const gchar *comment = tuple_get_string(tuple, FIELD_COMMENT, NULL);
- AUDDBG("comment = %s\n", comment);
+ TAGDBG("comment = %s\n", comment);
/* codec name */
const gchar *codec_name = tuple_get_string(tuple, FIELD_CODEC, NULL);
- AUDDBG("codec = %s\n", codec_name);
+ TAGDBG("codec = %s\n", codec_name);
/* album */
const gchar *album = tuple_get_string(tuple, FIELD_ALBUM, NULL);
- AUDDBG("Album = %s\n", album);
+ TAGDBG("Album = %s\n", album);
/*track number */
gint track_nr = tuple_get_int(tuple, FIELD_TRACK_NUMBER, NULL);
- AUDDBG("Track nr = %d\n", track_nr);
+ TAGDBG("Track nr = %d\n", track_nr);
/* genre */
const gchar *genre = tuple_get_string(tuple, FIELD_GENRE, NULL);
- AUDDBG("Genre = %s \n", genre);
+ TAGDBG("Genre = %s \n", genre);
/* length */
gint length = tuple_get_int(tuple, FIELD_LENGTH, NULL);
- AUDDBG("Length = %d\n", length);
+ TAGDBG("Length = %d\n", length);
/* year */
gint year = tuple_get_int(tuple, FIELD_YEAR, NULL);
- AUDDBG("Year = %d\n", year);
+ TAGDBG("Year = %d\n", year);
/* quality */
const gchar *quality = tuple_get_string(tuple, FIELD_QUALITY, NULL);
- AUDDBG("quality = %s\n", quality);
+ TAGDBG("quality = %s\n", quality);
/* path */
const gchar *path = tuple_get_string(tuple, FIELD_FILE_PATH, NULL);
- AUDDBG("path = %s\n", path);
+ TAGDBG("path = %s\n", path);
/* filename */
const gchar *filename = tuple_get_string(tuple, FIELD_FILE_NAME, NULL);
- AUDDBG("filename = %s\n", filename);
+ TAGDBG("filename = %s\n", filename);
- AUDDBG("-----------------END---------------------\n");
+ TAGDBG("-----------------END---------------------\n");
#endif
}
@@ -156,7 +156,7 @@ gunichar2 *fread_utf16(VFSFile * f, guint64 size)
p = NULL;
}
gchar *s = utf8(p);
- AUDDBG("Converted to UTF8: '%s'\n", s);
+ TAGDBG("Converted to UTF8: '%s'\n", s);
g_free(s);
return p;
}
diff --git a/src/libaudtag/util.h b/src/libaudtag/util.h
index 7d9acc0..4692cfd 100644
--- a/src/libaudtag/util.h
+++ b/src/libaudtag/util.h
@@ -23,7 +23,7 @@
#define TAGUTIL_H
#include <glib.h>
-#include <audacious/debug.h>
+
#include "libaudcore/tuple.h"
#include "libaudcore/vfs.h"
@@ -157,6 +157,10 @@ enum {
GENRE_EURO_HOUSE
};
+extern gboolean tag_verbose;
+
+#define TAGDBG(...) do {if (tag_verbose) {printf ("%s:%d [%s]: ", __FILE__, __LINE__, __FUNCTION__); printf (__VA_ARGS__);}} while (0)
+
time_t unix_time(guint64 win_time);
guint16 get_year(guint64 win_time);
diff --git a/src/libaudtag/wma/guid.c b/src/libaudtag/wma/guid.c
index 473c138..f464335 100644
--- a/src/libaudtag/wma/guid.c
+++ b/src/libaudtag/wma/guid.c
@@ -27,11 +27,11 @@
#include "guid.h"
#include "wma_fmt.h"
-GUID *guid_read_from_file(VFSFile * f)
+GUID_t *guid_read_from_file(VFSFile * f)
{
- GUID temp;
+ GUID_t temp;
- if ((f == NULL) || (vfs_fread(&temp, sizeof(GUID), 1, f) != 1))
+ if ((f == NULL) || (vfs_fread(&temp, sizeof(GUID_t), 1, f) != 1))
return NULL;
temp.le32 = GUINT32_FROM_LE(temp.le32);
@@ -39,56 +39,56 @@ GUID *guid_read_from_file(VFSFile * f)
temp.le16_2 = GUINT16_FROM_LE(temp.le16_2);
temp.be64 = GUINT64_FROM_BE(temp.be64);
- return g_memdup(&temp, sizeof(GUID));
+ return g_memdup(&temp, sizeof(GUID_t));
}
gboolean guid_write_to_file(VFSFile * f, int guid_type)
{
g_return_val_if_fail(f != NULL, FALSE);
- GUID *g = guid_convert_from_string(wma_guid_map(guid_type));
+ GUID_t *g = guid_convert_from_string(wma_guid_map(guid_type));
gboolean ret = write_LEuint32(f, g->le32) && write_LEuint16(f, g->le16_1) && write_LEuint16(f, g->le16_1) && write_LEuint64(f, g->be64);
g_free(g);
return ret;
}
-GUID *guid_convert_from_string(const gchar * string)
+GUID_t *guid_convert_from_string(const gchar * string)
{
- GUID temp;
+ GUID_t temp;
if (sscanf(string, "%" SCNx32 "-%" SCNx16 "-%" SCNx16 "-%" SCNx64, &temp.le32, &temp.le16_1, &temp.le16_2, &temp.be64) != 4)
return NULL;
- return g_memdup(&temp, sizeof(GUID));
+ return g_memdup(&temp, sizeof(GUID_t));
}
-gchar *guid_convert_to_string(const GUID * g)
+gchar *guid_convert_to_string(const GUID_t * g)
{
return g_strdup_printf("%8x-%hx-%hx-%" PRIx64 "\n", GUINT32_TO_LE(g->le32), GUINT16_TO_LE(g->le16_1), GUINT16_TO_LE(g->le16_2), GUINT64_TO_BE(g->be64));
}
-gboolean guid_equal(GUID * g1, GUID * g2)
+gboolean guid_equal(GUID_t * g1, GUID_t * g2)
{
/*
- AUDDBG("GUID 1 = %8x-%hx-%hx-%"PRIx64"\n", g1->le32, g1->le16_1, g1->le16_2, g1->be64);
- AUDDBG("GUID 2 = %8x-%hx-%hx-%"PRIx64"\n", g2->le32, g2->le16_1, g2->le16_2, g2->be64);
+ TAGDBG("GUID 1 = %8x-%hx-%hx-%"PRIx64"\n", g1->le32, g1->le16_1, g1->le16_2, g1->be64);
+ TAGDBG("GUID 2 = %8x-%hx-%hx-%"PRIx64"\n", g2->le32, g2->le16_1, g2->le16_2, g2->be64);
*/
g_return_val_if_fail((g1 != NULL) && (g2 != NULL), FALSE);
if (!memcmp(g1, g2, 16))
{
- // AUDDBG("equal\n");
+ // TAGDBG("equal\n");
return TRUE;
}
- /* AUDDBG("not equal\n"); */
+ /* TAGDBG("not equal\n"); */
return FALSE;
}
-int get_guid_type(GUID * g)
+int get_guid_type(GUID_t * g)
{
- GUID *g1;
+ GUID_t *g1;
int i;
for (i = 0; i < ASF_OBJECT_LAST - 1; i++)
{
diff --git a/src/libaudtag/wma/guid.h b/src/libaudtag/wma/guid.h
index 1bb193a..8d68d49 100644
--- a/src/libaudtag/wma/guid.h
+++ b/src/libaudtag/wma/guid.h
@@ -30,16 +30,16 @@ typedef struct _guid {
guint16 le16_1;
guint16 le16_2;
guint64 be64;
-}GUID;
+}GUID_t;
-GUID *guid_read_from_file(VFSFile *);
+GUID_t *guid_read_from_file(VFSFile *);
gboolean guid_write_to_file(VFSFile *, int);
-GUID *guid_convert_from_string(const gchar *);
-gchar *guid_convert_to_string(const GUID*);
-gboolean guid_equal(GUID *, GUID *);
-int get_guid_type(GUID *);
+GUID_t *guid_convert_from_string(const gchar *);
+gchar *guid_convert_to_string(const GUID_t*);
+gboolean guid_equal(GUID_t *, GUID_t *);
+int get_guid_type(GUID_t *);
const gchar *wma_guid_map(int);
#endif /* _GUID_H */
diff --git a/src/libaudtag/wma/wma.c b/src/libaudtag/wma/wma.c
index c307a7c..94e181e 100644
--- a/src/libaudtag/wma/wma.c
+++ b/src/libaudtag/wma/wma.c
@@ -31,7 +31,7 @@
/* static functions */
static GenericHeader *read_generic_header(VFSFile * f, gboolean read_data)
{
- AUDDBG("read top-level header object\n");
+ TAGDBG("read top-level header object\n");
g_return_val_if_fail((f != NULL), NULL);
GenericHeader *header = g_new0(GenericHeader, 1);
header->guid = guid_read_from_file(f);
@@ -42,7 +42,7 @@ static GenericHeader *read_generic_header(VFSFile * f, gboolean read_data)
header->data = NULL;
gchar *s = guid_convert_to_string(header->guid);
- AUDDBG("read GUID: %s\n", s);
+ TAGDBG("read GUID: %s\n", s);
g_free(s);
return header;
@@ -50,7 +50,7 @@ static GenericHeader *read_generic_header(VFSFile * f, gboolean read_data)
static HeaderObj *read_top_header_object(VFSFile * f)
{
- AUDDBG("read top-level header object\n");
+ TAGDBG("read top-level header object\n");
g_return_val_if_fail((f != NULL), NULL);
HeaderObj *header = g_new0(HeaderObj, 1);
@@ -59,7 +59,7 @@ static HeaderObj *read_top_header_object(VFSFile * f)
header->size = read_LEuint64(f);
header->objectsNr = read_LEuint32(f);
- AUDDBG("Number of child objects: %d\n", header->objectsNr);
+ TAGDBG("Number of child objects: %d\n", header->objectsNr);
header->res1 = read_uint8(f);
header->res2 = read_uint8(f);
@@ -102,14 +102,14 @@ static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile * f, Tuple * t, gb
static guint find_descriptor_id(gchar * s)
{
- AUDDBG("finding descriptor id for '%s'\n", s);
+ TAGDBG("finding descriptor id for '%s'\n", s);
g_return_val_if_fail(s != NULL, -1);
gchar *l[DESC_LAST] = { DESC_ALBUM_STR, DESC_YEAR_STR, DESC_GENRE_STR, DESC_TRACK_STR };
guint i;
for (i = 0; i < DESC_LAST; i++)
if (!strcmp(l[i], s))
{
- AUDDBG("found descriptor %s\n", s);
+ TAGDBG("found descriptor %s\n", s);
return i;
}
return -1;
@@ -121,20 +121,20 @@ static ContentDescriptor *read_descriptor(VFSFile * f, Tuple * t, gboolean popul
gchar *val = NULL, *name = NULL;
guint32 intval = -1;
gint dtype;
- AUDDBG("reading name_len\n");
+ TAGDBG("reading name_len\n");
cd->name_len = read_LEuint16(f);
- AUDDBG("reading name\n");
+ TAGDBG("reading name\n");
cd->name = fread_utf16(f, cd->name_len);
- AUDDBG("reading val_type\n");
+ TAGDBG("reading val_type\n");
cd->val_type = read_LEuint16(f);
- AUDDBG("reading val_len\n");
+ TAGDBG("reading val_len\n");
cd->val_len = read_LEuint16(f);
name = utf8(cd->name);
dtype = find_descriptor_id(name);
g_free(name);
- AUDDBG("reading val\n");
+ TAGDBG("reading val\n");
if (populate_tuple)
{
@@ -143,7 +143,7 @@ static ContentDescriptor *read_descriptor(VFSFile * f, Tuple * t, gboolean popul
{ /*UTF16 */
cd->val = read_char_data(f, cd->val_len);
val = utf8((gunichar2 *) cd->val);
- AUDDBG("val: '%s' dtype: %d\n", val, dtype);
+ TAGDBG("val: '%s' dtype: %d\n", val, dtype);
if (dtype == DESC_ALBUM)
tuple_associate_string(t, FIELD_ALBUM, NULL, val);
if (dtype == DESC_GENRE)
@@ -158,7 +158,7 @@ static ContentDescriptor *read_descriptor(VFSFile * f, Tuple * t, gboolean popul
if (cd->val_type == 3)
{
intval = read_LEuint32(f);
- AUDDBG("intval: %d, dtype: %d\n", intval, dtype);
+ TAGDBG("intval: %d, dtype: %d\n", intval, dtype);
if (dtype == DESC_TRACK)
tuple_associate_int(t, FIELD_TRACK_NUMBER, NULL, intval);
}
@@ -168,8 +168,8 @@ static ContentDescriptor *read_descriptor(VFSFile * f, Tuple * t, gboolean popul
}
else
cd->val = read_char_data(f, cd->val_len);
- AUDDBG("read str_val: '%s', intval: %d\n", val, intval);
- AUDDBG("exiting read_descriptor \n\n");
+ TAGDBG("read str_val: '%s', intval: %d\n", val, intval);
+ TAGDBG("exiting read_descriptor \n\n");
return cd;
}
@@ -212,9 +212,9 @@ void free_ext_content_descr_obj(ExtContentDescrObj * ecdo)
}
/* returns the offset of the object in the file */
-static long ftell_object_by_guid(VFSFile * f, GUID * g)
+static long ftell_object_by_guid(VFSFile * f, GUID_t * g)
{
- AUDDBG("seeking object %s, with ID %d \n", guid_convert_to_string(g), get_guid_type(g));
+ TAGDBG("seeking object %s, with ID %d \n", guid_convert_to_string(g), get_guid_type(g));
HeaderObj *h = read_top_header_object(f);
g_return_val_if_fail((f != NULL) && (g != NULL) && (h != NULL), -1);
@@ -222,19 +222,19 @@ static long ftell_object_by_guid(VFSFile * f, GUID * g)
while (i < h->objectsNr)
{
GenericHeader *gen_hdr = read_generic_header(f, FALSE);
- AUDDBG("encountered GUID %s, with ID %d\n", guid_convert_to_string(gen_hdr->guid), get_guid_type(gen_hdr->guid));
+ TAGDBG("encountered GUID %s, with ID %d\n", guid_convert_to_string(gen_hdr->guid), get_guid_type(gen_hdr->guid));
if (guid_equal(gen_hdr->guid, g))
{
g_free(h);
g_free(gen_hdr);
guint64 ret = vfs_ftell(f) - 24;
- AUDDBG("at offset %" PRIx64 "\n", ret);
+ TAGDBG("at offset %" PRIx64 "\n", ret);
return ret;
}
vfs_fseek(f, gen_hdr->size - 24, SEEK_CUR); //most headers have a size as their second field"
i++;
}
- AUDDBG("The object was not found\n");
+ TAGDBG("The object was not found\n");
g_free(h);
return -1;
@@ -250,7 +250,7 @@ VFSFile *make_temp_file()
long ftell_object_by_str(VFSFile * f, gchar * s)
{
- GUID *g = guid_convert_from_string(s);
+ GUID_t *g = guid_convert_from_string(s);
long res = ftell_object_by_guid(f, g);
g_free(g);
return res;
@@ -299,7 +299,7 @@ static void write_ext_content_descr_obj_from_tuple(VFSFile * f, ExtContentDescrO
static gboolean write_generic_header(VFSFile * f, GenericHeader * gh)
{
- AUDDBG("Writing generic header\n");
+ TAGDBG("Writing generic header\n");
guid_write_to_file(f, get_guid_type(gh->guid));
return write_char_data(f, gh->data, gh->size);
}
@@ -313,7 +313,7 @@ static void free_generic_header(GenericHeader * gh)
static gboolean write_top_header_object(VFSFile * f, HeaderObj * header)
{
- AUDDBG("write header object\n");
+ TAGDBG("write header object\n");
vfs_fseek(f, 0, SEEK_SET);
return (guid_write_to_file(f, ASF_HEADER_OBJECT) && write_LEuint64(f, header->size) && write_LEuint32(f, header->objectsNr) && write_uint8(f, header->res1) && /* the reserved fields */
write_uint8(f, header->res2));
@@ -322,8 +322,8 @@ static gboolean write_top_header_object(VFSFile * f, HeaderObj * header)
/* interface functions */
gboolean wma_can_handle_file(VFSFile * f)
{
- GUID *guid1 = guid_read_from_file(f);
- GUID *guid2 = guid_convert_from_string(ASF_HEADER_OBJECT_GUID);
+ GUID_t *guid1 = guid_read_from_file(f);
+ GUID_t *guid2 = guid_convert_from_string(ASF_HEADER_OBJECT_GUID);
gboolean equal = ((guid1 != NULL) && guid_equal(guid1, guid2));
g_free(guid1);
@@ -366,10 +366,10 @@ gboolean wma_write_tag (Tuple * tuple, VFSFile * f)
HeaderObj *top_ho = read_top_header_object(f);
VFSFile *tmpfile = make_temp_file();
gint i, cdo_pos, ecdo_pos;
- GUID *g;
+ GUID_t *g;
/*read all the headers and write them to the new file */
/*the headers that contain tuple data will be overwritten */
- AUDDBG("Header Object size: %" PRId64 "\n", top_ho->size);
+ TAGDBG("Header Object size: %" PRId64 "\n", top_ho->size);
//vfs_fseek(tmpfile, )
for (i = 0; i < top_ho->objectsNr; i++)
{
@@ -414,11 +414,11 @@ gboolean wma_write_tag (Tuple * tuple, VFSFile * f)
/*
if (g_rename(f1, f2) == 0)
{
- AUDDBG("the tag was updated successfully\n");
+ TAGDBG("the tag was updated successfully\n");
}
else
{
- AUDDBG("an error has occured\n");
+ TAGDBG("an error has occured\n");
}
*/
g_free(f1);
diff --git a/src/libaudtag/wma/wma.h b/src/libaudtag/wma/wma.h
index 756cee2..2743a7b 100644
--- a/src/libaudtag/wma/wma.h
+++ b/src/libaudtag/wma/wma.h
@@ -26,26 +26,6 @@
#include "libaudcore/vfs.h"
#include "wma_fmt.h"
-#ifndef TAG_WMA_MODULE_H
-/* static functions */
-
-/* reads the whole structure, containing the data */
-static GenericHeader *read_generic_header(VFSFile *f, gboolean read_data);
-
-static HeaderObj *read_top_header_object(VFSFile *f);
-
-static gboolean write_top_header_object(VFSFile *f, HeaderObj *h);
-
-static ContentDescriptor **read_descriptors(VFSFile *f, guint count, Tuple*t, gboolean populate_tuple);
-
-static ContentDescrObj *read_content_descr_obj(VFSFile *f);
-
-static ExtContentDescrObj *read_ext_content_descr_obj(VFSFile * f, Tuple *t, gboolean populate_tuple);
-
-static long ftell_object_by_guid(VFSFile *f, GUID *g);
-static long ftell_object_by_str(VFSFile *f, gchar *s);
-#endif
-
/* TAG plugin API */
gboolean wma_can_handle_file(VFSFile *f);
gboolean wma_read_tag (Tuple * tuple, VFSFile * handle);
diff --git a/src/libaudtag/wma/wma_fmt.h b/src/libaudtag/wma/wma_fmt.h
index c96517c..17d859f 100644
--- a/src/libaudtag/wma/wma_fmt.h
+++ b/src/libaudtag/wma/wma_fmt.h
@@ -81,13 +81,13 @@ typedef enum {
* but the size is needed so that we can skip it
*/
typedef struct _generic_header {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
gchar *data;
} GenericHeader;
typedef struct _header_object {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
guint32 objectsNr;
guint8 res1;
@@ -98,7 +98,7 @@ typedef struct _header_object {
* this is special, its size does not include the size of the ext_data
*/
typedef struct _header_extension_object {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
guint32 objects_count;
guint8 res1;
@@ -108,7 +108,7 @@ typedef struct _header_extension_object {
} HeaderExtensionObject;
typedef struct _file_properties_header {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
gchar dontcare1[16];
guint64 duration; //expressed as the count of 100ns intervals
@@ -116,7 +116,7 @@ typedef struct _file_properties_header {
} FilePropertiesHeader;
typedef struct _content_description_object {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
guint16 title_length;
guint16 author_length;
@@ -148,7 +148,7 @@ typedef struct _content_descriptor {
} ContentDescriptor;
typedef struct _extended_content_description_object {
- GUID *guid;
+ GUID_t *guid;
guint64 size;
guint16 content_desc_count;
ContentDescriptor **descriptors;
diff --git a/src/libeggsmclient/eggdesktopfile.c b/src/libeggsmclient/eggdesktopfile.c
index 4d48cda..9b12af5 100644
--- a/src/libeggsmclient/eggdesktopfile.c
+++ b/src/libeggsmclient/eggdesktopfile.c
@@ -31,7 +31,7 @@
#include <unistd.h>
#include <glib/gi18n.h>
-#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
#include <gtk/gtk.h>
struct EggDesktopFile {
@@ -55,7 +55,6 @@ struct EggDesktopFile {
EggDesktopFile *
egg_desktop_file_new (const char *desktop_file_path, GError **error)
{
- EggDesktopFile *desktop_file;
GKeyFile *key_file;
key_file = g_key_file_new ();
@@ -65,13 +64,8 @@ egg_desktop_file_new (const char *desktop_file_path, GError **error)
return NULL;
}
- desktop_file = egg_desktop_file_new_from_key_file (key_file,
- desktop_file_path,
- error);
- if (!desktop_file)
- g_key_file_free (key_file);
-
- return desktop_file;
+ return egg_desktop_file_new_from_key_file (key_file, desktop_file_path,
+ error);
}
/**
@@ -105,9 +99,42 @@ egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
full_path,
error);
g_free (full_path);
- if (!desktop_file)
- g_key_file_free (key_file);
+ return desktop_file;
+}
+
+/**
+ * egg_desktop_file_new_from_dirs:
+ * @desktop_file_path: relative path to a Freedesktop-style Desktop file
+ * @search_dirs: NULL-terminated array of directories to search
+ * @error: error pointer
+ *
+ * Looks for @desktop_file_path in the paths returned from
+ * g_get_user_data_dir() and g_get_system_data_dirs(), and creates
+ * a new #EggDesktopFile from it.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error)
+{
+ EggDesktopFile *desktop_file;
+ GKeyFile *key_file;
+ char *full_path;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs,
+ &full_path, 0, error))
+ {
+ g_key_file_free (key_file);
+ return NULL;
+ }
+ desktop_file = egg_desktop_file_new_from_key_file (key_file,
+ full_path,
+ error);
+ g_free (full_path);
return desktop_file;
}
@@ -118,8 +145,8 @@ egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
* @error: error pointer
*
* Creates a new #EggDesktopFile for @key_file. Assumes ownership of
- * @key_file on success (meaning it will be freed when the desktop_file
- * is freed).
+ * @key_file (on success or failure); you should consider @key_file to
+ * be freed after calling this function.
*
* Return value: the new #EggDesktopFile, or %NULL on error.
**/
@@ -136,6 +163,7 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
EGG_DESKTOP_FILE_ERROR_INVALID,
_("File is not a valid .desktop file"));
+ g_key_file_free (key_file);
return NULL;
}
@@ -159,13 +187,14 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
EGG_DESKTOP_FILE_ERROR_INVALID,
_("Unrecognized desktop file Version '%s'"), version);
g_free (version);
+ g_key_file_free (key_file);
return NULL;
}
- else
g_free (version);
}
desktop_file = g_new0 (EggDesktopFile, 1);
+ desktop_file->key_file = key_file;
if (g_path_is_absolute (source))
desktop_file->source = g_filename_to_uri (source, NULL, NULL);
@@ -201,7 +230,7 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
if (!exec)
{
egg_desktop_file_free (desktop_file);
- g_free(type);
+ g_free (type);
return NULL;
}
@@ -234,7 +263,7 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
if (!url)
{
egg_desktop_file_free (desktop_file);
- g_free(type);
+ g_free (type);
return NULL;
}
g_free (url);
@@ -244,7 +273,7 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
else
desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED;
- g_free(type);
+ g_free (type);
/* Check the Icon key */
desktop_file->icon = g_key_file_get_string (key_file,
@@ -269,7 +298,6 @@ egg_desktop_file_new_from_key_file (GKeyFile *key_file,
}
}
- desktop_file->key_file = key_file;
return desktop_file;
}
@@ -290,22 +318,6 @@ egg_desktop_file_free (EggDesktopFile *desktop_file)
}
/**
- * egg_desktop_file_get_key_file:
- * @desktop_file: an #EggDesktopFile
- *
- * Gets the #GKeyFile associated with @desktop_file. You must not free
- * this value, and changes made to it will not be reflected by
- * @desktop_file.
- *
- * Return value: the #GKeyFile associated with @desktop_file.
- **/
-GKeyFile *
-egg_desktop_file_get_key_file (EggDesktopFile *desktop_file)
-{
- return desktop_file->key_file;
-}
-
-/**
* egg_desktop_file_get_source:
* @desktop_file: an #EggDesktopFile
*
@@ -368,6 +380,91 @@ egg_desktop_file_get_icon (EggDesktopFile *desktop_file)
return desktop_file->icon;
}
+gboolean
+egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_has_key (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error)
+{
+ return g_key_file_get_locale_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, locale,
+ error);
+}
+
+gboolean
+egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_boolean (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+double
+egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_double (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+int
+egg_desktop_file_get_integer (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_integer (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char **
+egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, length,
+ error);
+}
+
+char **
+egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_locale_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ locale, length,
+ error);
+}
+
/**
* egg_desktop_file_can_launch:
* @desktop_file: an #EggDesktopFile
@@ -822,7 +919,7 @@ parse_link (EggDesktopFile *desktop_file,
return TRUE;
}
-#ifdef HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE
+#if GTK_CHECK_VERSION (2, 12, 0)
static char *
start_startup_notification (GdkDisplay *display,
EggDesktopFile *desktop_file,
@@ -900,7 +997,7 @@ end_startup_notification (GdkDisplay *display,
NULL);
}
-#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */ * 1000)
+#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */)
typedef struct {
GdkDisplay *display;
@@ -930,24 +1027,32 @@ set_startup_notification_timeout (GdkDisplay *display,
sn_data->display = g_object_ref (display);
sn_data->startup_id = g_strdup (startup_id);
- g_timeout_add (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH,
- startup_notification_timeout, sn_data);
+ g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH,
+ startup_notification_timeout, sn_data);
}
-#endif /* HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE */
-
-extern char **environ;
+#endif /* GTK 2.12 */
static GPtrArray *
array_putenv (GPtrArray *env, char *variable)
{
- int i, keylen;
+ guint i, keylen;
if (!env)
{
+ char **envp;
+
env = g_ptr_array_new ();
- for (i = 0; environ[i]; i++)
- g_ptr_array_add (env, g_strdup (environ[i]));
+ envp = g_listenv ();
+ for (i = 0; envp[i]; i++)
+ {
+ const char *value;
+
+ value = g_getenv (envp[i]);
+ g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i],
+ value ? value : ""));
+ }
+ g_strfreev (envp);
}
keylen = strcspn (variable, "=");
@@ -977,7 +1082,7 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
GError **error)
{
EggDesktopFileLaunchOption option;
- GSList *translated_documents, *docs;
+ GSList *translated_documents = NULL, *docs = NULL;
char *command, **argv;
int argc, i, screen_num;
gboolean success, current_success;
@@ -993,8 +1098,6 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
GSpawnChildSetupFunc setup_func = NULL;
gpointer setup_data = NULL;
- docs = NULL;
- translated_documents = NULL;
GPid *ret_pid = NULL;
int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL;
@@ -1114,7 +1217,7 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
}
g_free (command);
-#ifdef HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE
+#if GTK_CHECK_VERSION (2, 12, 0)
startup_id = start_startup_notification (display, desktop_file,
argv[0], screen_num,
workspace, launch_time);
@@ -1127,7 +1230,10 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
}
#else
startup_id = NULL;
-#endif /* HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE */
+#endif /* GTK 2.12 */
+
+ if (env != NULL)
+ g_ptr_array_add (env, NULL);
current_success =
g_spawn_async_with_pipes (directory,
@@ -1142,7 +1248,7 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
if (startup_id)
{
-#ifdef HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE
+#if GTK_CHECK_VERSION (2, 12, 0)
if (current_success)
{
set_startup_notification_timeout (display, startup_id);
@@ -1153,7 +1259,7 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
g_free (startup_id);
}
else
-#endif /* HAVE_GDK_X11_DISPLAY_BROADCAST_STARTUP_MESSAGE */
+#endif /* GTK 2.12 */
g_free (startup_id);
}
else if (ret_startup_id)
@@ -1178,8 +1284,8 @@ egg_desktop_file_launchv (EggDesktopFile *desktop_file,
out:
if (env)
{
- g_strfreev ((char **)env->pdata);
- g_ptr_array_free (env, FALSE);
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
}
free_document_list (translated_documents);
@@ -1290,6 +1396,8 @@ egg_desktop_file_launch (EggDesktopFile *desktop_file,
free_document_list (documents);
break;
+ case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED:
+ case EGG_DESKTOP_FILE_TYPE_DIRECTORY:
default:
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
@@ -1312,6 +1420,40 @@ egg_desktop_file_error_quark (void)
G_LOCK_DEFINE_STATIC (egg_desktop_file);
static EggDesktopFile *egg_desktop_file;
+static void
+egg_set_desktop_file_internal (const char *desktop_file_path,
+ gboolean set_defaults)
+{
+ GError *error = NULL;
+
+ G_LOCK (egg_desktop_file);
+ if (egg_desktop_file)
+ egg_desktop_file_free (egg_desktop_file);
+
+ egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error);
+ if (error)
+ {
+ g_warning ("Could not load desktop file '%s': %s",
+ desktop_file_path, error->message);
+ g_error_free (error);
+ }
+
+ if (set_defaults && egg_desktop_file != NULL) {
+ /* Set localized application name and default window icon */
+ if (egg_desktop_file->name)
+ g_set_application_name (egg_desktop_file->name);
+ if (egg_desktop_file->icon)
+ {
+ if (g_path_is_absolute (egg_desktop_file->icon))
+ gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL);
+ else
+ gtk_window_set_default_icon_name (egg_desktop_file->icon);
+ }
+ }
+
+ G_UNLOCK (egg_desktop_file);
+}
+
/**
* egg_set_desktop_file:
* @desktop_file_path: path to the application's desktop file
@@ -1323,42 +1465,38 @@ static EggDesktopFile *egg_desktop_file;
* gtk_window_set_default_icon_from_file() with the application's
* icon. Other code may use additional information from the desktop
* file.
+ * See egg_set_desktop_file_without_defaults() for a variant of this
+ * function that does not set the application name and default window
+ * icon.
*
* Note that for thread safety reasons, this function can only
- * be called once.
+ * be called once, and is mutually exclusive with calling
+ * egg_set_desktop_file_without_defaults().
**/
void
egg_set_desktop_file (const char *desktop_file_path)
{
- GError *error = NULL;
-
- G_LOCK (egg_desktop_file);
- if (egg_desktop_file)
- egg_desktop_file_free (egg_desktop_file);
-
- egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error);
- if (error)
- {
- g_warning ("Could not load desktop file '%s': %s"
- " - Session management may not work now.",
- desktop_file_path, error->message);
- g_error_free (error);
- G_UNLOCK (egg_desktop_file);
- return;
- }
-
- /* Set localized application name and default window icon */
- if (egg_desktop_file->name)
- g_set_application_name (egg_desktop_file->name);
- if (egg_desktop_file->icon)
- {
- if (g_path_is_absolute (egg_desktop_file->icon))
- gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL);
- else
- gtk_window_set_default_icon_name (egg_desktop_file->icon);
- }
+ egg_set_desktop_file_internal (desktop_file_path, TRUE);
+}
- G_UNLOCK (egg_desktop_file);
+/**
+ * egg_set_desktop_file_without_defaults:
+ * @desktop_file_path: path to the application's desktop file
+ *
+ * Creates an #EggDesktopFile for the application from the data at
+ * @desktop_file_path.
+ * See egg_set_desktop_file() for a variant of this function that
+ * sets the application name and default window icon from the information
+ * in the desktop file.
+ *
+ * Note that for thread safety reasons, this function can only
+ * be called once, and is mutually exclusive with calling
+ * egg_set_desktop_file().
+ **/
+void
+egg_set_desktop_file_without_defaults (const char *desktop_file_path)
+{
+ egg_set_desktop_file_internal (desktop_file_path, FALSE);
}
/**
diff --git a/src/libeggsmclient/eggdesktopfile.h b/src/libeggsmclient/eggdesktopfile.h
index f130541..16c5426 100644
--- a/src/libeggsmclient/eggdesktopfile.h
+++ b/src/libeggsmclient/eggdesktopfile.h
@@ -31,22 +31,23 @@ typedef enum {
EGG_DESKTOP_FILE_TYPE_APPLICATION,
EGG_DESKTOP_FILE_TYPE_LINK,
- EGG_DESKTOP_FILE_TYPE_DIRECTORY,
+ EGG_DESKTOP_FILE_TYPE_DIRECTORY
} EggDesktopFileType;
EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path,
GError **error);
-EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
- GError **error);
-EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *desktop,
+EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file,
const char *source,
GError **error);
void egg_desktop_file_free (EggDesktopFile *desktop_file);
-GKeyFile *egg_desktop_file_get_key_file (EggDesktopFile *desktop_file);
-
const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file);
EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file);
@@ -109,6 +110,37 @@ typedef enum {
#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass"
#define EGG_DESKTOP_FILE_KEY_URL "URL"
+/* Accessors */
+gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char *egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error) G_GNUC_MALLOC;
+char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error) G_GNUC_MALLOC;
+gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+int egg_desktop_file_get_integer (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+
+
/* Errors */
#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark()
@@ -117,12 +149,13 @@ GQuark egg_desktop_file_error_quark (void);
typedef enum {
EGG_DESKTOP_FILE_ERROR_INVALID,
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
- EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION,
+ EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION
} EggDesktopFileError;
/* Global application desktop file */
-void egg_set_desktop_file (const char *desktop_file_path);
-EggDesktopFile *egg_get_desktop_file (void);
+void egg_set_desktop_file (const char *desktop_file_path);
+void egg_set_desktop_file_without_defaults (const char *desktop_file_path);
+EggDesktopFile *egg_get_desktop_file (void);
G_END_DECLS
diff --git a/src/libeggsmclient/eggsmclient-osx.c b/src/libeggsmclient/eggsmclient-osx.c
deleted file mode 100644
index 066ccc2..0000000
--- a/src/libeggsmclient/eggsmclient-osx.c
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2007 Novell, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#define G_LOG_DOMAIN "EggSMClient"
-
-#include "eggsmclient.h"
-
-#define EGG_TYPE_SM_CLIENT_OSX (egg_sm_client_osx_get_type ())
-#define EGG_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSX))
-#define EGG_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
-#define EGG_IS_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_OSX))
-#define EGG_IS_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_OSX))
-#define EGG_SM_CLIENT_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
-
-typedef struct _EggSMClientOSX EggSMClientOSX;
-typedef struct _EggSMClientOSXClass EggSMClientOSXClass;
-
-struct _EggSMClientOSX {
- EggSMClient parent;
-
-}
-
-struct _EggSMClientOSXClass
-{
- EggSMClientClass parent_class;
-
-};
-
-static void sm_client_osx_startup (EggSMClient *client,
- const char *client_id);
-static void sm_client_osx_will_quit (EggSMClient *client,
- gboolean will_quit);
-static gboolean sm_client_osx_end_session (EggSMClient *client,
- EggSMClientEndStyle style,
- gboolean request_confirmation);
-
-static GdkFilterReturn sm_client_osx_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data);
-
-G_DEFINE_TYPE (EggSMClientOSX, egg_sm_client_osx, EGG_TYPE_SM_CLIENT)
-
-static void
-egg_sm_client_osx_init (EggSMClientOSX *osxclient)
-{
- ;
-}
-
-static void
-egg_sm_client_osx_class_init (EggSMClientOSXClass *klass)
-{
- EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
-
- sm_client_class->startup = sm_client_osx_startup;
- sm_client_class->will_quit = sm_client_osx_will_quit;
- sm_client_class->end_session = sm_client_osx_end_session;
-}
-
-EggSMClient *
-egg_sm_client_osx_new (void)
-{
- return g_object_new (EGG_TYPE_SM_CLIENT_OSX, NULL);
-}
-
-static void
-sm_client_osx_startup (EggSMClient *client)
-{
- gdk_window_add_filter (NULL, sm_client_osx_filter, client);
-}
-
-void
-sm_client_osx_will_quit (EggSMClient *client,
- gboolean will_quit)
-{
- EggSMClientOSX *osxclient = (EggSMClientOSX *)client;
-
- if (will_quit)
- {
- /* OS X doesn't send another message. We're supposed to just
- * quit after agreeing that it's OK.
- *
- * FIXME: do it from an idle handler though.
- */
- egg_sm_client_quit (client);
- }
- else
- {
- /* FIXME: "respond to the event by returning a userCancelledErr
- * error"
- */
- }
-}
-
-void
-sm_client_osx_end_session (EggSMClient *client,
- EggSMClientEndStyle style,
- gboolean request_confirmation)
-{
- EggSMClientOSX *osxclient = (EggSMClientOSX *)client;
- FIXME_t event;
-
- switch (style)
- {
- case EGG_SM_CLIENT_END_SESSION_DEFAULT:
- case EGG_SM_CLIENT_END_LOGOUT:
- event = request_confirmation ? kAELogOut : kAEReallyLogOut;
- break;
- case EGG_SM_CLIENT_END_REBOOT:
- event = request_confirmation ? kAEShowRestartDialog : kAERestart;
- break;
- case EGG_SM_CLIENT_END_SHUTDOWN:
- event = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
- break;
- }
-
- /* FIXME: send event to loginwindow process */
-}
-
-static GdkFilterReturn
-egg_sm_client_osx_filter (GdkXEvent *xevent,
- GdkEvent *event,
- gpointer data)
-{
- EggSMClientOSX *osxclient = data;
- EggSMClient *client = data;
- NSEvent *nsevent = (NSEvent *)xevent;
-
- switch (FIXME_get_apple_event_type (nsevent))
- {
- case kAEQuitApplication:
- if (FIXME_app_is_a_foreground_app)
- egg_sm_client_quit_requested (client);
- else
- egg_sm_client_quit (client);
- return GDK_FILTER_REMOVE;
-
- default:
- return GDK_FILTER_CONTINUE;
- }
-}
diff --git a/src/libeggsmclient/eggsmclient-private.h b/src/libeggsmclient/eggsmclient-private.h
index ccb10bf..0c98eee 100644
--- a/src/libeggsmclient/eggsmclient-private.h
+++ b/src/libeggsmclient/eggsmclient-private.h
@@ -20,7 +20,13 @@
#ifndef __EGG_SM_CLIENT_PRIVATE_H__
#define __EGG_SM_CLIENT_PRIVATE_H__
+#include <gtk/gtk.h>
+
+#if !GTK_CHECK_VERSION(2,91,7) && !GTK_CHECK_VERSION(3,0,0)
+/* GTK+ 3 includes this automatically */
#include <gdkconfig.h>
+#endif
+
#include "eggsmclient.h"
G_BEGIN_DECLS
diff --git a/src/libeggsmclient/eggsmclient-win32.c b/src/libeggsmclient/eggsmclient-win32.c
index 91a0f74..49e63ae 100644
--- a/src/libeggsmclient/eggsmclient-win32.c
+++ b/src/libeggsmclient/eggsmclient-win32.c
@@ -17,6 +17,35 @@
* Boston, MA 02111-1307, USA.
*/
+/* EggSMClientWin32
+ *
+ * For details on the Windows XP logout process, see:
+ * http://msdn.microsoft.com/en-us/library/aa376876.aspx.
+ *
+ * Vista adds some new APIs which EggSMClient does not make use of; see
+ * http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
+ *
+ * When shutting down, Windows sends every top-level window a
+ * WM_QUERYENDSESSION event, which the application must respond to
+ * synchronously, saying whether or not it will quit. To avoid main
+ * loop re-entrancy problems (and to avoid having to muck about too
+ * much with the guts of the gdk-win32 main loop), we watch for this
+ * event in a separate thread, which then signals the main thread and
+ * waits for the main thread to handle the event. Since we don't want
+ * to require g_thread_init() to be called, we do this all using
+ * Windows-specific thread methods.
+ *
+ * After the application handles the WM_QUERYENDSESSION event,
+ * Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
+ * parameter indicating whether the session is or is not actually
+ * going to end now. We handle this from the other thread as well.
+ *
+ * As mentioned above, Vista introduces several additional new APIs
+ * that don't fit into the (current) EggSMClient API. Windows also has
+ * an entirely separate shutdown-notification scheme for non-GUI apps,
+ * which we also don't handle here.
+ */
+
#include "config.h"
#include "eggsmclient-private.h"
@@ -25,6 +54,7 @@
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <windows.h>
+#include <process.h>
#define EGG_TYPE_SM_CLIENT_WIN32 (egg_sm_client_win32_get_type ())
#define EGG_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
@@ -39,7 +69,10 @@ typedef struct _EggSMClientWin32Class EggSMClientWin32Class;
struct _EggSMClientWin32 {
EggSMClient parent;
- GAsyncQueue *msg_queue;
+ HANDLE message_event, response_event;
+
+ volatile GSourceFunc event;
+ volatile gboolean will_quit;
};
struct _EggSMClientWin32Class
@@ -56,7 +89,10 @@ static gboolean sm_client_win32_end_session (EggSMClient *client,
EggSMClientEndStyle style,
gboolean request_confirmation);
-static gpointer sm_client_thread (gpointer data);
+static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
+ gpointer user_data);
+static gboolean got_message (gpointer user_data);
+static void sm_client_thread (gpointer data);
G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
@@ -88,9 +124,10 @@ sm_client_win32_startup (EggSMClient *client,
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
- /* spawn another thread to listen for logout signals on */
- win32->msg_queue = g_async_queue_new ();
- g_thread_create (sm_client_thread, client, FALSE, NULL);
+ win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ g_win32_handle_source_add (win32->message_event, got_message, win32);
+ _beginthread (sm_client_thread, 0, client);
}
static void
@@ -99,8 +136,8 @@ sm_client_win32_will_quit (EggSMClient *client,
{
EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
- /* Can't push NULL onto a GAsyncQueue, so we add 1 to the value... */
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (will_quit + 1));
+ win32->will_quit = will_quit;
+ SetEvent (win32->response_event);
}
static gboolean
@@ -143,9 +180,7 @@ sm_client_win32_end_session (EggSMClient *client,
static gboolean
emit_quit_requested (gpointer smclient)
{
- gdk_threads_enter ();
egg_sm_client_quit_requested (smclient);
- gdk_threads_leave ();
return FALSE;
}
@@ -155,11 +190,9 @@ emit_quit (gpointer smclient)
{
EggSMClientWin32 *win32 = smclient;
- gdk_threads_enter ();
egg_sm_client_quit (smclient);
- gdk_threads_leave ();
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+ SetEvent (win32->response_event);
return FALSE;
}
@@ -168,29 +201,82 @@ emit_quit_cancelled (gpointer smclient)
{
EggSMClientWin32 *win32 = smclient;
- gdk_threads_enter ();
egg_sm_client_quit_cancelled (smclient);
- gdk_threads_leave ();
- g_async_queue_push (win32->msg_queue, GINT_TO_POINTER (1));
+ SetEvent (win32->response_event);
return FALSE;
}
+static gboolean
+got_message (gpointer smclient)
+{
+ EggSMClientWin32 *win32 = smclient;
+
+ win32->event (win32);
+ return TRUE;
+}
+
+/* Windows HANDLE GSource */
-/* logout-listener thread */
+typedef struct {
+ GSource source;
+ GPollFD pollfd;
+} GWin32HandleSource;
-static int
-async_emit (EggSMClientWin32 *win32, GSourceFunc emitter)
+static gboolean
+g_win32_handle_source_prepare (GSource *source, gint *timeout)
+{
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+g_win32_handle_source_check (GSource *source)
{
- /* ensure message queue is empty */
- while (g_async_queue_try_pop (win32->msg_queue))
- ;
+ GWin32HandleSource *hsource = (GWin32HandleSource *)source;
- /* Emit signal in the main thread and wait for a response */
- g_idle_add (emitter, win32);
- return GPOINTER_TO_INT (g_async_queue_pop (win32->msg_queue)) - 1;
+ return hsource->pollfd.revents;
}
+static gboolean
+g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ return (*callback) (user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+ ;
+}
+
+GSourceFuncs g_win32_handle_source_funcs = {
+ g_win32_handle_source_prepare,
+ g_win32_handle_source_check,
+ g_win32_handle_source_dispatch,
+ g_win32_handle_source_finalize
+};
+
+static GSource *
+g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
+{
+ GWin32HandleSource *hsource;
+ GSource *source;
+
+ source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
+ hsource = (GWin32HandleSource *)source;
+ hsource->pollfd.fd = (int)handle;
+ hsource->pollfd.events = G_IO_IN;
+ hsource->pollfd.revents = 0;
+ g_source_add_poll (source, &hsource->pollfd);
+
+ g_source_set_callback (source, callback, user_data, NULL);
+ g_source_attach (source, NULL);
+ return source;
+}
+
+/* logout-listener thread */
+
LRESULT CALLBACK
sm_client_win32_window_procedure (HWND hwnd,
UINT message,
@@ -203,19 +289,27 @@ sm_client_win32_window_procedure (HWND hwnd,
switch (message)
{
case WM_QUERYENDSESSION:
- return async_emit (win32, emit_quit_requested);
+ win32->event = emit_quit_requested;
+ SetEvent (win32->message_event);
+
+ WaitForSingleObject (win32->response_event, INFINITE);
+ return win32->will_quit;
case WM_ENDSESSION:
if (wParam)
{
/* The session is ending */
- async_emit (win32, emit_quit);
+ win32->event = emit_quit;
}
else
{
/* Nope, the session *isn't* ending */
- async_emit (win32, emit_quit_cancelled);
+ win32->event = emit_quit_cancelled;
}
+
+ SetEvent (win32->message_event);
+ WaitForSingleObject (win32->response_event, INFINITE);
+
return 0;
default:
@@ -223,11 +317,11 @@ sm_client_win32_window_procedure (HWND hwnd,
}
}
-static gpointer
+static void
sm_client_thread (gpointer smclient)
{
HINSTANCE instance;
- WNDCLASSEXW wcl;
+ WNDCLASSEXW wcl;
ATOM klass;
HWND window;
MSG msg;
@@ -250,6 +344,4 @@ sm_client_thread (gpointer smclient)
/* main loop */
while (GetMessage (&msg, NULL, 0, 0))
DispatchMessage (&msg);
-
- return NULL;
}
diff --git a/src/libeggsmclient/eggsmclient-xsmp.c b/src/libeggsmclient/eggsmclient-xsmp.c
index 8e13ff4..84a8eb8 100644
--- a/src/libeggsmclient/eggsmclient-xsmp.c
+++ b/src/libeggsmclient/eggsmclient-xsmp.c
@@ -36,6 +36,7 @@
#include <X11/SM/SMlib.h>
#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
#define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ())
#define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP))
@@ -62,11 +63,10 @@ typedef enum
XSMP_STATE_INTERACT,
XSMP_STATE_SAVE_YOURSELF_DONE,
XSMP_STATE_SHUTDOWN_CANCELLED,
- XSMP_STATE_CONNECTION_CLOSED,
+ XSMP_STATE_CONNECTION_CLOSED
} EggSMClientXSMPState;
static const char *state_names[] = {
- "start",
"idle",
"save-yourself",
"interact-request",
@@ -221,19 +221,14 @@ sm_client_xsmp_set_initial_properties (gpointer user_data)
desktop_file = egg_get_desktop_file ();
if (desktop_file)
{
- GKeyFile *key_file;
GError *err = NULL;
char *cmdline, **argv;
int argc;
- key_file = egg_desktop_file_get_key_file (desktop_file);
-
if (xsmp->restart_style == SmRestartIfRunning)
{
- if (g_key_file_has_key (key_file, EGG_DESKTOP_FILE_GROUP,
- "X-GNOME-AutoRestart", NULL) &&
- g_key_file_get_boolean (key_file, EGG_DESKTOP_FILE_GROUP,
- "X-GNOME-AutoRestart", NULL))
+ if (egg_desktop_file_get_boolean (desktop_file,
+ "X-GNOME-AutoRestart", NULL))
xsmp->restart_style = SmRestartImmediately;
}
@@ -252,6 +247,7 @@ sm_client_xsmp_set_initial_properties (gpointer user_data)
err->message);
g_error_free (err);
}
+ g_free (cmdline);
}
}
@@ -371,9 +367,11 @@ sm_client_xsmp_startup (EggSMClient *client,
xsmp->client_id = g_strdup (ret_client_id);
free (ret_client_id);
- gdk_threads_enter ();
+#if !GTK_CHECK_VERSION(2,91,7) && !GTK_CHECK_VERSION(3,0,0)
gdk_set_sm_client_id (xsmp->client_id);
- gdk_threads_leave ();
+#else
+ gdk_x11_set_sm_client_id (xsmp->client_id);
+#endif
g_debug ("Got client ID \"%s\"", xsmp->client_id);
}
@@ -541,8 +539,6 @@ idle_do_pending_events (gpointer data)
EggSMClientXSMP *xsmp = data;
EggSMClient *client = data;
- gdk_threads_enter ();
-
xsmp->idle = 0;
if (xsmp->waiting_to_emit_quit)
@@ -566,7 +562,6 @@ idle_do_pending_events (gpointer data)
}
out:
- gdk_threads_leave ();
return FALSE;
}
@@ -771,30 +766,6 @@ do_save_yourself (EggSMClientXSMP *xsmp)
}
static void
-merge_keyfiles (GKeyFile *dest, GKeyFile *source)
-{
- int g, k;
- char **groups, **keys, *value;
-
- groups = g_key_file_get_groups (source, NULL);
- for (g = 0; groups[g]; g++)
- {
- keys = g_key_file_get_keys (source, groups[g], NULL, NULL);
- for (k = 0; keys[k]; k++)
- {
- value = g_key_file_get_value (source, groups[g], keys[k], NULL);
- if (value)
- {
- g_key_file_set_value (dest, groups[g], keys[k], value);
- g_free (value);
- }
- }
- g_strfreev (keys);
- }
- g_strfreev (groups);
-}
-
-static void
save_state (EggSMClientXSMP *xsmp)
{
GKeyFile *state_file;
@@ -824,30 +795,61 @@ save_state (EggSMClientXSMP *xsmp)
if (desktop_file)
{
GKeyFile *merged_file;
- char *exec;
- int i;
+ char *desktop_file_path;
merged_file = g_key_file_new ();
- merge_keyfiles (merged_file, egg_desktop_file_get_key_file (desktop_file));
- merge_keyfiles (merged_file, state_file);
-
- g_key_file_free (state_file);
- state_file = merged_file;
-
- /* Update Exec key using "--sm-client-state-file %k" */
- restart = generate_command (xsmp->restart_command,
- NULL, "%k");
- for (i = 0; i < restart->len; i++)
- restart->pdata[i] = g_shell_quote (restart->pdata[i]);
- g_ptr_array_add (restart, NULL);
- exec = g_strjoinv (" ", (char **)restart->pdata);
- g_strfreev ((char **)restart->pdata);
- g_ptr_array_free (restart, FALSE);
-
- g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP,
- EGG_DESKTOP_FILE_KEY_EXEC,
- exec);
- g_free (exec);
+ desktop_file_path =
+ g_filename_from_uri (egg_desktop_file_get_source (desktop_file),
+ NULL, NULL);
+ if (desktop_file_path &&
+ g_key_file_load_from_file (merged_file, desktop_file_path,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS, NULL))
+ {
+ guint g, k, i;
+ char **groups, **keys, *value, *exec;
+
+ groups = g_key_file_get_groups (state_file, NULL);
+ for (g = 0; groups[g]; g++)
+ {
+ keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL);
+ for (k = 0; keys[k]; k++)
+ {
+ value = g_key_file_get_value (state_file, groups[g],
+ keys[k], NULL);
+ if (value)
+ {
+ g_key_file_set_value (merged_file, groups[g],
+ keys[k], value);
+ g_free (value);
+ }
+ }
+ g_strfreev (keys);
+ }
+ g_strfreev (groups);
+
+ g_key_file_free (state_file);
+ state_file = merged_file;
+
+ /* Update Exec key using "--sm-client-state-file %k" */
+ restart = generate_command (xsmp->restart_command,
+ NULL, "%k");
+ for (i = 0; i < restart->len; i++)
+ restart->pdata[i] = g_shell_quote (restart->pdata[i]);
+ g_ptr_array_add (restart, NULL);
+ exec = g_strjoinv (" ", (char **)restart->pdata);
+ g_strfreev ((char **)restart->pdata);
+ g_ptr_array_free (restart, FALSE);
+
+ g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_EXEC,
+ exec);
+ g_free (exec);
+ }
+ else
+ desktop_file = NULL;
+
+ g_free (desktop_file_path);
}
/* Now write state_file to disk. (We can't use mktemp(), because
@@ -1050,13 +1052,13 @@ generate_command (char **restart_command, const char *client_id,
if (client_id)
{
- g_ptr_array_add (cmd, "--sm-client-id");
+ g_ptr_array_add (cmd, (char *)"--sm-client-id");
g_ptr_array_add (cmd, (char *)client_id);
}
if (state_file)
{
- g_ptr_array_add (cmd, "--sm-client-state-file");
+ g_ptr_array_add (cmd, (char *)"--sm-client-state-file");
g_ptr_array_add (cmd, (char *)state_file);
}
@@ -1076,7 +1078,7 @@ set_properties (EggSMClientXSMP *xsmp, ...)
GPtrArray *props;
SmProp *prop;
va_list ap;
- int i;
+ guint i;
props = g_ptr_array_new ();
@@ -1129,7 +1131,7 @@ delete_properties (EggSMClientXSMP *xsmp, ...)
* until you're done with the SmProp.
*/
static SmProp *
-array_prop (const char *name, ...)
+array_prop (const char *name, ...)
{
SmProp *prop;
SmPropValue pv;
@@ -1139,7 +1141,7 @@ array_prop (const char *name, ...)
prop = g_new (SmProp, 1);
prop->name = (char *)name;
- prop->type = SmLISTofARRAY8;
+ prop->type = (char *)SmLISTofARRAY8;
vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
@@ -1169,11 +1171,11 @@ ptrarray_prop (const char *name, GPtrArray *values)
SmProp *prop;
SmPropValue pv;
GArray *vals;
- int i;
+ guint i;
prop = g_new (SmProp, 1);
prop->name = (char *)name;
- prop->type = SmLISTofARRAY8;
+ prop->type = (char *)SmLISTofARRAY8;
vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
@@ -1203,7 +1205,7 @@ string_prop (const char *name, const char *value)
prop = g_new (SmProp, 1);
prop->name = (char *)name;
- prop->type = SmARRAY8;
+ prop->type = (char *)SmARRAY8;
prop->num_vals = 1;
prop->vals = g_new (SmPropValue, 1);
@@ -1228,7 +1230,7 @@ card8_prop (const char *name, unsigned char value)
prop = g_new (SmProp, 1);
prop->name = (char *)name;
- prop->type = SmCARD8;
+ prop->type = (char *)SmCARD8;
prop->num_vals = 1;
prop->vals = g_new (SmPropValue, 2);
@@ -1280,9 +1282,7 @@ process_ice_messages (IceConn ice_conn)
{
IceProcessMessagesStatus status;
- gdk_threads_enter ();
status = IceProcessMessages (ice_conn, NULL, NULL);
- gdk_threads_leave ();
switch (status)
{
@@ -1347,13 +1347,13 @@ ice_error_handler (IceConn ice_conn,
IcePointer values)
{
/* Do nothing */
-}
+}
static void
ice_io_error_handler (IceConn ice_conn)
{
/* Do nothing */
-}
+}
static void
smc_error_handler (SmcConn smc_conn,
diff --git a/src/libeggsmclient/eggsmclient.c b/src/libeggsmclient/eggsmclient.c
index d778de5..92be8a7 100644
--- a/src/libeggsmclient/eggsmclient.c
+++ b/src/libeggsmclient/eggsmclient.c
@@ -17,6 +17,8 @@
* Boston, MA 02111-1307, USA.
*/
+#include "config.h"
+
#include <string.h>
#include <glib/gi18n.h>
@@ -36,7 +38,7 @@ enum {
LAST_SIGNAL
};
-static guint signals[LAST_SIGNAL] = { 0 };
+static guint signals[LAST_SIGNAL];
struct _EggSMClientPrivate {
GKeyFile *state_file;
@@ -176,19 +178,7 @@ egg_sm_client_class_init (EggSMClientClass *klass)
static gboolean sm_client_disable = FALSE;
static char *sm_client_state_file = NULL;
static char *sm_client_id = NULL;
-
-static GOptionEntry entries[] = {
- { "sm-client-disable", 0, 0,
- G_OPTION_ARG_NONE, &sm_client_disable,
- N_("Disable connection to session manager"), NULL },
- { "sm-client-state-file", 0, 0,
- G_OPTION_ARG_STRING, &sm_client_state_file,
- N_("Specify file containing saved configuration"), N_("FILE") },
- { "sm-client-id", 0, 0,
- G_OPTION_ARG_STRING, &sm_client_id,
- N_("Specify session management ID"), N_("ID") },
- { NULL }
-};
+static char *sm_config_prefix = NULL;
static gboolean
sm_client_post_parse_func (GOptionContext *context,
@@ -198,7 +188,22 @@ sm_client_post_parse_func (GOptionContext *context,
{
EggSMClient *client = egg_sm_client_get ();
- if (EGG_SM_CLIENT_GET_CLASS (client)->startup)
+ if (sm_client_id == NULL)
+ {
+ const gchar *desktop_autostart_id;
+
+ desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
+
+ if (desktop_autostart_id != NULL)
+ sm_client_id = g_strdup (desktop_autostart_id);
+ }
+
+ /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
+ * use the same client id. */
+ g_unsetenv ("DESKTOP_AUTOSTART_ID");
+
+ if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
+ EGG_SM_CLIENT_GET_CLASS (client)->startup)
EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
return TRUE;
}
@@ -215,6 +220,29 @@ sm_client_post_parse_func (GOptionContext *context,
GOptionGroup *
egg_sm_client_get_option_group (void)
{
+ const GOptionEntry entries[] = {
+ { "sm-client-disable", 0, 0,
+ G_OPTION_ARG_NONE, &sm_client_disable,
+ N_("Disable connection to session manager"), NULL },
+ { "sm-client-state-file", 0, 0,
+ G_OPTION_ARG_FILENAME, &sm_client_state_file,
+ N_("Specify file containing saved configuration"), N_("FILE") },
+ { "sm-client-id", 0, 0,
+ G_OPTION_ARG_STRING, &sm_client_id,
+ N_("Specify session management ID"), N_("ID") },
+ /* GnomeClient compatibility option */
+ { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_NONE, &sm_client_disable,
+ NULL, NULL },
+ /* GnomeClient compatibility option. This is a dummy option that only
+ * exists so that sessions saved by apps with GnomeClient can be restored
+ * later when they've switched to EggSMClient. See bug #575308.
+ */
+ { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING, &sm_config_prefix,
+ NULL, NULL },
+ { NULL }
+ };
GOptionGroup *group;
/* Use our own debug handler for the "EggSMClient" domain. */
@@ -222,8 +250,8 @@ egg_sm_client_get_option_group (void)
egg_sm_client_debug_handler, NULL);
group = g_option_group_new ("sm-client",
- _("Session Management Options"),
- _("Show Session Management options"),
+ _("Session management options:"),
+ _("Show session management options"),
NULL, NULL);
g_option_group_add_entries (group, entries);
g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func);
@@ -238,9 +266,9 @@ egg_sm_client_get_option_group (void)
* Sets the "mode" of #EggSMClient as follows:
*
* %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
- * disabled. The application will not even connect to the session
- * manager. (egg_sm_client_get() will still return an #EggSMClient,
- * but it will just be a dummy object.)
+ * disabled, until the mode is changed again. The application will
+ * not even connect to the session manager. (egg_sm_client_get()
+ * will still return an #EggSMClient object.)
*
* %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
* the session manager (and thus will receive notification when the
@@ -250,12 +278,27 @@ egg_sm_client_get_option_group (void)
* %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
* function normally.
*
- * This must be called before the application's main loop begins.
+ * This must be called before the application's main loop begins and
+ * before any call to egg_sm_client_get(), unless the mode was set
+ * earlier to %EGG_SM_CLIENT_MODE_DISABLED and this call enables
+ * session management. Note that option parsing will call
+ * egg_sm_client_get().
**/
void
egg_sm_client_set_mode (EggSMClientMode mode)
{
+ EggSMClientMode old_mode = global_client_mode;
+
+ g_return_if_fail (global_client == NULL || global_client_mode == EGG_SM_CLIENT_MODE_DISABLED);
+ g_return_if_fail (!(global_client != NULL && mode == EGG_SM_CLIENT_MODE_DISABLED));
+
global_client_mode = mode;
+
+ if (global_client != NULL && old_mode == EGG_SM_CLIENT_MODE_DISABLED)
+ {
+ if (EGG_SM_CLIENT_GET_CLASS (global_client)->startup)
+ EGG_SM_CLIENT_GET_CLASS (global_client)->startup (global_client, sm_client_id);
+ }
}
/**
@@ -290,24 +333,23 @@ egg_sm_client_get (void)
{
if (!global_client)
{
- if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
- !sm_client_disable)
+ if (!sm_client_disable)
{
#if defined (GDK_WINDOWING_WIN32)
global_client = egg_sm_client_win32_new ();
#elif defined (GDK_WINDOWING_QUARTZ)
global_client = egg_sm_client_osx_new ();
#else
- /* If both D-Bus and XSMP are compiled in, try D-Bus first
- * and fall back to XSMP if D-Bus session management isn't
- * available.
+ /* If both D-Bus and XSMP are compiled in, try XSMP first
+ * (since it supports state saving) and fall back to D-Bus
+ * if XSMP isn't available.
*/
-# ifdef EGG_SM_CLIENT_BACKEND_DBUS
- global_client = egg_sm_client_dbus_new ();
-# endif
# ifdef EGG_SM_CLIENT_BACKEND_XSMP
+ global_client = egg_sm_client_xsmp_new ();
+# endif
+# ifdef EGG_SM_CLIENT_BACKEND_DBUS
if (!global_client)
- global_client = egg_sm_client_xsmp_new ();
+ global_client = egg_sm_client_dbus_new ();
# endif
#endif
}