Locales, or: The Infamous 2,17 Problem.

``Warning: need lyxformat 2,17 but found 2,00'' plagues every user with
funny (<g>) LC_NUMERIC.  As everyone know, the .lyx file must be
read/written in the C locale to have its \lyxformat correctly formatted.

For writing, this is already half-done: if the library have <locale>,
the file is written correctly.  For reading, it's a quarter done; I mean
"2,17" is converted to "2.17" and then interpreted---according to the
current locale.

Furthermore, there are two sorts of locale setting functions: the C
setlocale(), which is global, and the C++ many ways (either local setting
for a stream or global setting that affect future streams and C
library functions).  While lyx is (of course) to use the C++ locales, they
are as yet not well supported.

So, what to do?

1. The quickest fix: setlocale(LC_NUMERIC,"C") in main.  I believe it's
what's done in 1.1.5?

2. A better fix: temporary switching to the "C" locale when reading/writing
files.
In this case, should it use setlocale, locale::global or .imbue?
setlocale is the only option when <locale> is not available.  In the later
case, imbuing the stream looks like the right thing---but there's a catch.
lex.getFloat() uses strToDbl(), which calls ::atof...  See the can of
worms open (-:

I've implemented my #2 proposition.  It adds a small header file (~100 lines
with lots of whitespace) defining a hidding-the-#ifdefs class. It is
instancied in buffer.C (writeFile) and lyxlex_pimpl.C (constructor, setFile,
setStream).

What do you LyXperts think?

-- 
        Stid
Index: src/BufferView2.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/BufferView2.C,v
retrieving revision 1.46
diff -u -r1.46 BufferView2.C
--- src/BufferView2.C   2000/10/30 12:03:18     1.46
+++ src/BufferView2.C   2000/11/03 15:19:48
@@ -31,6 +31,7 @@
 #include "LaTeX.h"
 #include "BufferView_pimpl.h"
 #include "insets/insetcommand.h" //ChangeRefs
+#include "CLocale.h"
 
 extern BufferList bufferlist;
 
Index: src/Makefile.am
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/Makefile.am,v
retrieving revision 1.63
diff -u -r1.63 Makefile.am
--- src/Makefile.am     2000/11/02 04:48:33     1.63
+++ src/Makefile.am     2000/11/03 15:19:48
@@ -32,6 +32,7 @@
        Bullet.h \
        Chktex.C \
        Chktex.h \
+       CLocale.h \
        ColorHandler.C \
        ColorHandler.h \
        CutAndPaste.C \
Index: src/buffer.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/buffer.C,v
retrieving revision 1.148
diff -u -r1.148 buffer.C
--- src/buffer.C        2000/10/27 10:04:49     1.148
+++ src/buffer.C        2000/11/03 15:19:49
@@ -24,10 +24,6 @@
 
 #include <algorithm>
 
-#ifdef HAVE_LOCALE
-#include <locale>
-#endif
-
 #ifdef __GNUG__
 #pragma implementation "buffer.h"
 #endif
@@ -93,6 +89,7 @@
 #include "encoding.h"
 #include "exporter.h"
 #include "Lsstream.h"
+#include "CLocale.h"
 
 using std::ostream;
 using std::ofstream;
@@ -1206,10 +1203,8 @@
                return false;
        }
 
-#ifdef HAVE_LOCALE
        // Use the standard "C" locale for file output.
-       ofs.imbue(std::locale::classic());
-#endif
+       CLocale c_locale(ofs);
 
        // The top of the file should not be written by params.
 
Index: src/lyxlex_pimpl.C
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxlex_pimpl.C,v
retrieving revision 1.9
diff -u -r1.9 lyxlex_pimpl.C
--- src/lyxlex_pimpl.C  2000/10/11 21:06:41     1.9
+++ src/lyxlex_pimpl.C  2000/11/03 15:19:49
@@ -30,7 +30,8 @@
 
 LyXLex::Pimpl::Pimpl(keyword_item * tab, int num) 
        : is(&fb__), table(tab), no_items(num),
-         status(0), lineno(0)
+         status(0), lineno(0),
+         c_locale(is)
 {
        verifyTable();
 }
@@ -115,6 +116,7 @@
                        "file or stream already set." << endl;
        fb__.open(filename.c_str(), ios::in);
        is.rdbuf(&fb__);
+       c_locale.imbue(is);     // Is this necessary again (<[EMAIL PROTECTED]>)?
        name = filename;
        lineno = 0;
        return fb__.is_open() && is.good();
@@ -127,6 +129,7 @@
                lyxerr[Debug::LYXLEX]  << "Error in LyXLex::setStream: "
                        "file or stream already set." << endl;
        is.rdbuf(i.rdbuf());
+       c_locale.imbue(is);     // Is this necessary again (<[EMAIL PROTECTED]>)?
        lineno = 0;
 }
 
@@ -462,3 +465,4 @@
 {
        pushTok = pt;
 }
+
Index: src/lyxlex_pimpl.h
===================================================================
RCS file: /usr/local/lyx/cvsroot/lyx-devel/src/lyxlex_pimpl.h,v
retrieving revision 1.5
diff -u -r1.5 lyxlex_pimpl.h
--- src/lyxlex_pimpl.h  2000/08/05 05:17:17     1.5
+++ src/lyxlex_pimpl.h  2000/11/03 15:19:49
@@ -7,6 +7,7 @@
 #include <stack>
 
 #include "lyxlex.h"
+#include "CLocale.h"
 
 #ifdef __GNUG__
 #pragma interface
@@ -84,5 +85,7 @@
        };
        ///
        std::stack<pushed_table> pushed;
+
+       CLocale c_locale;
 };
 #endif
===================================================================
--- src/CLocale.h       Fri Nov  3 16:16:52 2000
+++ src/CLocale.h       Fri Nov  3 16:13:15 2000
@@ -0,0 +1,113 @@
+// -*- C++ -*-
+/* This file might become part of
+ * ====================================================== 
+ * 
+ *           LyX, The Document Processor        
+ *           Copyright 1995 Matthias Ettrich
+ *
+ * ====================================================== */
+
+#ifndef CLOCALE_H
+#define CLOCALE_H
+
+#include <config.h>
+
+#include <iostream>
+#include "LString.h"
+
+/** The clocale object.
+    This is the clocale object.  Its only use is to select the "C"
+    locale for loading and saving files.  The implementation differs
+    whether C++ locales are available or not.
+*/
+class CLocale {
+public:
+       /** clocale constructors.
+           For C++ locales, the constructor just call imbue.
+           For C locales, it first save the current locale.
+       */
+       CLocale(std::istream &fs);
+       CLocale(std::ostream &fs);
+
+       /** imbue.
+           These functions either imbue a (i|o)stream with the "C"
+           locale (the C++ way), or globally set it (the C way).
+       */
+       void imbue(std::istream &fs);
+       void imbue(std::ostream &fs);
+
+       /** clocale destructor.
+           The destructor does nothing in the C++ case.  In the C
+           case, it resets the global locale.
+       */
+       ~CLocale();
+private:
+#if !defined(HAVE_LOCALE) || !defined(NO_MORE_WILD_ATOF)
+       string previous_locale;
+#endif
+};
+
+
+#if defined(HAVE_LOCALE) && defined(NO_MORE_WILD_ATOF)
+
+#include <locale>
+
+inline CLocale::CLocale(std::istream &fs)
+{
+       imbue(fs);
+}
+
+inline CLocale::CLocale(std::ostream &fs)
+{
+       imbue(fs);
+}
+
+inline void CLocale::imbue(std::istream &fs)
+{
+       fs.imbue(std::locale::classic());
+}
+
+inline void CLocale::imbue(std::ostream &fs)
+{
+       fs.imbue(std::locale::classic());
+}
+
+inline CLocale::~CLocale()
+{
+}
+
+#else
+
+// Old-style header: we don't want to play the ``is-this-in-std'' game.
+#include <locale.h>
+
+inline CLocale::CLocale(std::istream &fs)
+{
+       previous_locale=setlocale(LC_ALL,0);
+       imbue(fs);
+}
+
+inline CLocale::CLocale(std::ostream &fs)
+{
+       previous_locale=setlocale(LC_ALL,0);
+       imbue(fs);
+}
+
+inline void CLocale::imbue(std::istream &)
+{
+       setlocale(LC_ALL,"C");
+}
+
+inline void CLocale::imbue(std::ostream &)
+{
+       setlocale(LC_ALL,"C");
+}
+
+inline CLocale::~CLocale()
+{
+       setlocale(LC_ALL,previous_locale.c_str());
+}
+
+#endif
+
+#endif

Reply via email to