1/*
2 * Copyright © 2019 Ebrahim Byagowi
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 */
25
26#include "hb.hh"
27#include "hb-machinery.hh"
28#include "hb-number-parser.hh"
29
30#include <locale.h>
31#ifdef HAVE_XLOCALE_H
32#include <xlocale.h>
33#endif
34
35template<typename T, typename Func>
36static bool
37_parse_number (const char **pp, const char *end, T *pv,
38 bool whole_buffer, Func f)
39{
40 char buf[32];
41 unsigned int len = hb_min (ARRAY_LENGTH (buf) - 1,
42 (unsigned int) (end - *pp));
43 strncpy (buf, *pp, len);
44 buf[len] = '\0';
45
46 char *p = buf;
47 char *pend = p;
48
49 errno = 0;
50 *pv = f (p, &pend);
51 if (unlikely (errno || p == pend ||
52 /* Check if consumed whole buffer if is requested */
53 (whole_buffer && pend - p != end - *pp))) return false;
54
55 *pp += pend - p;
56 return true;
57}
58
59bool
60hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
61{
62 return _parse_number<int> (pp, end, pv, whole_buffer,
63 [] (const char *p, char **end)
64 { return strtol (p, end, 10); });
65}
66
67bool
68hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
69 bool whole_buffer, int base)
70{
71 return _parse_number<unsigned int> (pp, end, pv, whole_buffer,
72 [base] (const char *p, char **end)
73 { return strtoul (p, end, base); });
74}
75
76
77#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
78#define USE_XLOCALE 1
79#define HB_LOCALE_T locale_t
80#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
81#define HB_FREE_LOCALE(loc) freelocale (loc)
82#elif defined(_MSC_VER)
83#define USE_XLOCALE 1
84#define HB_LOCALE_T _locale_t
85#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
86#define HB_FREE_LOCALE(loc) _free_locale (loc)
87#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
88#endif
89
90#ifdef USE_XLOCALE
91
92#if HB_USE_ATEXIT
93static void free_static_C_locale ();
94#endif
95
96static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<HB_LOCALE_T>,
97 hb_C_locale_lazy_loader_t>
98{
99 static HB_LOCALE_T create ()
100 {
101 HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
102
103#if HB_USE_ATEXIT
104 atexit (free_static_C_locale);
105#endif
106
107 return C_locale;
108 }
109 static void destroy (HB_LOCALE_T p)
110 {
111 HB_FREE_LOCALE (p);
112 }
113 static HB_LOCALE_T get_null ()
114 {
115 return nullptr;
116 }
117} static_C_locale;
118
119#if HB_USE_ATEXIT
120static
121void free_static_C_locale ()
122{
123 static_C_locale.free_instance ();
124}
125#endif
126
127static HB_LOCALE_T
128get_C_locale ()
129{
130 return static_C_locale.get_unconst ();
131}
132#endif /* USE_XLOCALE */
133
134bool
135hb_parse_double (const char **pp, const char *end, double *pv,
136 bool whole_buffer)
137{
138 return _parse_number<double> (pp, end, pv, whole_buffer,
139 [] (const char *p, char **end)
140 {
141#ifdef USE_XLOCALE
142 return strtod_l (p, end, get_C_locale ());
143#else
144 return strtod_rl (p, end);
145#endif
146 });
147}
148