ifdef MINGW
ifneq ($(ENABLE_NLS),0)
- INTL_LIBS := -lintl
+ INTL_LIBS := -lintl -liconv
endif
OGL_LIBS := -lopengl32 -lm
BASE_LIBS := -lSDL -lSDL_image $(INTL_LIBS)
share/binary.o \
share/state.o \
share/audio.o \
+ share/text.o \
ball/hud.o \
ball/mode.o \
ball/game.o \
share/audio.o \
share/state.o \
share/gui.o \
+ share/text.o \
putt/hud.o \
putt/game.o \
putt/hole.o \
#include "solid.h"
#include "config.h"
#include "binary.h"
+#include "text.h"
/*---------------------------------------------------------------------------*/
#define MAGIC 0x52424EAF
-#define DEMO_VERSION 3
+#define DEMO_VERSION 4
#define DATELEN 20
get_index(fp, &d->status);
get_index(fp, &d->mode);
- fread(d->player, 1, MAXNAM, fp);
+ get_string(fp, d->player, MAXNAM);
- fread(datestr, 1, DATELEN, fp);
+ get_string(fp, datestr, DATELEN);
sscanf(datestr,
"%d-%d-%dT%d:%d:%d",
&date.tm_year,
d->date = make_time_from_utc(&date);
- fread(d->shot, 1, PATHMAX, fp);
- fread(d->file, 1, PATHMAX, fp);
+ get_string(fp, d->shot, PATHMAX);
+ get_string(fp, d->file, PATHMAX);
get_index(fp, &d->time);
get_index(fp, &d->goal);
put_index(fp, &zero);
put_index(fp, &d->mode);
- fwrite(d->player, 1, MAXNAM, fp);
- fwrite(datestr, 1, DATELEN, fp);
+ put_string(fp, d->player);
+ put_string(fp, datestr);
- fwrite(d->shot, 1, PATHMAX, fp);
- fwrite(d->file, 1, PATHMAX, fp);
+ put_string(fp, d->shot);
+ put_string(fp, d->file);
put_index(fp, &d->time);
put_index(fp, &d->goal);
{
if (demo_header_read(fp, d))
{
- strncpy(d->filename, config_user(filename), MAXSTR);
- strncpy(d->name, bname(filename, REPLAY_EXT), PATHMAX);
+ strncpy(d->filename, config_user(filename), MAXSTR);
+ strncpy(d->name, bname(text_from_locale(d->filename), REPLAY_EXT),
+ PATHMAX);
d->name[PATHMAX - 1] = '\0';
count++;
const char *date_to_str(time_t i)
{
static char str[MAXSTR];
+ const char *fmt;
/* TRANSLATORS: here is the format of the date shown at the
- replay selection screen. The default will work in most cases, so
- you should only change it if something's horribly wrong, like,
- for instance, the GUI layout is broken. See strftime(3) for
+ replay selection screen (and possibly elsewhere). The default
+ format is necessarily locale-independent. See strftime(3) for
details on the format.
*/
- strftime(str, MAXSTR, /* xgettext:no-c-format */ _("%c"), localtime(&i));
-
- return str;
+ fmt = /* xgettext:no-c-format */ L_("%Y-%m-%d %H:%M:%S");
+ strftime(str, MAXSTR, fmt, localtime(&i));
+ return text_from_locale(str);
}
/*---------------------------------------------------------------------------*/
if (demo_fp && demo_header_read(demo_fp, &demo_replay))
{
- strncpy(demo_replay.filename, name, MAXSTR);
- strncpy(demo_replay.name, bname(name, REPLAY_EXT), PATHMAX);
+ strncpy(demo_replay.filename, name, MAXSTR);
+ strncpy(demo_replay.name, bname(text_from_locale(demo_replay.filename),
+ REPLAY_EXT), PATHMAX);
if (!demo_load_level(&demo_replay, &demo_level_replay))
return 0;
#include "config.h"
#include "demo.h"
+#include "text.h"
#include "level.h"
#include "mode.h"
#include "set.h"
memset(level, 0, sizeof (struct level));
memset(&sol, 0, sizeof (sol));
+#define format \
+ L_("Error while loading level file '%s': %s\n")
+#define default_error \
+ L_("Not a valid level file")
+
if (!sol_load_only_head(&sol, config_data(filename)))
{
- fprintf(stderr,
- _("Error while loading level file '%s': %s\n"), filename,
- errno ? strerror(errno) : _("Not a valid level file"));
+ const char *error = errno ? strerror(errno) : default_error;
+ fprintf(stderr, format, filename, error);
return 0;
}
+#undef format
+#undef default_error
+
strcpy(level->file, filename);
/* Init hs with default values */
#include "game.h"
#include "gui.h"
#include "set.h"
+#include "text.h"
#include "st_conf.h"
#include "st_title.h"
static unsigned int display_info = 0;
static unsigned int replay_demo = 0;
+#define usage \
+ L_( \
+ "Usage: %s [options ...]\n" \
+ "Options:\n" \
+ " -h, --help show this usage message.\n" \
+ " -v, --version show version.\n" \
+ " -d, --data <dir> use 'dir' as game data directory.\n" \
+ " -r, --replay <file> play the replay 'file'.\n" \
+ " -i, --info display info about a replay.\n" \
+ )
+
#define argument_error(option) { \
- fprintf(stderr, _("Option '%s' requires an argument.\n"), option); \
+ fprintf(stderr, L_("Option '%s' requires an argument.\n"), option); \
}
static void parse_args(int argc, char **argv)
{
int i;
- const char *usage = _(
- "Usage: %s [options ...]\n"
- "Options:\n"
- " -h, --help show this usage message.\n"
- " -v, --version show version.\n"
- " -d, --data <dir> use 'dir' as game data directory.\n"
- " -r, --replay <file> play the replay 'file'.\n"
- " -i, --info display info about a replay.\n"
- );
-
/* Scan argument list. */
for (i = 1; i < argc; i++)
if (display_info)
{
/* FIXME, I'm a required option. */
- fputs(_("Option '--info' requires '--replay'.\n"), stderr);
+ fputs(L_("Option '--info' requires '--replay'.\n"), stderr);
exit(EXIT_FAILURE);
}
}
+#undef usage
#undef argument_error
/*---------------------------------------------------------------------------*/
lang_init("neverball", CONFIG_LOCALE);
+ text_init();
+
parse_args(argc, argv);
if (!config_data_path(data_path, SET_FILE))
{
- fprintf(stderr, _("Failure to establish game data directory\n"));
+ fputs(L_("Failure to establish game data directory\n"), stderr);
return 1;
}
if (!config_user_path(NULL))
{
- fprintf(stderr, _("Failure to establish config directory\n"));
+ fputs(L_("Failure to establish config directory\n"), stderr);
return 1;
}
{
if (!level_replay(demo_path))
{
- fprintf(stderr, _("Replay file '%s': %s\n"), demo_path,
- errno ? strerror(errno) : _("Not a replay file"));
+ fprintf(stderr, L_("Replay file '%s': %s\n"), demo_path,
+ errno ? strerror(errno) : L_("Not a replay file"));
return 1;
}
demo_replay_dump_info();
config_save();
+ text_quit();
+
return 0;
}
#include "glext.h"
#include "config.h"
#include "image.h"
+#include "text.h"
#include "set.h"
#include "game.h"
if (!res && errno != ENOENT)
{
fprintf(stderr,
- _("Error while loading user high-score file '%s': %s\n"),
- fn, errno ? strerror(errno) : _("Incorrect format"));
+ L_("Error while loading user high-score file '%s': %s\n"),
+ fn, errno ? strerror(errno) : L_("Incorrect format"));
}
}
if (!fin)
{
- fprintf(stderr, _("Cannot load the set file '%s': %s\n"),
+ fprintf(stderr, L_("Cannot load the set file '%s': %s\n"),
filename, strerror(errno));
return 0;
}
#include "audio.h"
#include "config.h"
#include "game.h"
+#include "text.h"
#include "st_name.h"
#include "st_shared.h"
static int name_action(int i)
{
- size_t l = strlen(player);
-
audio_play(AUD_MENU, 1.0f);
switch (i)
{
case NAME_OK:
- if (l == 0)
+ if (strlen(player) == 0)
return 1;
config_set_s(CONFIG_PLAYER, player);
break;
case GUI_BS:
- if (l > 0)
- {
- player[l - 1] = '\0';
+ if (text_del_char(player))
gui_set_label(name_id, player);
- }
break;
default:
- if (l < MAXNAM - 1)
- {
- player[l + 0] = (char) i;
- player[l + 1] = '\0';
-
+ if (text_add_char(i, player, MAXNAM, 17))
gui_set_label(name_id, player);
- }
}
return 1;
}
static int name_keybd(int c, int d)
{
- if (d && (c & 0xFF80) == 0)
+ if (d)
{
gui_focus(enter_id);
#include "config.h"
#include "demo.h"
#include "levels.h"
+#include "text.h"
#include "st_shared.h"
#include "st_save.h"
static int save_action(int i)
{
- size_t l = strlen(filename);
+ char *n;
audio_play(AUD_MENU, 1.0f);
switch (i)
{
case SAVE_SAVE:
- if (strlen(filename) == 0)
+ n = text_to_locale(filename);
+
+ if (strlen(n) == 0)
return 1;
- if (demo_exists(filename))
+ if (demo_exists(n))
return goto_state(&st_clobber);
else
{
- demo_rename(filename);
+ demo_rename(n);
return goto_state(ok_state);
}
break;
case GUI_BS:
- if (l > 0)
- {
- filename[l - 1] = 0;
+ if (text_del_char(filename))
gui_set_label(file_id, filename);
- }
break;
default:
- if (l < MAXNAM - 1)
- {
- filename[l + 0] = (char) i;
- filename[l + 1] = 0;
+ if (text_add_char(i, filename, MAXNAM, 17))
gui_set_label(file_id, filename);
- }
}
return 1;
}
static int save_keybd(int c, int d)
{
- if (d && (c & 0xFF80) == 0)
+ if (d)
{
gui_focus(enter_id);
if (i == SAVE_SAVE)
{
- demo_rename(filename);
+ demo_rename(text_to_locale(filename));
return goto_state(ok_state);
}
return goto_state(&st_save);
- Menu navigation improvements
- Neverputt joystick and keyboard support
- New pause screen
+ - I18n improvements
- Various bug fixes
Jeremy Messenger
- FreeBSD port
XGETTEXT := xgettext
XGETTEXT_FLAGS := \
--add-comments=TRANSLATORS --from-code=UTF-8 \
- --keyword=_ --keyword=N_ --keyword=sgettext \
+ --keyword=_ --keyword=N_ --keyword=L_ \
+ --keyword=sgettext \
--default-domain="$(DOMAIN)" \
--copyright-holder="$(COPYRIGHT)" \
--msgid-bugs-address="$(BUGADDR)"
#include "hole.h"
#include "game.h"
#include "gui.h"
+#include "text.h"
#include "st_conf.h"
#include "st_all.h"
}
else fprintf(stderr, "%s: %s\n", argv[0], SDL_GetError());
}
- else fprintf(stderr, _("Failure to establish config directory\n"));
+ else fprintf(stderr, L_("Failure to establish config directory\n"));
}
- else fprintf(stderr, _("Failure to establish game data directory\n"));
+ else fprintf(stderr, L_("Failure to establish game data directory\n"));
return 0;
}
#include <SDL_mixer.h>
#include <string.h>
+#include "text.h"
#include "config.h"
#include "audio.h"
}
else
{
- fprintf(stderr, _("Sound disabled\n"));
+ fprintf(stderr, L_("Sound disabled\n"));
audio_state = 0;
}
}
}
/*---------------------------------------------------------------------------*/
+
+void put_string(FILE *fout, const char *s)
+{
+ fputs(s, fout);
+ fputc('\0', fout);
+}
+
+void get_string(FILE *fin, char *s, int max)
+{
+ do
+ *s = (char) fgetc(fin);
+ while (*s++ != '\0' && max-- > 0);
+
+ if(*(s - 1) != '\0')
+ *(s - 1) = '\0';
+}
+
+/*---------------------------------------------------------------------------*/
void get_index(FILE *, int *);
void get_array(FILE *, float *, size_t);
+void put_string(FILE *fout, const char *);
+void get_string(FILE *fin, char *, int );
+
/*---------------------------------------------------------------------------*/
#endif
#include "glext.h"
#include "image.h"
#include "vec3.h"
+#include "text.h"
#include "gui.h"
/*---------------------------------------------------------------------------*/
return id;
}
- fprintf(stderr, _("Out of widget IDs\n"));
+ fprintf(stderr, "Out of widget IDs\n");
return 0;
}
*/
#include <string.h>
-#include <stdlib.h>
#include <locale.h>
+#include <stdlib.h>
+#include <stdio.h>
#include "lang.h"
+#include "text.h"
/*---------------------------------------------------------------------------*/
return msgval;
}
+const char *get_local_text(const char *msgid)
+{
+#if ENABLE_NLS
+ return text_to_locale(gettext(msgid));
+#else
+ return msgid;
+#endif
+}
+
/*---------------------------------------------------------------------------*/
#if ENABLE_NLS
#include <libintl.h>
+
#define _(String) gettext(String)
+#define L_(String) get_local_text(String)
+
#else
+
#define _(String) (String)
-#endif
+#define L_(String) (String)
+
+#endif /* ENABLE_NLS */
/* No-op, useful for marking up strings for extraction-only. */
#define N_(String) (String)
void lang_init(const char *domain, const char *locale_dir);
const char *sgettext(const char *);
+const char *get_local_text(const char *);
/*---------------------------------------------------------------------------*/
--- /dev/null
+/*
+ * Copyright (C) 2003 Robert Kooima
+ *
+ * NEVERBALL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#if ENABLE_NLS
+#include <iconv.h>
+#endif
+
+#include "text.h"
+
+/*---------------------------------------------------------------------------*/
+
+#define MAXSTR 256
+
+/*---------------------------------------------------------------------------*/
+
+#if ENABLE_NLS
+static iconv_t conv_from_locale = 0;
+static iconv_t conv_to_locale = 0;
+#endif
+
+void text_init(void)
+{
+#if ENABLE_NLS
+ if ((conv_from_locale = iconv_open("UTF-8", "")) == (iconv_t) -1)
+ fprintf(stderr, "Error: %s\n", strerror(errno));
+
+ if ((conv_to_locale = iconv_open("", "UTF-8")) == (iconv_t) -1)
+ fprintf(stderr, "Error: %s\n", strerror(errno));
+#else
+ return;
+#endif
+}
+
+void text_quit(void)
+{
+#if ENABLE_NLS
+ if (conv_from_locale != (iconv_t) -1)
+ iconv_close(conv_from_locale);
+
+ if (conv_to_locale != (iconv_t) -1)
+ iconv_close(conv_to_locale);
+#else
+ return;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+
+char *text_from_locale(char *str0)
+{
+#if ENABLE_NLS
+ static char buffer[MAXSTR * 2];
+
+ char *str0p = str0;
+ char *str1p = buffer;
+
+ size_t l0 = strlen(str0);
+ size_t l1 = sizeof (buffer);
+
+ if (conv_from_locale == (iconv_t) -1)
+ return str0;
+
+ if (iconv(conv_from_locale, &str0p, &l0, &str1p, &l1) == (size_t) -1)
+ fprintf(stderr, "Error while converting to UTF-8: %s\n",
+ strerror(errno));
+
+ *str1p = '\0';
+
+ return buffer;
+#else
+ return str0;
+#endif
+}
+
+char *text_to_locale(char *str0)
+{
+#if ENABLE_NLS
+ static char buffer[MAXSTR * 2];
+
+ char *str0p = str0;
+ char *str1p = buffer;
+
+ size_t l0 = strlen(str0);
+ size_t l1 = sizeof (buffer);
+
+ if (conv_to_locale == (iconv_t) -1)
+ return str0;
+
+ if (iconv(conv_to_locale, &str0p, &l0, &str1p, &l1) == (size_t) -1)
+ fprintf(stderr, "Error while converting from UTF-8: %s\n",
+ strerror(errno));
+
+ *str1p = '\0';
+
+ return buffer;
+#else
+ return str0;
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+
+int text_add_char(Uint32 unicode, char *string, int maxbytes, int maxchars)
+{
+ size_t pos = strlen(string);
+ int l;
+
+ if (unicode < 0x80) l = 1;
+ else if (unicode < 0x0800) l = 2;
+ else if (unicode < 0x10000) l = 3;
+ else l = 4;
+
+ if ((pos + l >= maxbytes) || (text_length(string) + 1 >= maxchars))
+ return 0;
+
+ if (unicode < 0x80)
+ string[pos++] = (char) unicode;
+ else if (unicode < 0x0800)
+ {
+ string[pos++] = (char) ((unicode >> 6) | 0xC0);
+ string[pos++] = (char) ((unicode & 0x3F) | 0x80);
+ }
+ else if (unicode < 0x10000)
+ {
+ string[pos++] = (char) ((unicode >> 12) | 0xE0);
+ string[pos++] = (char) (((unicode >> 6) & 0x3F) | 0x80);
+ string[pos++] = (char) ((unicode & 0x3F) | 0x80);
+ }
+ else
+ {
+ string[pos++] = (char) ((unicode >> 18) | 0xF0);
+ string[pos++] = (char) (((unicode >> 12) & 0x3F) | 0x80);
+ string[pos++] = (char) (((unicode >> 6) & 0x3F) | 0x80);
+ string[pos++] = (char) ((unicode & 0x3F) | 0x80);
+ }
+
+ string[pos++] = 0;
+
+ return l;
+}
+
+int text_del_char(char *string)
+{
+ size_t pos = strlen(string) - 1;
+
+ while (pos >= 0 && ((string[pos] & 0xC0) == 0x80))
+ string[pos--] = 0;
+
+ if (pos >= 0)
+ {
+ string[pos] = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int text_length(const char *string)
+{
+ int result = 0;
+
+ while (*string != '\0')
+ if ((*string++ & 0xC0) != 0x80)
+ result++;
+
+ return result;
+}
+
+/*---------------------------------------------------------------------------*/
--- /dev/null
+#ifndef TEXT_H
+#define TEXT_H
+
+#include <SDL.h>
+
+/*---------------------------------------------------------------------------*/
+
+void text_init(void);
+
+char *text_from_locale(char *);
+char *text_to_locale(char *);
+
+int text_add_char(Uint32, char *, int, int);
+int text_del_char(char *);
+int text_length(const char *);
+
+void text_quit(void);
+
+/*---------------------------------------------------------------------------*/
+
+#endif
* democonv
- A bare-bones Neverball 1.4.0 to v3 (Neverball 1.5.0) format replay
+ A bare-bones Neverball 1.4.0 to v4 (Neverball 1.5.0) format replay
converter. Reads a replay from standard input and writes a
converted replay to standard output. See below for examples.
/*
- * democonv -- Neverball 1.4.0 to v3 format replay converter.
+ * democonv -- Neverball 1.4.0 to v4 format replay converter.
*
* Copyright (C) 2006 Jānis Rūcis
*
#define MAG_OLD 0x4E425250
#define MAG_NEW 0x52424EAF
-#define VER_NEW 3
+#define VER_NEW 4
/*---------------------------------------------------------------------------*/
*goal = (int) sg;
*score = (int) ss;
*balls = (int) sb;
-
+
return 1;
}
return 0;
put_index(fout, &state);
put_index(fout, &mode);
- fwrite(player, 1, MAXNAM, fout);
- fwrite(date, 1, DATELEN, fout);
+ put_string(fout, player);
+ put_string(fout, date);
- fwrite(shot, 1, PATHMAX, fout);
- fwrite(file, 1, PATHMAX, fout);
+ put_string(fout, shot);
+ put_string(fout, file);
put_index(fout, &time);
put_index(fout, &goal);