Coverage Report

Created: 2025-11-09 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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"