Compare commits

..

No commits in common. "3d53b2c131914da48fe8873f4133995bd42dbdcc" and "b8e43c5d5a7f3854b630dc364fa380be7e98aec4" have entirely different histories.

9 changed files with 95 additions and 265 deletions

View File

@ -6,8 +6,8 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: sdtui 0.1.0\n" "Project-Id-Version: sdtui 0.1.0\n"
"Report-Msgid-Bugs-To: https://git.janouch.name/p/sdtui/issues\n" "Report-Msgid-Bugs-To: https://github.com/pjanouch/sdtui/issues\n"
"POT-Creation-Date: 2021-10-11 21:10+0200\n" "POT-Creation-Date: 2016-09-28 16:12+0200\n"
"PO-Revision-Date: 2016-09-28 16:15+0200\n" "PO-Revision-Date: 2016-09-28 16:15+0200\n"
"Last-Translator: Přemysl Eric Janouch <p@janouch.name>\n" "Last-Translator: Přemysl Eric Janouch <p@janouch.name>\n"
"Language-Team: Czech <translation-team-cs@lists.sourceforge.net>\n" "Language-Team: Czech <translation-team-cs@lists.sourceforge.net>\n"
@ -17,137 +17,115 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.8.9\n" "X-Generator: Poedit 1.8.9\n"
#: ../src/sdgtk.c:304 #: ../src/sdtui.c:573
msgid "- StarDict GTK+ UI"
msgstr ""
#: ../src/sdtui.c:726
msgid "Cannot load configuration" msgid "Cannot load configuration"
msgstr "Nemohu načíst konfiguraci" msgstr "Nemohu načíst konfiguraci"
#: ../src/sdtui.c:2497 #: ../src/sdtui.c:1997
msgid "Error" msgid "Error"
msgstr "Chyba" msgstr "Chyba"
#: ../src/sdtui.c:745 #: ../src/sdtui.c:606
msgid "Error loading dictionary" msgid "Error loading dictionary"
msgstr "Chyba při načítání slovníku" msgstr "Chyba při načítání slovníku"
#: ../src/sdgtk.c:299 #: ../src/sdtui.c:612
msgid "FILE..."
msgstr ""
#: ../src/sdgtk.c:355
msgid "Follow selection"
msgstr ""
#: ../src/sdtui.c:750
msgid "" msgid ""
"No dictionaries found either in the configuration or on the command line" "No dictionaries found either in the configuration or on the command line"
msgstr "V konfiguraci ani na příkazové řádce nebyly nalezeny žádné slovníky" msgstr "V konfiguraci ani na příkazové řádce nebyly nalezeny žádné slovníky"
#: ../src/sdtui.c:2476 #: ../src/sdtui.c:1976
msgid "Output version information and exit" msgid "Output version information and exit"
msgstr "Vypíše informace o verzi a ukončí se" msgstr "Vypíše informace o verzi a ukončí se"
#: ../src/sdtui.c:700 #: ../src/sdtui.c:548
msgid "Search" msgid "Search"
msgstr "Hledat" msgstr "Hledat"
#: ../src/sdtui.c:1114 #: ../src/sdtui.c:966
msgid "Terminal UI for StarDict dictionaries" msgid "Terminal UI for StarDict dictionaries"
msgstr "Terminálové UI pro stardictové slovníky" msgstr "Terminálové UI pro stardictové slovníky"
#: ../src/sdtui.c:1117 #: ../src/sdtui.c:969
msgid "Type to search" msgid "Type to search"
msgstr "Zadejte vyhledávaný výraz" msgstr "Zadejte vyhledávaný výraz"
#: ../src/sdgtk.c:289 ../src/sdtui.c:2481 #: ../src/sdtui.c:1981
msgid "Warning" msgid "Warning"
msgstr "Varování" msgstr "Varování"
#: ../src/sdtui.c:2095 #: ../src/sdtui.c:1989
#, c-format
msgid "X11 connection failed (error code %d)"
msgstr ""
#: ../src/sdtui.c:2241
#, c-format
msgid "X11 request error (%d, major %d, minor %d)"
msgstr ""
#: ../src/sdtui.c:2489
msgid "[dictionary.ifo...] - StarDict terminal UI" msgid "[dictionary.ifo...] - StarDict terminal UI"
msgstr "[slovník.ifo...] - terminálové UI pro StarDict" msgstr "[slovník.ifo...] - terminálové UI pro StarDict"
#: ../src/stardict.c:850 #: ../src/stardict.c:835
msgid "cannot find .dict file" msgid "cannot find .dict file"
msgstr "nemohu najít .dict soubor" msgstr "nemohu najít .dict soubor"
#: ../src/stardict.c:827 #: ../src/stardict.c:812
msgid "cannot find .idx file" msgid "cannot find .idx file"
msgstr "nemohu najít .idx soubor" msgstr "nemohu najít .idx soubor"
#: ../src/sdtui.c:320 #: ../src/sdtui.c:283
msgid "error in entry" msgid "error in entry"
msgstr "chyba v záznamu" msgstr "chyba v záznamu"
#: ../src/sdgtk.c:289 ../src/sdtui.c:2481 #: ../src/sdtui.c:1981
msgid "failed to set the locale" msgid "failed to set the locale"
msgstr "selhalo nastavení locale" msgstr "selhalo nastavení locale"
#: ../src/stardict.c:330 #: ../src/stardict.c:308
msgid "index file size not specified" msgid "index file size not specified"
msgstr "nebyla určena velikost rejstříku" msgstr "nebyla určena velikost rejstříku"
#: ../src/stardict.c:1153 ../src/stardict.c:1178 #: ../src/stardict.c:1130 ../src/stardict.c:1155
msgid "invalid data entry" msgid "invalid data entry"
msgstr "neplatná datová položka" msgstr "neplatná datová položka"
#: ../src/stardict.c:281 #: ../src/stardict.c:259
msgid "invalid encoding, must be valid UTF-8" msgid "invalid encoding, must be valid UTF-8"
msgstr "neplatné kódování, musí být validní UTF-8" msgstr "neplatné kódování, musí být validní UTF-8"
#: ../src/stardict.c:89 #: ../src/stardict.c:91
msgid "invalid header format" msgid "invalid header format"
msgstr "neplatný formát hlavičky" msgstr "neplatný formát hlavičky"
#: ../src/stardict.c:339 #: ../src/stardict.c:317
msgid "invalid index offset bits" msgid "invalid index offset bits"
msgstr "neplatný počet bitů pro offset v rejstříku" msgstr "neplatný počet bitů pro offset v rejstříku"
#: ../src/stardict.c:298 #: ../src/stardict.c:276
msgid "invalid integer" msgid "invalid integer"
msgstr "neplatné číslo" msgstr "neplatné číslo"
#: ../src/stardict.c:260 #: ../src/stardict.c:238
msgid "invalid version" msgid "invalid version"
msgstr "neplatná verze" msgstr "neplatná verze"
#: ../src/stardict.c:318 #: ../src/stardict.c:296
msgid "no book name specified" msgid "no book name specified"
msgstr "nebyl určen název knihy" msgstr "nebyl určen název knihy"
#: ../src/sdtui.c:415 #: ../src/sdtui.c:302
msgid "no usable field found" msgid "no usable field found"
msgstr "nenalezeno žádné použitelné pole" msgstr "nenalezeno žádné použitelné pole"
#: ../src/stardict.c:308 #: ../src/stardict.c:286
msgid "option format error" msgid "option format error"
msgstr "chyba v zápisu volby" msgstr "chyba v zápisu volby"
#: ../src/sdtui.c:2497 #: ../src/sdtui.c:1997
msgid "option parsing failed" msgid "option parsing failed"
msgstr "zpracování přepínačů selhalo" msgstr "zpracování přepínačů selhalo"
#: ../src/stardict.c:274 #: ../src/stardict.c:252
msgid "unknown key, ignoring" msgid "unknown key, ignoring"
msgstr "neznámý klíč, ignoruji" msgstr "neznámý klíč, ignoruji"
#: ../src/stardict.c:249 #: ../src/stardict.c:227
msgid "version not specified" msgid "version not specified"
msgstr "nebyla určena verze" msgstr "nebyla určena verze"
#: ../src/stardict.c:324 #: ../src/stardict.c:302
msgid "word count not specified" msgid "word count not specified"
msgstr "nebyl určen počet slov" msgstr "nebyl určen počet slov"

View File

@ -284,7 +284,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
fatal ("Error: option parsing failed: %s\n", error->message); fatal ("Error: option parsing failed: %s\n", error->message);
if (argc != 3) if (argc != 3)
fatal ("%s", g_option_context_get_help (ctx, TRUE, NULL)); fatal ("%s", g_option_context_get_help (ctx, TRUE, FALSE));
g_option_context_free (ctx); g_option_context_free (ctx);

View File

@ -1,14 +1,14 @@
/* /*
* A tool to query multiple dictionaries for the specified word * A tool to query multiple dictionaries for the specified word
* *
* Intended for use in IRC bots and similar silly things---words go in, * Intended for use in IRC bots and similar silly things---words go in, one
* one per each line, and entries come out, one dictionary at a time, * on a line, and entries come out, one dictionary at a time, finalised with
* finalised with an empty line. Newlines are escaped with `\n', * an empty line. Newlines are escaped with `\n', backslashes with `\\'.
* backslashes with `\\'.
* *
* So far only the `m', `g`, and `x` fields are supported, as in sdtui. * So far only the `m' field is supported. Feel free to extend the program
* according to your needs, it's not very complicated.
* *
* Copyright (c) 2013 - 2021, Přemysl Eric Janouch <p@janouch.name> * Copyright (c) 2013, Přemysl Eric Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted. * purpose with or without fee is hereby granted.
@ -30,124 +30,10 @@
#include <glib.h> #include <glib.h>
#include <gio/gio.h> #include <gio/gio.h>
#include <pango/pango.h>
#include "stardict.h" #include "stardict.h"
#include "stardict-private.h" #include "stardict-private.h"
#include "generator.h" #include "generator.h"
#include "utils.h"
// --- Output formatting -------------------------------------------------------
/// Transform Pango attributes to in-line formatting sequences (non-reentrant)
typedef const gchar *(*FormatterFunc) (PangoAttrIterator *);
static const gchar *
pango_attrs_ignore (G_GNUC_UNUSED PangoAttrIterator *iterator)
{
return "";
}
static const gchar *
pango_attrs_to_irc (PangoAttrIterator *iterator)
{
static gchar buf[5];
gchar *p = buf;
*p++ = 0x0f;
if (!iterator)
goto reset_formatting;
PangoAttrInt *attr = NULL;
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_WEIGHT)) && attr->value >= PANGO_WEIGHT_BOLD)
*p++ = 0x02;
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_UNDERLINE)) && attr->value == PANGO_UNDERLINE_SINGLE)
*p++ = 0x1f;
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_STYLE)) && attr->value == PANGO_STYLE_ITALIC)
*p++ = 0x1d;
reset_formatting:
*p++ = 0;
return buf;
}
static const gchar *
pango_attrs_to_ansi (PangoAttrIterator *iterator)
{
static gchar buf[16];
g_strlcpy (buf, "\x1b[0", sizeof buf);
if (!iterator)
goto reset_formatting;
PangoAttrInt *attr = NULL;
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_WEIGHT)) && attr->value >= PANGO_WEIGHT_BOLD)
g_strlcat (buf, ";1", sizeof buf);
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_UNDERLINE)) && attr->value == PANGO_UNDERLINE_SINGLE)
g_strlcat (buf, ";4", sizeof buf);
if ((attr = (PangoAttrInt *) pango_attr_iterator_get (iterator,
PANGO_ATTR_STYLE)) && attr->value == PANGO_STYLE_ITALIC)
g_strlcat (buf, ";3", sizeof buf);
reset_formatting:
g_strlcat (buf, "m", sizeof buf);
return buf;
}
static gchar *
pango_to_output_text (const gchar *markup, FormatterFunc formatter)
{
// This function skips leading whitespace, but it's the canonical one
gchar *text = NULL;
PangoAttrList *attrs = NULL;
if (!pango_parse_markup (markup, -1, 0, &attrs, &text, NULL, NULL))
return g_strdup_printf ("<%s>", ("error in entry"));
PangoAttrIterator *iterator = pango_attr_list_get_iterator (attrs);
GString *result = g_string_new ("");
do
{
gint start = 0, end = 0;
pango_attr_iterator_range (iterator, &start, &end);
if (end == G_MAXINT)
end = strlen (text);
g_string_append (result, formatter (iterator));
g_string_append_len (result, text + start, end - start);
}
while (pango_attr_iterator_next (iterator));
g_string_append (result, formatter (NULL));
g_free (text);
pango_attr_iterator_destroy (iterator);
pango_attr_list_unref (attrs);
return g_string_free (result, FALSE);
}
static gchar *
field_to_output_text (const StardictEntryField *field, FormatterFunc formatter)
{
const gchar *definition = field->data;
if (field->type == STARDICT_FIELD_MEANING)
return g_strdup (definition);
if (field->type == STARDICT_FIELD_PANGO)
return pango_to_output_text (definition, formatter);
if (field->type == STARDICT_FIELD_XDXF)
{
gchar *markup = xdxf_to_pango_markup_with_reduced_effort (definition);
gchar *result = pango_to_output_text (markup, formatter);
g_free (markup);
return result;
}
return NULL;
}
// --- Main --------------------------------------------------------------------
static guint static guint
count_equal_chars (const gchar *a, const gchar *b) count_equal_chars (const gchar *a, const gchar *b)
@ -160,16 +46,15 @@ count_equal_chars (const gchar *a, const gchar *b)
} }
static void static void
do_dictionary (StardictDict *dict, const gchar *word, FormatterFunc formatter) do_dictionary (StardictDict *dict, const gchar *word)
{ {
gboolean found; gboolean found;
StardictIterator *iter = stardict_dict_search (dict, word, &found); StardictIterator *iter = stardict_dict_search (dict, word, &found);
if (!found) if (!found)
goto out; goto out;
// Default Stardict ordering is ASCII case-insensitive, // Default Stardict ordering is ASCII case-insensitive.
// which may be further exacerbated by our own collation feature. // Try to find a better matching entry based on letter case:
// Try to find a better matching entry:
gint64 best_offset = stardict_iterator_get_offset (iter); gint64 best_offset = stardict_iterator_get_offset (iter);
guint best_score = count_equal_chars guint best_score = count_equal_chars
@ -201,67 +86,27 @@ do_dictionary (StardictDict *dict, const gchar *word, FormatterFunc formatter)
for (; list; list = list->next) for (; list; list = list->next)
{ {
StardictEntryField *field = list->data; StardictEntryField *field = list->data;
gchar *definitions = field_to_output_text (field, formatter); if (field->type == STARDICT_FIELD_MEANING)
if (!definitions)
continue;
printf ("%s\t", info->book_name);
for (const gchar *p = definitions; *p; p++)
{ {
if (*p == '\\') const gchar *desc = field->data;
printf ("\\\\"); printf ("%s:", info->book_name);
else if (*p == '\n') for (; *desc; desc++)
printf ("\\n"); {
else if (*desc == '\\')
putchar (*p); printf ("\\\\");
else if (*desc == '\n')
printf ("\\n");
else
putchar (*desc);
}
putchar ('\n');
} }
putchar ('\n');
g_free (definitions);
} }
g_object_unref (entry); g_object_unref (entry);
out: out:
g_object_unref (iter); g_object_unref (iter);
} }
static FormatterFunc
parse_options (int *argc, char ***argv)
{
GError *error = NULL;
GOptionContext *ctx = g_option_context_new
("DICTIONARY.ifo... - query multiple dictionaries");
gboolean format_with_ansi = FALSE;
gboolean format_with_irc = FALSE;
GOptionEntry entries[] =
{
{ "ansi", 'a', 0, G_OPTION_ARG_NONE, &format_with_ansi,
"Format with ANSI sequences", NULL },
{ "irc", 'i', 0, G_OPTION_ARG_NONE, &format_with_irc,
"Format with IRC codes", NULL },
{ }
};
g_option_context_add_main_entries (ctx, entries, NULL);
if (!g_option_context_parse (ctx, argc, argv, &error))
{
g_printerr ("Error: option parsing failed: %s\n", error->message);
exit (EXIT_FAILURE);
}
if (*argc < 2)
{
g_printerr ("%s\n", g_option_context_get_help (ctx, TRUE, NULL));
exit (EXIT_FAILURE);
}
g_option_context_free (ctx);
if (format_with_ansi)
return pango_attrs_to_ansi;
if (format_with_irc)
return pango_attrs_to_irc;
return pango_attrs_ignore;
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -270,7 +115,21 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
g_type_init (); g_type_init ();
G_GNUC_END_IGNORE_DEPRECATIONS G_GNUC_END_IGNORE_DEPRECATIONS
FormatterFunc formatter = parse_options (&argc, &argv); GError *error = NULL;
GOptionContext *ctx = g_option_context_new
("DICTIONARY.ifo... - query multiple dictionaries");
if (!g_option_context_parse (ctx, &argc, &argv, &error))
{
g_printerr ("Error: option parsing failed: %s\n", error->message);
exit (EXIT_FAILURE);
}
g_option_context_free (ctx);
if (argc < 2)
{
g_printerr ("Error: no dictionaries given\n");
exit (EXIT_FAILURE);
}
guint n_dicts = argc - 1; guint n_dicts = argc - 1;
StardictDict **dicts = g_alloca (sizeof *dicts * n_dicts); StardictDict **dicts = g_alloca (sizeof *dicts * n_dicts);
@ -278,7 +137,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
guint i; guint i;
for (i = 1; i <= n_dicts; i++) for (i = 1; i <= n_dicts; i++)
{ {
GError *error = NULL;
dicts[i - 1] = stardict_dict_new (argv[i], &error); dicts[i - 1] = stardict_dict_new (argv[i], &error);
if (error) if (error)
{ {
@ -288,23 +146,26 @@ G_GNUC_END_IGNORE_DEPRECATIONS
} }
} }
gint c; while (TRUE)
do
{ {
GString *s = g_string_new (NULL); GString *s = g_string_new (NULL);
gint c;
while ((c = getchar ()) != EOF && c != '\n') while ((c = getchar ()) != EOF && c != '\n')
if (c != '\r') if (c != '\r')
g_string_append_c (s, c); g_string_append_c (s, c);
if (s->len) if (s->len)
for (i = 0; i < n_dicts; i++) for (i = 0; i < n_dicts; i++)
do_dictionary (dicts[i], s->str, formatter); do_dictionary (dicts[i], s->str);
printf ("\n"); printf ("\n");
fflush (NULL); fflush (NULL);
g_string_free (s, TRUE); g_string_free (s, TRUE);
if (c == EOF)
break;
} }
while (c != EOF);
for (i = 0; i < n_dicts; i++) for (i = 0; i < n_dicts; i++)
g_object_unref (dicts[i]); g_object_unref (dicts[i]);

View File

@ -348,9 +348,23 @@ view_entry_split_add_pango (ViewEntry *ve, const gchar *markup)
static void static void
view_entry_split_add_xdxf (ViewEntry *ve, const gchar *xml) view_entry_split_add_xdxf (ViewEntry *ve, const gchar *xml)
{ {
gchar *markup = xdxf_to_pango_markup_with_reduced_effort (xml); // Trivially filter out all tags we can't quite handle,
view_entry_split_add_pango (ve, markup); // then parse the reduced XML as Pango markup--this seems to work well.
g_free (markup); // Given the nature of our display, also skip keyword elements.
GString *filtered = g_string_new ("");
while (*xml)
{
// GMarkup can read some of the wilder XML constructs, Pango skips them
const gchar *p = NULL;
if (*xml != '<' || xml[1] == '!' || xml[1] == '?'
|| g_ascii_isspace (xml[1]) || !*(p = xml + 1 + (xml[1] == '/'))
|| (strchr ("biu", *p) && p[1] == '>') || !(p = strchr (p, '>')))
g_string_append_c (filtered, *xml++);
else if (xml[1] != 'k' || xml[2] != '>' || !(xml = strstr (p, "</k>")))
xml = ++p;
}
view_entry_split_add_pango (ve, filtered->str);
g_string_free (filtered, TRUE);
} }
/// Decomposes a dictionary entry into the format we want. /// Decomposes a dictionary entry into the format we want.

View File

@ -1354,7 +1354,7 @@ stardict_iterator_get_entry (StardictIterator *sdi)
{ {
g_return_val_if_fail (STARDICT_IS_ITERATOR (sdi), NULL); g_return_val_if_fail (STARDICT_IS_ITERATOR (sdi), NULL);
if (!stardict_iterator_is_valid (sdi)) if (!stardict_iterator_is_valid (sdi))
return NULL; return FALSE;
return stardict_dict_get_entry (sdi->owner, sdi->offset); return stardict_dict_get_entry (sdi->owner, sdi->offset);
} }

View File

@ -179,7 +179,7 @@ main (int argc, char *argv[])
if (!g_option_context_parse (ctx, &argc, &argv, &error)) if (!g_option_context_parse (ctx, &argc, &argv, &error))
fatal ("Error: option parsing failed: %s\n", error->message); fatal ("Error: option parsing failed: %s\n", error->message);
if (argc != 2) if (argc != 2)
fatal ("%s", g_option_context_get_help (ctx, TRUE, NULL)); fatal ("%s", g_option_context_get_help (ctx, TRUE, FALSE));
g_option_context_free (ctx); g_option_context_free (ctx);
template.version = SD_VERSION_3_0_0; template.version = SD_VERSION_3_0_0;

View File

@ -155,7 +155,7 @@ main (int argc, char *argv[])
fatal ("Error: option parsing failed: %s\n", error->message); fatal ("Error: option parsing failed: %s\n", error->message);
if (argc < 3) if (argc < 3)
fatal ("%s", g_option_context_get_help (ctx, TRUE, NULL)); fatal ("%s", g_option_context_get_help (ctx, TRUE, FALSE));
// GLib is bullshit, getopt_long() always correctly removes this // GLib is bullshit, getopt_long() always correctly removes this
gint program_argv_start = 3; gint program_argv_start = 3;

View File

@ -33,27 +33,6 @@
#include "utils.h" #include "utils.h"
/// Trivially filter out all tags that aren't part of the Pango markup language,
/// or no frontend can quite handle--this seems to work well.
/// Given the nature of our display, also skip whole keyword elements.
gchar *
xdxf_to_pango_markup_with_reduced_effort (const gchar *xml)
{
GString *filtered = g_string_new ("");
while (*xml)
{
// GMarkup can read some of the wilder XML constructs, Pango skips them
const gchar *p = NULL;
if (*xml != '<' || xml[1] == '!' || xml[1] == '?'
|| g_ascii_isspace (xml[1]) || !*(p = xml + 1 + (xml[1] == '/'))
|| (strchr ("biu", *p) && p[1] == '>') || !(p = strchr (p, '>')))
g_string_append_c (filtered, *xml++);
else if (xml[1] != 'k' || xml[2] != '>' || !(xml = strstr (p, "</k>")))
xml = ++p;
}
return g_string_free (filtered, FALSE);
}
/// Read the whole stream into a byte array. /// Read the whole stream into a byte array.
gboolean gboolean
stream_read_all (GByteArray *ba, GInputStream *is, GError **error) stream_read_all (GByteArray *ba, GInputStream *is, GError **error)

View File

@ -36,8 +36,6 @@
} \ } \
} }
gchar *xdxf_to_pango_markup_with_reduced_effort (const gchar *xml);
gboolean stream_read_all (GByteArray *ba, GInputStream *is, GError **error); gboolean stream_read_all (GByteArray *ba, GInputStream *is, GError **error);
gchar *stream_read_string (GDataInputStream *dis, GError **error); gchar *stream_read_string (GDataInputStream *dis, GError **error);
gboolean xstrtoul (unsigned long *out, const char *s, int base); gboolean xstrtoul (unsigned long *out, const char *s, int base);