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