/src/openbabel/src/locale.cpp
Line | Count | Source |
1 | | /********************************************************************** |
2 | | locale.cpp - Handle internal numeric locale issues -- parse data in "C" |
3 | | |
4 | | Copyright (C) 2008 by Geoffrey R. Hutchison |
5 | | |
6 | | This file is part of the Open Babel project. |
7 | | For more information, see <http://openbabel.org/> |
8 | | |
9 | | This program is free software; you can redistribute it and/or modify |
10 | | it under the terms of the GNU General Public License as published by |
11 | | the Free Software Foundation version 2 of the License. |
12 | | |
13 | | This program is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | ***********************************************************************/ |
18 | | |
19 | | #include <cstdlib> |
20 | | #include <cstring> |
21 | | #include <openbabel/locale.h> |
22 | | |
23 | | #if HAVE_XLOCALE_H |
24 | | #include <xlocale.h> |
25 | | #endif |
26 | | #if HAVE_LOCALE_H |
27 | | #include <locale.h> |
28 | | #endif |
29 | | |
30 | | namespace OpenBabel |
31 | | { |
32 | | class OBLocalePrivate { |
33 | | public: |
34 | | char *old_locale_string; |
35 | | #if HAVE_USELOCALE |
36 | | locale_t new_c_num_locale; |
37 | | locale_t old_locale; |
38 | | #endif |
39 | | unsigned int counter; // Reference counter -- ensures balance in SetLocale/RestoreLocale calls |
40 | | |
41 | 6 | OBLocalePrivate(): counter(0) |
42 | 6 | { |
43 | | #if HAVE_USELOCALE |
44 | | new_c_num_locale = newlocale(LC_NUMERIC_MASK, NULL, NULL); |
45 | | #endif |
46 | 6 | } |
47 | | |
48 | | ~OBLocalePrivate() |
49 | 0 | { } |
50 | | }; // class definition for OBLocalePrivate |
51 | | |
52 | | /** \class OBLocale locale.h <openbabel/locale.h> |
53 | | * |
54 | | * Many users will utilize Open Babel and tools built on top of the library |
55 | | * in non-English locales. In particular, the numeric locale (LC_NUMERIC) |
56 | | * is used to determine the parsing of numeric data in files, reference data, |
57 | | * etc. |
58 | | * |
59 | | * The OBLocale class, and its global variable obLocale handle both internal |
60 | | * parsing of data through the ANSI-C numeric locale and can be used for |
61 | | * external use as well. |
62 | | * |
63 | | * In particular, where available, OBLocale will use the enhanced uselocale() |
64 | | * interface, which sets the locale for a particular thread, rather |
65 | | * for the entire process. (This is available on Linux, Mac OS X, |
66 | | * and other platforms.) |
67 | | * |
68 | | * \code |
69 | | * obLocale.SetLocale(); // set the numeric locale before reading data |
70 | | * ... // your data processing here |
71 | | * obLocale.RestoreLocale(); // restore the numeric locale |
72 | | * \endcode |
73 | | * |
74 | | * To prevent errors, OBLocale will handle reference counting. |
75 | | * If nested function calls all set the locale, only the first call |
76 | | * to SetLocale() and the last call to RestoreLocale() will do any work. |
77 | | **/ |
78 | | |
79 | | OBLocale::OBLocale() |
80 | 6 | { |
81 | 6 | d = new OBLocalePrivate; |
82 | 6 | } |
83 | | |
84 | | OBLocale::~OBLocale() |
85 | 0 | { |
86 | 0 | if (d) { |
87 | 0 | delete d; |
88 | 0 | d = nullptr; |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | | void OBLocale::SetLocale() |
93 | 8.36k | { |
94 | 8.36k | if (d->counter == 0) { |
95 | | // Set the locale for number parsing to avoid locale issues: PR#1785463 |
96 | | #if HAVE_USELOCALE |
97 | | // Extended per-thread interface |
98 | | d->old_locale = uselocale(d->new_c_num_locale); |
99 | | #else |
100 | 8.36k | #ifndef ANDROID |
101 | | // Original global POSIX interface |
102 | | // regular UNIX, no USELOCALE, no ANDROID |
103 | 8.36k | d->old_locale_string = strdup(setlocale(LC_NUMERIC, nullptr)); |
104 | | #else |
105 | | // ANDROID should stay as "C" -- Igor Filippov |
106 | | d->old_locale_string = "C"; |
107 | | #endif |
108 | 8.36k | setlocale(LC_NUMERIC, "C"); |
109 | 8.36k | #endif |
110 | 8.36k | } |
111 | | |
112 | 8.36k | ++d->counter; |
113 | 8.36k | } |
114 | | |
115 | | void OBLocale::RestoreLocale() |
116 | 8.36k | { |
117 | 8.36k | --d->counter; |
118 | 8.36k | if(d->counter == 0) { |
119 | | // return the locale to the original one |
120 | | #ifdef HAVE_USELOCALE |
121 | | uselocale(d->old_locale); |
122 | | #else |
123 | 8.36k | setlocale(LC_NUMERIC, d->old_locale_string); |
124 | 8.36k | #ifndef ANDROID |
125 | | // Don't free on Android because "C" is a static ctring constant |
126 | 8.36k | free (d->old_locale_string); |
127 | 8.36k | #endif |
128 | 8.36k | #endif |
129 | 8.36k | } |
130 | 8.36k | } |
131 | | |
132 | | //global definitions |
133 | | // Global OBLocale for setting and restoring locale information |
134 | | OBLocale obLocale; |
135 | | |
136 | | } // namespace OpenBabel |
137 | | |
138 | | //! \file locale.cpp |
139 | | //! \brief Handle internal numeric locale issues -- parse data in "C" |