Merge commit 'origin/master' into charset
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 1 Apr 2009 01:58:49 +0000 (09:58 +0800)
committerJohn Darrington <john@darrington.wattle.id.au>
Wed, 1 Apr 2009 01:58:49 +0000 (09:58 +0800)
36 files changed:
doc/dev/system-file-format.texi
doc/utilities.texi
src/data/dictionary.c
src/data/dictionary.h
src/data/gnumeric-reader.c
src/data/identifier.c
src/data/psql-reader.c
src/data/settings.c
src/data/sys-file-reader.c
src/data/sys-file-writer.c
src/language/dictionary/sys-file-info.c
src/language/utilities/set.q
src/libpspp/i18n.c
src/libpspp/i18n.h
src/ui/gui/compute-dialog.c
src/ui/gui/dialog-common.c
src/ui/gui/dict-display.c
src/ui/gui/helper.c
src/ui/gui/helper.h
src/ui/gui/main.c
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-store.c
src/ui/gui/psppire-dict.c
src/ui/gui/psppire-dict.h
src/ui/gui/psppire-dictview.c
src/ui/gui/psppire-var-sheet.c
src/ui/gui/psppire-var-store.c
src/ui/gui/psppire.c
src/ui/gui/val-labs-dialog.c
src/ui/gui/val-labs-dialog.h
src/ui/gui/var-display.c
src/ui/gui/var-display.h
src/ui/gui/variable-info-dialog.c
src/ui/terminal/main.c
tests/command/sysfile-info.sh
tests/dissect-sysfile.c

index 3e764c8ce714099f1becf877c927681911b23a54..164807b80115e4796bb394c0336522b0d84344ba 100644 (file)
@@ -96,6 +96,7 @@ Each type of record is described separately below.
 * Variable Display Parameter Record::
 * Long Variable Names Record::
 * Very Long String Record::
+* Character Encoding Record::
 * Data File and Variable Attributes Records::
 * Miscellaneous Informational Records::
 * Dictionary Termination Record::
@@ -546,9 +547,14 @@ Compression code.  Always set to 1.
 Machine endianness.  1 indicates big-endian, 2 indicates little-endian.
 
 @item int32 character_code;
+@anchor{character-code}
 Character code.  1 indicates EBCDIC, 2 indicates 7-bit ASCII, 3
 indicates 8-bit ASCII, 4 indicates DEC Kanji.
 Windows code page numbers are also valid.
+
+Experience has shown that in many files, this field is ignored or incorrect.
+For a more reliable indication of the file's character encoding
+see @ref{Character Encoding Record}.
 @end table
 
 @node Machine Floating-Point Info Record
@@ -792,6 +798,46 @@ After the last tuple, there may be a single byte 00, or @{00, 09@}.
 The total length is @code{count} bytes.
 @end table
 
+@node Character Encoding Record
+@section Character Encoding Record
+
+This record, if present, indicates the character encoding for string data,
+long variable names, variable labels, value labels and other strings in the
+file.
+
+@example
+/* @r{Header.} */
+int32               rec_type;
+int32               subtype;
+int32               size;
+int32               count;
+
+/* @r{Exactly @code{count} bytes of data.} */
+char                encoding[];
+@end example
+
+@table @code
+@item int32 rec_type;
+Record type.  Always set to 7.
+
+@item int32 subtype;
+Record subtype.  Always set to 20.
+
+@item int32 size;
+The size of each element in the @code{encoding} member. Always set to 1.
+
+@item int32 count;
+The total number of bytes in @code{encoding}.
+
+@item char encoding[];
+The name of the character encoding.  Normally this will be an official IANA characterset name or alias.
+See @url{http://www.iana.org/assignments/character-sets}.
+@end table
+
+This record is not present in files generated by older software.
+See also @ref{character-code}.
+
+
 @node Data File and Variable Attributes Records
 @section Data File and Variable Attributes Records
 
index 95cfa25dd89d472c615461f51f4eabb1aa0299dc..6882aa2165f525aa2b12ae466da5d762eabe95af 100644 (file)
@@ -374,8 +374,10 @@ SET
         /COMPRESSION=@{ON,OFF@}
         /SCOMPRESSION=@{ON,OFF@}
 
-(security)
+(miscellaneous)
         /SAFER=ON
+        /LOCALE='string'
+
 
 (obsolete settings accepted for compatibility, but ignored)
         /BOXSTRING=@{'xxx','xxxxxxxxxxx'@}
@@ -701,6 +703,37 @@ Be aware that this setting does not guarantee safety (commands can still
 overwrite files, for instance) but it is an improvement.
 When set, this setting cannot be reset during the same session, for
 obvious security reasons.
+
+@item LOCALE
+@cindex locale
+@cindex encoding, characters
+This item is used to set the default character encoding.
+The encoding may be specified either as an encoding name or alias
+(see @url{http://www.iana.org/assignments/character-sets}), or
+as a locale name.
+If given as a locale name, only the character encoding of the 
+locale is relevant.
+
+System files written by PSPP will use this encoding.
+System files read by PSPP, for which the encoding is unknown, will be
+interpreted using this encoding.
+
+The full list of valid encodings and locale names/alias are operating system
+dependent.
+The following are all examples of acceptable syntax on common GNU/Linux
+systems.
+@example
+
+SET LOCALE='iso-8859-1'.
+
+SET LOCALE='ru_RU.cp1251'.
+
+SET LOCALE='japanese'.
+
+@end example
+
+Contrary to the intuition, this command does not affect any aspect 
+of the system's locale.
 @end table
 
 @node SHOW
index ba840898112494b775d02c810edee29c98037fee..b5b6cca58f19bbf1732eae911379f0d4606caf3f 100644 (file)
@@ -63,6 +63,9 @@ struct dictionary
     struct vector **vector;     /* Vectors of variables. */
     size_t vector_cnt;          /* Number of vectors. */
     struct attrset attributes;  /* Custom attributes. */
+
+    char *encoding;             /* Character encoding of string data */
+
     const struct dict_callbacks *callbacks; /* Callbacks on dictionary
                                               modification */
     void *cb_data ;                  /* Data passed to callbacks */
@@ -71,6 +74,21 @@ struct dictionary
     void *changed_data;
   };
 
+
+void
+dict_set_encoding (struct dictionary *d, const char *enc)
+{
+  if (enc)
+    d->encoding = strdup (enc);
+}
+
+const char *
+dict_get_encoding (const struct dictionary *d)
+{
+  return d->encoding ;
+}
+
+
 void
 dict_set_change_callback (struct dictionary *d,
                          void (*changed) (struct dictionary *, void*),
@@ -194,6 +212,9 @@ dict_clone (const struct dictionary *s)
   for (i = 0; i < s->vector_cnt; i++)
     d->vector[i] = vector_clone (s->vector[i], s, d);
 
+  if ( s->encoding)
+    d->encoding = strdup (s->encoding);
+
   dict_set_attributes (d, dict_get_attributes (s));
 
   return d;
index 18bf3f781081a14fc23fe2d3568efa1e96b31a9c..4efb953c550fae754c62c96098bb8e8a51995b80 100644 (file)
@@ -147,6 +147,11 @@ struct attrset *dict_get_attributes (const struct dictionary *);
 void dict_set_attributes (struct dictionary *, const struct attrset *);
 bool dict_has_attributes (const struct dictionary *);
 
+
+void dict_set_encoding (struct dictionary *d, const char *enc);
+const char *dict_get_encoding (const struct dictionary *d);
+
+
 /* Functions to be called upon dictionary changes. */
 struct dict_callbacks
  {
index 5a0c75ede293a21052228a87b295a070398f3e1f..f2f4e52f58294d846aaa05b8d4f36d9df666917f 100644 (file)
@@ -314,11 +314,10 @@ static void
 convert_xml_string_to_value (struct ccase *c, const struct variable *var,
                             const xmlChar *xv)
 {
-  char *text;
   int n_bytes = 0;
   union value *v = case_data_rw (c, var);
 
-  text = recode_string (CONV_UTF8_TO_PSPP, (const char *) xv, -1);
+  const char *text = (const char *) xv;
 
   if ( text)
     n_bytes = MIN (var_get_width (var), strlen (text));
@@ -335,8 +334,6 @@ convert_xml_string_to_value (struct ccase *c, const struct variable *var,
       if ( errno != 0 || endptr == text)
        v->f = SYSMIS;
     }
-
-  free (text);
 }
 
 struct var_spec
@@ -459,10 +456,8 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
 
       if ( r->node_type == XML_READER_TYPE_TEXT )
        {
-         char *text ;
          xmlChar *value = xmlTextReaderValue (r->xtr);
-
-         text = recode_string (CONV_UTF8_TO_PSPP, (const char *) value, -1);
+         const char *text  = (const char *) value;
 
          if ( r->row < r->start_row)
            {
@@ -481,7 +476,6 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
            }
 
          free (value);
-         free (text);
        }
       else if ( r->node_type == XML_READER_TYPE_ELEMENT
                && r->state == STATE_CELL)
@@ -503,6 +497,8 @@ gnumeric_open_reader (struct gnumeric_read_info *gri, struct dictionary **dict)
   /* Create the dictionary and populate it */
   *dict = r->dict = dict_create ();
 
+  dict_set_encoding (r->dict, (const char *) xmlTextReaderConstEncoding (r->xtr));
+  
   r->value_cnt = 0;
 
   for (i = 0 ; i < n_var_specs ; ++i )
index a52944e2757a11db7ace38273283d081581d0375..37384b6d7786f24f46f6b5e6a785ffc87f44116e 100644 (file)
@@ -35,7 +35,7 @@ bool
 lex_is_id1 (char c_)
 {
   unsigned char c = c_;
-  return isalpha (c) || c == '@' || c == '#' || c == '$';
+  return isalpha (c) || c == '@' || c == '#' || c == '$' || c >= 128;
 }
 
 
@@ -45,7 +45,7 @@ bool
 lex_is_idn (char c_)
 {
   unsigned char c = c_;
-  return lex_is_id1 (c) || isdigit (c) || c == '.' || c == '_';
+  return lex_is_id1 (c) || isdigit (c) || c == '.' || c == '_' || c >= 128;
 }
 
 /* Returns the length of the longest prefix of STRING that forms
index a54b9f8b3888c58320623ea1d53086bc8650a155..f2d5ff282272f48e821c4826d9d60f5158f6bfca 100644 (file)
@@ -288,10 +288,22 @@ psql_open_reader (struct psql_read_info *info, struct dictionary **dict)
   /* Create the dictionary and populate it */
   *dict = r->dict = dict_create ();
 
+  {
+    const int enc = PQclientEncoding (r->conn);
+
+    /* According to section 22.2 of the Postgresql manual
+       a value of zero (SQL_ASCII) indicates
+       "a declaration of ignorance about the encoding".
+       Accordingly, we don't set the dictionary's encoding
+       if we find this value.
+    */
+    if ( enc != 0 )
+      dict_set_encoding (r->dict, pg_encoding_to_char (enc));
+  }
+
   /*
     select count (*) from (select * from medium) stupid_sql_standard;
   */
-
   ds_init_cstr (&query,
                "BEGIN READ ONLY ISOLATION LEVEL SERIALIZABLE; "
                "DECLARE  pspp BINARY CURSOR FOR ");
index ad509fb028059a6c6d3af86445a1bdb9e744ce08..f9c65fc8c4ee61f53eb2c4cc3db9af21a6f49417 100644 (file)
@@ -22,9 +22,9 @@
 #include "format.h"
 #include "value.h"
 #include "xalloc.h"
-#include <libpspp/i18n.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/message.h>
+#include <libpspp/i18n.h>
 
 #include "error.h"
 
@@ -147,7 +147,6 @@ settings_init (int *width, int *length)
 {
   init_viewport (width, length);
   settings_set_epoch (-1);
-  i18n_init ();
   the_settings.styles = fmt_create ();
 
   settings_set_decimal_char (get_system_decimal ());
@@ -157,7 +156,6 @@ void
 settings_done (void)
 {
   fmt_done (the_settings.styles);
-  i18n_done ();
 }
 
 /* Returns the floating-point format used for RB and RBHEX
index 84d7f83c4c422a502272ec47039aeb3bb5889b18..fb4f6f93defcc8cc7486fd3039fe7a36f8efd37a 100644 (file)
@@ -778,7 +778,12 @@ read_extension_record (struct sfm_reader *r, struct dictionary *dict,
     case 20:
       /* New in SPSS 16.  Contains a single string that describes
          the character encoding, e.g. "windows-1252". */
-      break;
+      {
+       char *encoding = calloc (size, count + 1);
+       read_string (r, encoding, count + 1);
+       dict_set_encoding (dict, encoding);
+       return;
+      }
 
     case 21:
       /* New in SPSS 16.  Encodes value labels for long string
index 393be4e1265292b58fc37daa64bfaf4a4ff40a15..292ec9c5d053ba7603b1db27d26178e4eeb6335d 100644 (file)
@@ -103,6 +103,9 @@ static void write_float_info_record (struct sfm_writer *);
 static void write_longvar_table (struct sfm_writer *w,
                                  const struct dictionary *dict);
 
+static void write_encoding_record (struct sfm_writer *w,
+                                  const struct dictionary *);
+
 static void write_vls_length_table (struct sfm_writer *w,
                              const struct dictionary *dict);
 
@@ -246,6 +249,8 @@ sfm_open_writer (struct file_handle *fh, struct dictionary *d,
     write_data_file_attributes (w, d);
   write_variable_attributes (w, d);
 
+  write_encoding_record (w, d);
+
   /* Write end-of-headers record. */
   write_int (w, 999);
   write_int (w, 0);
@@ -660,6 +665,24 @@ write_vls_length_table (struct sfm_writer *w,
   ds_destroy (&map);
 }
 
+
+static void
+write_encoding_record (struct sfm_writer *w,
+                      const struct dictionary *d)
+{
+  const char *enc = dict_get_encoding (d);
+
+  if ( NULL == enc)
+    return;
+
+  write_int (w, 7);             /* Record type. */
+  write_int (w, 20);            /* Record subtype. */
+  write_int (w, 1);             /* Data item (char) size. */
+  write_int (w, strlen (enc));  /* Number of data items. */
+  write_string (w, enc, strlen (enc));
+}
+
+
 /* Writes the long variable name table. */
 static void
 write_longvar_table (struct sfm_writer *w, const struct dictionary *dict)
@@ -1019,7 +1042,7 @@ write_value (struct sfm_writer *w, const union value *value, int width)
 }
 
 /* Writes null-terminated STRING in a field of the given WIDTH to
-   W.  If WIDTH is longer than WIDTH, it is truncated; if WIDTH
+   W.  If STRING is longer than WIDTH, it is truncated; if WIDTH
    is narrowed, it is padded on the right with spaces. */
 static void
 write_string (struct sfm_writer *w, const char *string, size_t width)
index d6279159a6587e8cf2d8c82524e52581c50ba979..6d033419d1f404e8a0a6dcfd3ff0cabe32f919cd 100644 (file)
@@ -108,7 +108,7 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
     }
   casereader_destroy (reader);
 
-  t = tab_create (2, 10, 0);
+  t = tab_create (2, 11, 0);
   tab_vline (t, TAL_GAP, 1, 0, 8);
   tab_text (t, 0, 0, TAB_LEFT, _("File:"));
   tab_text (t, 1, 0, TAB_LEFT, fh_get_file_name (h));
@@ -153,6 +153,13 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   tab_text (t, 0, 9, TAB_LEFT, _("Mode:"));
   tab_text (t, 1, 9, TAB_LEFT | TAT_PRINTF,
                _("Compression %s."), info.compressed ? _("on") : _("off"));
+
+
+  tab_text (t, 0, 10, TAB_LEFT, _("Charset:"));
+  tab_text (t, 1, 10, TAB_LEFT | TAT_PRINTF,
+           dict_get_encoding(d) ? dict_get_encoding(d) : _("Unknown"));
+
+
   tab_dim (t, tab_natural_dimensions);
   tab_submit (t);
 
index 37388f9264162e2c346c4f7b7a3edc637aa8bcce..e8cdf1aad89e6c0dfc3996a286698450779a1c15 100644 (file)
@@ -38,6 +38,7 @@
 #include <libpspp/float-format.h>
 #include <libpspp/integer-format.h>
 #include <libpspp/message.h>
+#include <libpspp/i18n.h>
 #include <math/random.h>
 #include <output/journal.h>
 #include <output/output.h>
@@ -86,6 +87,7 @@ int tgetnum (const char *);
      journal=custom;
      log=custom;
      length=custom;
+     locale=custom;
      listing=custom;
      lowres=lores:auto/on/off;
      lpi=integer "x>0" "%s must be greater than 0";
@@ -361,6 +363,41 @@ stc_custom_length (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_se
   return 1;
 }
 
+static int
+stc_custom_locale (struct lexer *lexer, struct dataset *ds UNUSED,
+                  struct cmd_set *cmd UNUSED, void *aux UNUSED)
+{
+  const struct string *s;
+
+  lex_match (lexer, '=');
+
+  if ( !lex_force_string (lexer))
+    return 0;
+
+  s = lex_tokstr (lexer);
+
+  lex_get (lexer);
+
+  /* First try this string as an encoding name */
+  if ( valid_encoding (ds_cstr (s)))
+    set_default_encoding (ds_cstr (s));
+
+  /* Now try as a locale name (or alias) */
+  else if (set_encoding_from_locale (ds_cstr (s)))
+    {
+    }
+  else
+    {
+      msg (ME, _("%s is not a recognised encoding or locale name"),
+          ds_cstr (s));
+      return 0;
+    }
+
+  return 1;
+}
+
+
+
 static int
 stc_custom_seed (struct lexer *lexer, struct dataset *ds UNUSED, struct cmd_set *cmd UNUSED, void *aux UNUSED)
 {
@@ -589,6 +626,12 @@ show_length (const struct dataset *ds UNUSED)
   msg (SN, _("LENGTH is %d."), settings_get_viewlength ());
 }
 
+static void
+show_locale (const struct dataset *ds UNUSED)
+{
+  msg (SN, _("LOCALE is %s"), get_default_encoding ());
+}
+
 static void
 show_mxerrs (const struct dataset *ds UNUSED)
 {
@@ -744,6 +787,7 @@ const struct show_sbc show_table[] =
     {"ERRORS", show_errors},
     {"FORMAT", show_format},
     {"LENGTH", show_length},
+    {"LOCALE", show_locale},
     {"MXERRS", show_mxerrs},
     {"MXLOOPS", show_mxloops},
     {"MXWARNS", show_mxwarns},
index f8e5e396e865efe267155f29f02aa29fb024649f..c0459712e71480dba9503aaa9260a28ac115f4c6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2009 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
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <libintl.h>
 #include <iconv.h>
 #include <errno.h>
 #include "assertion.h"
+#include "hmapx.h"
+#include "hash-functions.h"
 
 #include "i18n.h"
 
+#include "version.h"
+
 #include <localcharset.h>
 #include "xstrndup.h"
 
 #include <langinfo.h>
 #endif
 
-
-static char *locale;
-static char *charset;
-
-
-static iconv_t convertor[n_CONV];
-
+static char *default_encoding;
+static struct hmapx map;
 
 /* A wrapper around iconv_open */
 static iconv_t
 create_iconv (const char* tocode, const char* fromcode)
 {
-  iconv_t conv = iconv_open (tocode, fromcode);
+  iconv_t conv;
+  struct hmapx_node *node;
+  size_t hash ;
+  char *key = alloca (strlen (tocode) + strlen (fromcode) + 2);
+
+  strcpy (key, tocode);
+  strcat (key, "\n"); /* hopefully no encoding names contain '\n' */
+  strcat (key, fromcode);
 
-  /* I don't think it's safe to translate this string or to use messaging
-     as the convertors have not yet been set up */
-  if ( (iconv_t) -1 == conv && 0 != strcmp (tocode, fromcode))
+  hash = hsh_hash_string (key);
+
+  node = hmapx_first_with_hash (&map, hash);
+
+  if (!node)
+    {
+      conv = iconv_open (tocode, fromcode);
+
+      /* I don't think it's safe to translate this string or to use messaging
+        as the convertors have not yet been set up */
+      if ( (iconv_t) -1 == conv && 0 != strcmp (tocode, fromcode))
+       {
+         const int err = errno;
+         fprintf (stderr,
+                  "Warning: "
+                  "cannot create a convertor for \"%s\" to \"%s\": %s\n",
+                  fromcode, tocode, strerror (err));
+       }
+
+      hmapx_insert (&map, conv, hash);
+    }
+  else
     {
-      const int err = errno;
-      fprintf (stderr,
-       "Warning: cannot create a convertor for \"%s\" to \"%s\": %s\n",
-       fromcode, tocode, strerror (err));
+      conv = hmapx_node_data (node);
     }
 
   return conv;
@@ -66,7 +89,8 @@ create_iconv (const char* tocode, const char* fromcode)
    The returned string must be freed when no longer required.
 */
 char *
-recode_string (enum conv_id how,  const char *text, int length)
+recode_string (const char *to, const char *from,
+              const char *text, int length)
 {
   char *outbuf = 0;
   size_t outbufferlength;
@@ -74,6 +98,7 @@ recode_string (enum conv_id how,  const char *text, int length)
   char *op ;
   size_t inbytes = 0;
   size_t outbytes ;
+  iconv_t conv ;
 
   /* FIXME: Need to ensure that this char is valid in the target encoding */
   const char fallbackchar = '?';
@@ -84,10 +109,12 @@ recode_string (enum conv_id how,  const char *text, int length)
   if ( length == -1 )
      length = strlen(text);
 
-  assert (how < n_CONV);
 
-  if (convertor[how] == (iconv_t) -1)
-    return xstrndup (text, length);
+  if (to == NULL)
+    to = default_encoding;
+
+  if (from == NULL)
+    from = default_encoding;
 
   for ( outbufferlength = 1 ; outbufferlength != 0; outbufferlength <<= 1 )
     if ( outbufferlength > length)
@@ -99,9 +126,12 @@ recode_string (enum conv_id how,  const char *text, int length)
   outbytes = outbufferlength;
   inbytes = length;
 
+
+  conv = create_iconv (to, from);
+
   do {
     const char *ip = text;
-    result = iconv (convertor[how], (ICONV_CONST char **) &text, &inbytes,
+    result = iconv (conv, (ICONV_CONST char **) &text, &inbytes,
                   &op, &outbytes);
 
     if ( -1 == result )
@@ -152,79 +182,113 @@ recode_string (enum conv_id how,  const char *text, int length)
 }
 
 
-/* Returns the current PSPP locale */
+void
+i18n_init (void)
+{
+#if ENABLE_NLS
+  setlocale (LC_CTYPE, "");
+#if HAVE_LC_MESSAGES
+  setlocale (LC_MESSAGES, "");
+#endif
+#if HAVE_LC_PAPER
+  setlocale (LC_PAPER, "");
+#endif
+  bindtextdomain (PACKAGE, locale_dir);
+  textdomain (PACKAGE);
+#endif /* ENABLE_NLS */
+
+  assert (default_encoding == NULL);
+  default_encoding = strdup (locale_charset ());
+
+  hmapx_init (&map);
+}
+
+
 const char *
-get_pspp_locale (void)
+get_default_encoding (void)
 {
-  assert (locale);
-  return locale;
+  return default_encoding;
 }
 
-/* Set the PSPP locale */
 void
-set_pspp_locale (const char *l)
+set_default_encoding (const char *enc)
 {
-  char *current_locale;
-  char *current_charset;
+  free (default_encoding);
+  default_encoding = strdup (enc);
+}
 
-  free(locale);
-  locale = strdup(l);
 
-  current_locale = strdup (setlocale (LC_CTYPE, 0));
-  current_charset = strdup (locale_charset ());
-  setlocale (LC_CTYPE, locale);
+/* Attempts to set the encoding from a locale name
+   returns true if successfull.
+   This function does not (should not!) alter the current locale.
+*/
+bool
+set_encoding_from_locale (const char *loc)
+{
+  bool ok = true;
+  char *c_encoding;
+  char *loc_encoding;
+  char *tmp = strdup (setlocale (LC_CTYPE, NULL));
 
-  free (charset);
-  charset = strdup (locale_charset ());
-  setlocale (LC_CTYPE, current_locale);
+  setlocale (LC_CTYPE, "C");
+  c_encoding = strdup (locale_charset ());
 
-  iconv_close (convertor[CONV_PSPP_TO_UTF8]);
-  convertor[CONV_PSPP_TO_UTF8] = create_iconv ("UTF-8", charset);
+  setlocale (LC_CTYPE, loc);
+  loc_encoding = strdup (locale_charset ());
 
-  iconv_close (convertor[CONV_SYSTEM_TO_PSPP]);
-  convertor[CONV_SYSTEM_TO_PSPP] = create_iconv (charset, current_charset);
 
-  iconv_close (convertor[CONV_UTF8_TO_PSPP]);
-  convertor[CONV_UTF8_TO_PSPP] = create_iconv (charset, "UTF-8");
+  if ( 0 == strcmp (loc_encoding, c_encoding))
+    {
+      ok = false;
+    }
 
-  free (current_locale);
-  free (current_charset);
-}
 
-void
-i18n_init (void)
-{
-  assert (!locale) ;
-  locale = strdup (setlocale (LC_CTYPE, NULL));
+  setlocale (LC_CTYPE, tmp);
 
-  setlocale (LC_CTYPE, locale);
+  free (tmp);
+
+  if (ok)
+    {
+      free (default_encoding);
+      default_encoding = loc_encoding;
+    }
+  else
+    free (loc_encoding);
 
-  free (charset);
-  charset = strdup (locale_charset ());
+  free (c_encoding);
 
-  convertor[CONV_PSPP_TO_UTF8]   = create_iconv ("UTF-8", charset);
-  convertor[CONV_SYSTEM_TO_PSPP] = create_iconv (charset, charset);
-  convertor[CONV_UTF8_TO_PSPP]   = create_iconv (charset, "UTF-8");
+  return ok;
 }
 
-
 void
 i18n_done (void)
 {
-  int i;
-  free (locale);
-  locale = 0;
+  struct hmapx_node *node;
+  iconv_t conv;
+  HMAPX_FOR_EACH (conv, node, &map)
+    iconv_close (conv);
 
-  for(i = 0 ; i < n_CONV; ++i )
-    {
-      if ( (iconv_t) -1 == convertor[i] )
-       continue;
-      iconv_close (convertor[i]);
-    }
+  hmapx_destroy (&map);
+
+  free (default_encoding);
+  default_encoding = NULL;
 }
 
 
 
+bool
+valid_encoding (const char *enc)
+{
+  iconv_t conv = iconv_open ("UTF8", enc);
+
+  if ( conv == (iconv_t) -1)
+    return false;
+
+  iconv_close (conv);
+
+  return true;
+}
+
 
 /* Return the system local's idea of the
    decimal seperator character */
index db15bad86940a955f0a0a942af548a8a7b177edb..2c30a70012e18fd2c556c158f9355edb3a0a5d31 100644 (file)
 #ifndef I18N_H
 #define I18N_H
 
-const char * get_pspp_locale (void);
-void set_pspp_locale (const char *locale);
-const char * get_pspp_charset (void);
+#include <stdbool.h>
 
 void  i18n_done (void);
 void  i18n_init (void);
 
-enum conv_id
-  {
-    CONV_PSPP_TO_UTF8,
-    CONV_SYSTEM_TO_PSPP,
-    CONV_UTF8_TO_PSPP,
-    n_CONV
-  };
+#define UTF8 "UTF-8"
 
+char * recode_string (const char *to, const char *from,
+                     const char *text, int len);
 
-char * recode_string (enum conv_id how,  const char *text, int len);
 
+bool valid_encoding (const char *enc);
 
 /* Return the decimal separator according to the
    system locale */
 char get_system_decimal (void);
 
+const char * get_default_encoding (void);
+void set_default_encoding (const char *enc);
+
+bool set_encoding_from_locale (const char *loc);
+
+
 #endif /* i18n.h */
index 7703640c4d553e81eb6584f28eb46841a0c3fe21..a42ce4febf438d338727a68a9f70728217b8c2d4 100644 (file)
@@ -24,6 +24,7 @@
 #include "psppire-var-store.h"
 #include "psppire-selector.h"
 #include "dialog-common.h"
+#include <libpspp/i18n.h>
 
 #include <language/expressions/public.h>
 #include <language/syntax-string-source.h>
@@ -631,7 +632,9 @@ insert_source_row_into_text_view (GtkTreeIter iter,
 
   gtk_tree_path_free (path);
 
-  name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+  name = recode_string (UTF8, psppire_dict_encoding (dict),
+                       var_get_name (var),
+                       -1);
 
   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (dest));
 
index 0aab294e12ef0b2a8ca937851f60533525847619..8d03bed16186e5664207b9fc2b8e989c63f10eae 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <config.h>
 
+#include <libpspp/i18n.h>
 #include "dialog-common.h"
 
 #include "psppire-var-ptr.h"
@@ -118,7 +119,8 @@ cell_var_name (GtkTreeViewColumn *tree_column,
 
   var = get_selected_variable (tree_model, iter, dict);
 
-  name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+  name = recode_string (UTF8, psppire_dict_encoding (dict),
+                       var_get_name (var), -1);
   g_object_set (cell, "text", name, NULL);
   g_free (name);
 }
index 2123c3c5cfe7b300b6c2bcaca241f5ae95d5636d..d6b1bcd58c3b60bc5bb17705da7c18c4121d4105 100644 (file)
@@ -23,6 +23,7 @@
 #include "dict-display.h"
 
 #include "psppire-dict.h"
+#include <libpspp/i18n.h>
 #include "helper.h"
 #include <data/variable.h>
 #include <data/format.h>
@@ -80,7 +81,8 @@ insert_source_row_into_entry (GtkTreeIter iter,
 
   gtk_tree_path_free (path);
 
-  name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+  name = recode_string (UTF8, psppire_dict_encoding (PSPPIRE_DICT (dict)),
+                       var_get_name (var), -1);
   gtk_entry_set_text (GTK_ENTRY (dest),  name);
   g_free (name);
 }
@@ -142,7 +144,8 @@ is_currently_in_entry (GtkTreeModel *model, GtkTreeIter *iter,
 
   gtk_tree_path_free (path);
 
-  name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+  name = recode_string (UTF8, psppire_dict_encoding (PSPPIRE_DICT (dict)),
+                       var_get_name (var), -1);
   result = ( 0 == strcmp (text, name));
   g_free (name);
 
index 9ac9fde6ec43b65ab79765859fb5ccfe9f5ec6ec..6d90cfc4ea5e7a4b6e5b2a33b6ad3210744c802c 100644 (file)
@@ -152,20 +152,6 @@ get_widget_assert (GtkBuilder *builder, const gchar *name)
   return GTK_WIDGET (get_object_assert (builder, name, GTK_TYPE_WIDGET));
 }
 
-/* Converts a string in the pspp locale to utf-8.
-   The return value must be freed when no longer required*/
-gchar *
-pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err)
-{
-  return recode_string (CONV_PSPP_TO_UTF8, text, len);
-}
-
-gchar *
-utf8_to_pspp_locale (const gchar *text, gssize len, GError **err)
-{
-  return recode_string (CONV_UTF8_TO_PSPP, text, len);
-}
-
 /* This function must be used whenever a filename generated by glib,
    (eg, from gtk_file_chooser_get_filename) and passed to the C library,
    (eg through a pspp syntax string).
index 30792faf0835f5f8b0f1e2d6da11c469e9633516..6bd610e7c541b2e5bd01f0a17694fa4bc8703bb4 100644 (file)
@@ -43,14 +43,9 @@ GObject *get_object_assert (GtkBuilder *builder, const gchar *name, GType type);
 GtkAction * get_action_assert (GtkBuilder *builder, const gchar *name);
 GtkWidget * get_widget_assert (GtkBuilder *builder, const gchar *name);
 
-/* Converts a string in the pspp locale to utf-8 */
-gchar * pspp_locale_to_utf8 (const gchar *text, gssize len, GError **err);
-gchar * utf8_to_pspp_locale (const gchar *text, gssize len, GError **err);
-
 gchar * convert_glib_filename_to_system_filename (const gchar *fname,
                                                  GError **err);
 
-
 void connect_help (GtkBuilder *);
 
 void reference_manual (GtkMenuItem *, gpointer);
index a36e9410a345557f6c7e9a8ece90b0a15b5aec3d..71b9fbdc9674bebc13b6ea4ccca79d93619a1e00 100644 (file)
@@ -142,6 +142,8 @@ main (int argc, char *argv[])
 
   set_program_name (argv[0]);
 
+  gtk_disable_setlocale ();
+
   if ( ! gtk_parse_args (&argc, &argv) )
     {
       perror ("Error parsing arguments");
index ab3b21284ec55d23968c7c0de5c3a3fa246beb52..1070f5c2871caef36db153d9b48aca7667497ad3 100644 (file)
@@ -24,6 +24,7 @@
 #include <language/syntax-string-source.h>
 #include "psppire-data-store.h"
 #include <ui/gui/sheet/psppire-axis-impl.h>
+#include <libpspp/i18n.h>
 #include "helper.h"
 
 #include <gtk-contrib/gtkxpaned.h>
@@ -743,7 +744,9 @@ update_data_ref_entry (const PsppireSheet *sheet,
          gchar *text = g_strdup_printf ("%d: %s", row + FIRST_CASE_NUMBER,
                                         var_get_name (var));
 
-         gchar *s = pspp_locale_to_utf8 (text, -1, 0);
+         gchar *s = recode_string (UTF8,
+                                   psppire_dict_encoding (data_store->dict),
+                                   text, -1);
 
          g_free (text);
 
index 45104f5cbb8ff519418fee88edf92e496e91652c..45fa82488b4e19dabbdf991bae83681fe2e93075 100644 (file)
@@ -31,6 +31,7 @@
 #include <pango/pango-context.h>
 
 #include "psppire-data-store.h"
+#include <libpspp/i18n.h>
 #include "helper.h"
 
 #include <data/dictionary.h>
@@ -598,7 +599,8 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
       if (label)
         {
           free (v);
-         return pspp_locale_to_utf8 (label, -1, 0);
+         return recode_string (UTF8, psppire_dict_encoding (store->dict),
+                               label, -1);
         }
     }
 
@@ -616,7 +618,8 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
      FP.  No null terminator is appended to the buffer.  */
   data_out (v, fp, s->str);
 
-  text = pspp_locale_to_utf8 (s->str, fp->w, 0);
+  text = recode_string (UTF8, psppire_dict_encoding (store->dict),
+                       s->str, fp->w);
   g_string_free (s, TRUE);
 
   g_strchomp (text);
@@ -673,7 +676,7 @@ psppire_data_store_set_string (PsppireDataStore *store,
   if (row == n_cases)
     psppire_data_store_insert_new_case (store, row);
 
-  s = utf8_to_pspp_locale (text, -1, NULL);
+  s = recode_string (psppire_dict_encoding (store->dict), UTF8, text, -1);
 
   psppire_data_store_data_in (store, row,
                              var_get_case_index (pv), ss_cstr (s),
@@ -749,9 +752,11 @@ static const gchar null_var_name[]=N_("var");
 static gchar *
 get_row_button_label (const PsppireSheetModel *model, gint unit)
 {
+  PsppireDataStore *ds = PSPPIRE_DATA_STORE (model);
   gchar *s = g_strdup_printf (_("%d"), unit + FIRST_CASE_NUMBER);
 
-  gchar *text =  pspp_locale_to_utf8 (s, -1, 0);
+  gchar *text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
+                               s, -1);
 
   g_free (s);
 
@@ -787,7 +792,8 @@ get_column_subtitle (const PsppireSheetModel *model, gint col)
   if ( ! var_has_label (v))
     return NULL;
 
-  text =  pspp_locale_to_utf8 (var_get_label (v), -1, 0);
+  text =  recode_string (UTF8, psppire_dict_encoding (ds->dict),
+                        var_get_label (v), -1);
 
   return text;
 }
@@ -804,7 +810,8 @@ get_column_button_label (const PsppireSheetModel *model, gint col)
 
   pv = psppire_dict_get_variable (ds->dict, col);
 
-  text =  pspp_locale_to_utf8 (var_get_name (pv), -1, 0);
+  text = recode_string (UTF8, psppire_dict_encoding (ds->dict),
+                       var_get_name (pv), -1);
 
   return text;
 }
index 564257f46c8cdb74c6adef8ce6d4547f0bd70764..afc7d570c9afe6ab85f637344b9b46a9340bc711 100644 (file)
@@ -26,6 +26,7 @@
 #include <data/missing-values.h>
 #include <data/value-labels.h>
 #include <data/variable.h>
+#include <libpspp/i18n.h>
 
 #include "helper.h"
 #include "message-dialog.h"
@@ -752,10 +753,11 @@ tree_model_get_value (GtkTreeModel *model, GtkTreeIter *iter,
     {
     case DICT_TVM_COL_NAME:
       {
-      gchar *name = pspp_locale_to_utf8(var_get_name (var), -1, NULL);
-      g_value_init (value, G_TYPE_STRING);
-      g_value_set_string (value, name);
-      g_free (name);
+       gchar *name = recode_string (UTF8, psppire_dict_encoding (dict),
+                                    var_get_name (var), -1);
+       g_value_init (value, G_TYPE_STRING);
+       g_value_set_string (value, name);
+       g_free (name);
       }
       break;
     case DICT_TVM_COL_VAR:
@@ -859,3 +861,12 @@ psppire_dict_dump (const PsppireDict *dict)
     }
 }
 #endif
+
+
+
+
+const gchar *
+psppire_dict_encoding (const PsppireDict *dict)
+{
+  return dict_get_encoding (dict->dict);
+}
index 3fd73f9a6dc0bd9f21e9016cc7037f495081dcb6..54f3e39af0597d3399d09bf628eb8fb12d2bb1c9 100644 (file)
@@ -109,6 +109,8 @@ struct variable * psppire_dict_get_weight_variable (const PsppireDict *);
 void psppire_dict_dump (const PsppireDict *);
 #endif
 
+const gchar *psppire_dict_encoding (const PsppireDict *);
+
 G_END_DECLS
 
 #endif /* __PSPPIRE_DICT_H__ */
index 863365f9f8549696f9c0afa2fb1cbd14dba09e79..37539694b138c109fbe6692628e3009dd62e35e9 100644 (file)
@@ -21,6 +21,7 @@
 #include "psppire-dict.h"
 #include "psppire-conf.h"
 #include <data/format.h>
+#include <libpspp/i18n.h>
 #include "helper.h"
 
 #include <gettext.h>
@@ -274,11 +275,15 @@ dv_get_base_model (GtkTreeModel *top_model, GtkTreeIter *top_iter,
                )
 {
   *model = top_model;
-  *iter = *top_iter;
+
+  if ( iter)
+    *iter = *top_iter;
 
   while ( ! PSPPIRE_IS_DICT (*model))
     {
-      GtkTreeIter parent_iter = *iter;
+      GtkTreeIter parent_iter;
+      if (iter)
+       parent_iter = *iter;
 
       if ( GTK_IS_TREE_MODEL_FILTER (*model))
        {
@@ -286,9 +291,10 @@ dv_get_base_model (GtkTreeModel *top_model, GtkTreeIter *top_iter,
 
          *model = gtk_tree_model_filter_get_model (parent_model);
 
-         gtk_tree_model_filter_convert_iter_to_child_iter (parent_model,
-                                                           iter,
-                                                           &parent_iter);
+         if (iter)
+           gtk_tree_model_filter_convert_iter_to_child_iter (parent_model,
+                                                             iter,
+                                                             &parent_iter);
        }
       else if (GTK_IS_TREE_MODEL_SORT (*model))
        {
@@ -296,9 +302,10 @@ dv_get_base_model (GtkTreeModel *top_model, GtkTreeIter *top_iter,
 
          *model = gtk_tree_model_sort_get_model (parent_model);
 
-         gtk_tree_model_sort_convert_iter_to_child_iter (parent_model,
-                                                         iter,
-                                                         &parent_iter);
+         if (iter)
+           gtk_tree_model_sort_convert_iter_to_child_iter (parent_model,
+                                                           iter,
+                                                           &parent_iter);
        }
     }
 }
@@ -318,11 +325,11 @@ var_description_cell_data_func (GtkTreeViewColumn *col,
   struct variable *var;
   GtkTreeIter iter;
   GtkTreeModel *model;
-
+  PsppireDict *dict;
 
   dv_get_base_model (top_model, top_iter, &model, &iter);
 
-  g_assert (PSPPIRE_IS_DICT (model));
+  dict = PSPPIRE_DICT (model);
 
   gtk_tree_model_get (model,
                      &iter, DICT_TVM_COL_VAR, &var, -1);
@@ -333,7 +340,8 @@ var_description_cell_data_func (GtkTreeViewColumn *col,
                                     "<span stretch=\"condensed\">%s</span>",
                                     var_get_label (var));
 
-      char *utf8 = pspp_locale_to_utf8 (text, -1, NULL);
+      char *utf8 = recode_string (UTF8, psppire_dict_encoding (dict),
+                                 text, -1);
 
       g_free (text);
       g_object_set (cell, "markup", utf8, NULL);
@@ -341,7 +349,8 @@ var_description_cell_data_func (GtkTreeViewColumn *col,
     }
   else
     {
-      char *name = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+      char *name = recode_string (UTF8, psppire_dict_encoding (dict),
+                                 var_get_name (var), -1);
       g_object_set (cell, "text", name, NULL);
       g_free (name);
     }
@@ -406,7 +415,6 @@ set_tooltip_for_variable (GtkTreeView  *treeview,
   struct variable *var = NULL;
   gboolean ok;
 
-
   gtk_tree_view_convert_widget_to_bin_window_coords (treeview,
                                                      x, y, &bx, &by);
 
@@ -416,7 +424,6 @@ set_tooltip_for_variable (GtkTreeView  *treeview,
 
   tree_model = gtk_tree_view_get_model (treeview);
 
-
   gtk_tree_view_set_tooltip_row (treeview, tooltip, path);
 
   ok = gtk_tree_model_get_iter (tree_model, &iter, path);
@@ -433,11 +440,18 @@ set_tooltip_for_variable (GtkTreeView  *treeview,
 
   {
     gchar *tip ;
+    GtkTreeModel *m;
+    PsppireDict *dict;
+
+    dv_get_base_model (tree_model, NULL, &m, NULL);
+    dict = PSPPIRE_DICT (m);
 
     if ( PSPPIRE_DICT_VIEW (treeview)->prefer_labels )
-      tip = pspp_locale_to_utf8 (var_get_name (var), -1, NULL);
+      tip = recode_string (UTF8, psppire_dict_encoding (dict),
+                          var_get_name (var), -1);
     else
-      tip = pspp_locale_to_utf8 (var_get_label (var), -1, NULL);
+      tip = recode_string (UTF8, psppire_dict_encoding (dict),
+                          var_get_label (var), -1);
 
     gtk_tooltip_set_text (tooltip, tip);
 
index 517a61e04b71924064ba4463aa695da111ff9e6b..b742f3b7c69d7431ab2789fb5b7fcbc1f366586a 100644 (file)
@@ -489,7 +489,8 @@ psppire_var_sheet_realize (GtkWidget *w)
 
   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (vs));
 
-  vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel));
+  vs->val_labs_dialog = val_labs_dialog_create (GTK_WINDOW (toplevel),
+                                               PSPPIRE_SHEET (vs));
   vs->missing_val_dialog = missing_val_dialog_create (GTK_WINDOW (toplevel));
   vs->var_type_dialog = var_type_dialog_create (GTK_WINDOW (toplevel));
 
index 1d6f465d437e5c2605bb8001a7ddce6fd720eb3c..b64bc64ee79c805d3e21cf58a4de56b4077be995 100644 (file)
@@ -21,7 +21,7 @@
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
-
+#include <libpspp/i18n.h>
 
 #include <gobject/gvaluecollector.h>
 
@@ -53,9 +53,6 @@ static void         psppire_var_store_sheet_model_init (PsppireSheetModelIface *
 static void         psppire_var_store_finalize        (GObject           *object);
 
 
-gchar * missing_values_to_string (const struct variable *pv, GError **err);
-
-
 static gchar *psppire_var_store_get_string (const PsppireSheetModel *sheet_model, glong row, glong column);
 
 static gboolean  psppire_var_store_clear (PsppireSheetModel *model,  glong row, glong col);
@@ -67,7 +64,8 @@ static gboolean psppire_var_store_set_string (PsppireSheetModel *model,
 static glong psppire_var_store_get_row_count (const PsppireSheetModel * model);
 static glong psppire_var_store_get_column_count (const PsppireSheetModel * model);
 
-static gchar *text_for_column (const struct variable *pv, gint c, GError **err);
+static gchar *text_for_column (PsppireVarStore *vs, const struct variable *pv,
+                              gint c, GError **err);
 
 
 static GObjectClass *parent_class = NULL;
@@ -399,7 +397,8 @@ psppire_var_store_finalize (GObject *object)
 }
 
 static gchar *
-psppire_var_store_get_string (const PsppireSheetModel *model, glong row, glong column)
+psppire_var_store_get_string (const PsppireSheetModel *model,
+                             glong row, glong column)
 {
   PsppireVarStore *store = PSPPIRE_VAR_STORE (model);
 
@@ -410,7 +409,7 @@ psppire_var_store_get_string (const PsppireSheetModel *model, glong row, glong c
 
   pv = psppire_dict_get_variable (store->dict, row);
 
-  return text_for_column (pv, column, 0);
+  return text_for_column (store, pv, column, 0);
 }
 
 
@@ -531,7 +530,9 @@ psppire_var_store_set_string (PsppireSheetModel *model,
       break;
     case PSPPIRE_VAR_STORE_COL_LABEL:
       {
-       gchar *s = utf8_to_pspp_locale (text, -1, NULL);
+       gchar *s = recode_string (psppire_dict_encoding (var_store->dict),
+                                 UTF8,
+                                 text, -1);
        var_set_label (pv, s);
        free (s);
        return TRUE;
@@ -557,8 +558,10 @@ psppire_var_store_set_string (PsppireSheetModel *model,
 static const gchar none[] = N_("None");
 
 static  gchar *
-text_for_column (const struct variable *pv, gint c, GError **err)
+text_for_column (PsppireVarStore *vs,
+                const struct variable *pv, gint c, GError **err)
 {
+  PsppireDict *dict = vs->dict;
   static const gchar *const type_label[] =
     {
       N_("Numeric"),
@@ -578,7 +581,8 @@ text_for_column (const struct variable *pv, gint c, GError **err)
   switch (c)
     {
     case PSPPIRE_VAR_STORE_COL_NAME:
-      return pspp_locale_to_utf8 ( var_get_name (pv), -1, err);
+      return recode_string (UTF8, psppire_dict_encoding (dict),
+                           var_get_name (pv), -1);
       break;
     case PSPPIRE_VAR_STORE_COL_TYPE:
       {
@@ -665,12 +669,13 @@ text_for_column (const struct variable *pv, gint c, GError **err)
       }
       break;
     case PSPPIRE_VAR_STORE_COL_LABEL:
-      return pspp_locale_to_utf8 (var_get_label (pv), -1, err);
+      return recode_string (UTF8, psppire_dict_encoding (dict),
+                           var_get_label (pv), -1);
       break;
 
     case PSPPIRE_VAR_STORE_COL_MISSING:
       {
-       return missing_values_to_string (pv, err);
+       return missing_values_to_string (dict, pv, err);
       }
       break;
     case PSPPIRE_VAR_STORE_COL_VALUES:
@@ -696,7 +701,8 @@ text_for_column (const struct variable *pv, gint c, GError **err)
 
            val_labs_done (&ip);
 
-           ss = pspp_locale_to_utf8 (gstr->str, gstr->len, err);
+           ss = recode_string (UTF8, psppire_dict_encoding (dict),
+                               gstr->str, gstr->len);
            g_string_free (gstr, TRUE);
            return ss;
          }
index 599d8108ddb7d8b91897eb6f16bf0cf27003ec1b..a1f48e7b64d016f1cee8c5fb4b13c2be0bcf6af4 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <config.h>
 
-#include <locale.h>
+#include <libpspp/i18n.h>
 #include <assert.h>
 #include <libintl.h>
 #include <gsl/gsl_errno.h>
@@ -89,12 +89,8 @@ initialize (struct command_line_processor *clp, int argc, char **argv)
 {
   PsppireDict *dictionary = 0;
 
-  /* gtk_init messes with the locale.
-     So unset the bits we want to control ourselves */
-  setlocale (LC_NUMERIC, "C");
-
-  bindtextdomain (PACKAGE, locale_dir);
 
+  i18n_init ();
 
   preregister_widgets ();
 
@@ -171,6 +167,7 @@ de_initialize (void)
   message_dialog_done ();
   settings_done ();
   outp_done ();
+  i18n_done ();
 }
 
 
index f6d0ab738b74270f508dab07ac82e6e852d132cf..42dd0b349c530c3f7a3d3daa5e970b78d541c0b1 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPPIRE - a graphical user interface for PSPP.
-   Copyright (C) 2005  Free Software Foundation
+   Copyright (C) 2005, 2009  Free Software Foundation
 
    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
 #include "val-labs-dialog.h"
 #include <data/value-labels.h>
 #include <data/format.h>
-
+#include "psppire-var-sheet.h"
+#include "psppire-var-store.h"
+#include <libpspp/i18n.h>
 
 struct val_labs_dialog
 {
   GtkWidget *window;
 
+  PsppireSheet *vs;
+
   /* The variable to be updated */
   struct variable *pv;
 
@@ -325,8 +329,7 @@ on_remove (GtkWidget *w, gpointer data)
 /* Callback which occurs when a line item is selected in the list of
    value--label pairs.*/
 static void
-on_select_row                  (GtkTreeView *treeview,
-                               gpointer data)
+on_select_row (GtkTreeView *treeview, gpointer data)
 {
   gchar *labeltext;
   struct val_labs_dialog *dialog = data;
@@ -336,6 +339,9 @@ on_select_row                  (GtkTreeView *treeview,
   gchar *const text = value_to_text (vl->value,
                                    *var_get_write_format (dialog->pv));
 
+  PsppireVarStore *var_store =
+    PSPPIRE_VAR_STORE (psppire_sheet_get_model (dialog->vs));
+
   g_signal_handler_block (GTK_ENTRY (dialog->value_entry),
                         dialog->value_handler_id);
 
@@ -348,7 +354,10 @@ on_select_row                  (GtkTreeView *treeview,
   g_signal_handler_block (GTK_ENTRY (dialog->label_entry),
                         dialog->change_handler_id);
 
-  labeltext = pspp_locale_to_utf8 (vl->label, -1, 0);
+
+  labeltext = recode_string (UTF8, psppire_dict_encoding (var_store->dict),
+                            vl->label, -1);
+
   gtk_entry_set_text (GTK_ENTRY (dialog->label_entry),
                     labeltext);
   g_free (labeltext);
@@ -364,7 +373,7 @@ on_select_row                  (GtkTreeView *treeview,
 /* Create a new dialog box
    (there should  normally be only one)*/
 struct val_labs_dialog *
-val_labs_dialog_create (GtkWindow *toplevel)
+val_labs_dialog_create (GtkWindow *toplevel, PsppireSheet *sheet)
 {
   GtkTreeViewColumn *column;
 
@@ -377,6 +386,7 @@ val_labs_dialog_create (GtkWindow *toplevel)
   dialog->window = get_widget_assert (xml,"val_labs_dialog");
   dialog->value_entry = get_widget_assert (xml,"value_entry");
   dialog->label_entry = get_widget_assert (xml,"label_entry");
+  dialog->vs = sheet;
 
   gtk_window_set_transient_for
     (GTK_WINDOW (dialog->window), toplevel);
@@ -461,6 +471,9 @@ repopulate_dialog (struct val_labs_dialog *dialog)
 
   GtkTreeIter iter;
 
+  PsppireVarStore *var_store =
+    PSPPIRE_VAR_STORE (psppire_sheet_get_model (dialog->vs));
+
   GtkListStore *list_store = gtk_list_store_new (2,
                                                 G_TYPE_STRING,
                                                 G_TYPE_DOUBLE);
@@ -489,11 +502,12 @@ repopulate_dialog (struct val_labs_dialog *dialog)
                      *var_get_write_format (dialog->pv));
 
       gchar *labeltext =
-       pspp_locale_to_utf8 (vl->label, -1, 0);
+       recode_string (UTF8,
+                      psppire_dict_encoding (var_store->dict),
+                      vl->label, -1);
 
       gchar *const text = g_strdup_printf ("%s = \"%s\"",
-                                         vstr, labeltext);
-
+                                          vstr, labeltext);
 
       gtk_list_store_append (list_store, &iter);
       gtk_list_store_set (list_store, &iter,
index 6b1d0e378b68ca04b95313c57864a3aeaaf277c6..3a09f1ca410e0f2f6b775741d9e62dde48e4aae7 100644 (file)
@@ -14,8 +14,6 @@
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
-
-
 #ifndef __PSPPIRE_VAL_LABS_DIALOG_H
 #define __PSPPIRE_VAL_LABS_DIALOG_H
 
 
 #include <gtk/gtk.h>
 #include <data/variable.h>
+#include <gtk-contrib/psppire-sheet.h>
 
 
 struct val_labs;
 
 
-struct val_labs_dialog * val_labs_dialog_create (GtkWindow *);
+struct val_labs_dialog * val_labs_dialog_create (GtkWindow *, PsppireSheet *);
 
 void val_labs_dialog_show (struct val_labs_dialog *);
 
index 07c7a4736ff08e8537d62182383592fc4aec0ec1..50e0df4bbc7ec360869195c387ce9c1deadda119 100644 (file)
@@ -4,34 +4,17 @@
 #include <data/variable.h>
 #include <data/format.h>
 #include <stdlib.h>
+#include "psppire-dict.h"
 
 #include <gettext.h>
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
 
 #include "helper.h"
+#include <libpspp/i18n.h>
 
 static const gchar none[] = N_("None");
 
-gchar *
-name_to_string (const struct variable *var, GError **err)
-{
-  const char *name = var_get_name (var);
-  g_assert (name);
-
-  return pspp_locale_to_utf8 (name, -1, err);
-}
-
-
-gchar *
-label_to_string (const struct variable *var, GError **err)
-{
-  const char *label = var_get_label (var);
-
-  if ( ! label ) return g_strdup (none);
-
-  return pspp_locale_to_utf8 (label, -1, err);
-}
 
 gchar *
 measure_to_string (const struct variable *var, GError **err)
@@ -45,7 +28,7 @@ measure_to_string (const struct variable *var, GError **err)
 
 
 gchar *
-missing_values_to_string (const struct variable *pv, GError **err)
+missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GError **err)
 {
   const struct fmt_spec *fmt =  var_get_print_format (pv);
   gchar *s;
@@ -70,7 +53,8 @@ missing_values_to_string (const struct variable *pv, GError **err)
              g_string_append (gstr, mv[i]);
              g_free (mv[i]);
            }
-         s = pspp_locale_to_utf8 (gstr->str, gstr->len, err);
+         s = recode_string (UTF8, psppire_dict_encoding (dict),
+                            gstr->str, gstr->len);
          g_string_free (gstr, TRUE);
        }
       else
@@ -99,7 +83,8 @@ missing_values_to_string (const struct variable *pv, GError **err)
              g_string_append (gstr, ss);
              free (ss);
            }
-         s = pspp_locale_to_utf8 (gstr->str, gstr->len, err);
+         s = recode_string (UTF8, psppire_dict_encoding (dict),
+                            gstr->str, gstr->len);
          g_string_free (gstr, TRUE);
        }
 
index 40404b896d1ae7be087830d39d5f5fbc4ab9b8df..927e235c21419d48e80875284412dd9268424f3e 100644 (file)
 
 #include <glib.h>
 #include <data/variable.h>
+#include "psppire-dict.h"
 
 struct variable;
 
 #define n_ALIGNMENTS 3
 
 extern const gchar *const alignments[n_ALIGNMENTS + 1];
-
 extern const gchar *const measures[n_MEASURES + 1];
 
-
-gchar * name_to_string (const struct variable *var, GError **err);
-
-
-gchar * missing_values_to_string (const struct variable *pv, GError **err);
-
-gchar * measure_to_string (const struct variable *var, GError **err);
-
-gchar * label_to_string (const struct variable *var, GError **err);
-
+gchar *missing_values_to_string (const PsppireDict *dict, const struct variable *pv, GError **err);
+gchar *measure_to_string (const struct variable *var, GError **err);
 
 #endif
index 612643b4351b4447f72b3b35449a1e63793dafd6..3b3367f75c7b6dafe7309ec1e1c31f7efc27cad3 100644 (file)
@@ -28,6 +28,7 @@
 #include "helper.h"
 
 #include <language/syntax-string-source.h>
+#include <libpspp/i18n.h>
 #include "helper.h"
 
 
 #define N_(msgid) msgid
 
 
+static const gchar none[] = N_("None");
+
+
+static gchar *
+name_to_string (const struct variable *var, PsppireDict *dict)
+{
+  const char *name = var_get_name (var);
+  g_assert (name);
+
+  return recode_string (UTF8, psppire_dict_encoding (dict),
+                       name, -1);
+}
+
+
+static gchar *
+label_to_string (const struct variable *var, PsppireDict *dict)
+{
+  const char *label = var_get_label (var);
+
+  if (! label) return g_strdup (none);
+
+  return recode_string (UTF8, psppire_dict_encoding (dict),
+                       label, -1);
+}
+
 
 static void
 populate_text (PsppireDictView *treeview, gpointer data)
 {
   gchar *text = 0;
   GString *gstring;
+  PsppireDict *dict;
 
-  GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(data));
+  GtkTextBuffer *textbuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (data));
   const struct variable *var =
     psppire_dict_view_get_selected_variable (treeview);
 
   if ( var == NULL)
     return;
 
+  g_object_get (treeview,
+               "dictionary", &dict,
+               NULL);
+
   gstring = g_string_sized_new (200);
-  text = name_to_string (var, NULL);
+  text = name_to_string (var, dict);
   g_string_assign (gstring, text);
   g_free (text);
   g_string_append (gstring, "\n");
 
 
-  text = label_to_string (var, NULL);
+  text = label_to_string (var, dict);
   g_string_append_printf (gstring, _("Label: %s\n"), text);
   g_free (text);
 
@@ -70,7 +101,7 @@ populate_text (PsppireDictView *treeview, gpointer data)
     g_string_append_printf (gstring, _("Type: %s\n"), buffer);
   }
 
-  text = missing_values_to_string (var, NULL);
+  text = missing_values_to_string (dict, var, NULL);
   g_string_append_printf (gstring, _("Missing Values: %s\n"),
                          text);
   g_free (text);
@@ -92,7 +123,6 @@ populate_text (PsppireDictView *treeview, gpointer data)
       g_string_append (gstring, "\n");
       g_string_append (gstring, _("Value Labels:\n"));
 
-#if 1
       for (vl = val_labs_first_sorted (labs, &vli);
           vl;
           vl = val_labs_next (labs, &vli))
@@ -100,14 +130,15 @@ populate_text (PsppireDictView *treeview, gpointer data)
          gchar *const vstr  =
            value_to_text (vl->value,  *var_get_print_format (var));
 
-         text = pspp_locale_to_utf8 (vl->label, -1, NULL);
+
+         text = recode_string (UTF8, psppire_dict_encoding (dict),
+                               vl->label, -1);
 
          g_string_append_printf (gstring, _("%s %s\n"), vstr, text);
 
          g_free (text);
          g_free (vstr);
        }
-#endif
     }
 
   gtk_text_buffer_set_text (textbuffer, gstring->str, gstring->len);
index e37cace39ec05af2527c6e23493689b46e75d75b..a1f201697193e04282e5726fc3b4493050fecbb1 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <config.h>
 
-#include <locale.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -30,6 +29,8 @@
 #include <ieeefp.h>
 #endif
 
+
+#include <libpspp/i18n.h>
 #include <data/dictionary.h>
 #include <data/file-handle-def.h>
 #include <libpspp/getl.h>
@@ -61,7 +62,6 @@
 #define _(msgid) gettext (msgid)
 
 
-static void i18n_init (void);
 static void fpu_init (void);
 static void clean_up (void);
 
@@ -166,21 +166,6 @@ main (int argc, char **argv)
   return any_errors ();
 }
 \f
-static void
-i18n_init (void)
-{
-#if ENABLE_NLS
-#if HAVE_LC_MESSAGES
-  setlocale (LC_MESSAGES, "");
-#endif
-#if HAVE_LC_PAPER
-  setlocale (LC_PAPER, "");
-#endif
-  bindtextdomain (PACKAGE, locale_dir);
-  textdomain (PACKAGE);
-#endif /* ENABLE_NLS */
-}
-
 static void
 fpu_init (void)
 {
@@ -234,5 +219,6 @@ clean_up (void)
       readln_uninitialize ();
       outp_done ();
       msg_ui_done ();
+      i18n_done ();
     }
 }
index 3456fba2e33f0791a7d2960eb6eb7d0b427947b1..bc11fa3a20ad6120b45901fd57d79995c7255158 100755 (executable)
@@ -99,6 +99,7 @@ Cases:          3
 Type:           System File.
 Weight:         Not weighted.
 Mode:           Compression on.
+Charset:        Unknown
 +--------+-------------+---+
 |Variable|Description  |Pos|
 |        |             |iti|
index 25d01158ee77b1c80062f8c6689f7a5f0fb608fa..1c81c72c98b089c3cb5dd6639c695acd64bedd01 100644 (file)
@@ -66,6 +66,9 @@ static void read_datafile_attributes (struct sfm_reader *r,
                                       size_t size, size_t count);
 static void read_variable_attributes (struct sfm_reader *r,
                                       size_t size, size_t count);
+static void read_character_encoding (struct sfm_reader *r,
+                                      size_t size, size_t count);
+
 
 static struct text_record *open_text_record (
   struct sfm_reader *, size_t size);
@@ -510,6 +513,10 @@ read_extension_record (struct sfm_reader *r)
       read_variable_attributes (r, size, count);
       return;
 
+    case 20:
+      read_character_encoding (r, size, count);
+      return;
+
     default:
       sys_warn (r, _("Unrecognized record type 7, subtype %d."), subtype);
       break;
@@ -712,6 +719,17 @@ read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count)
   close_text_record (text);
 }
 
+static void
+read_character_encoding (struct sfm_reader *r, size_t size, size_t count)
+{
+  const unsigned long int posn =  ftell (r->file);
+  char *encoding = calloc (size, count + 1);
+  read_string (r, encoding, count + 1);
+
+  printf ("%08lx: Character Encoding: %s\n", posn, encoding);
+}
+
+
 static void
 read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) 
 {