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
35 template<typename T, typename Func>
36 static bool
_parse_number(const char ** pp,const char * end,T * pv,bool whole_buffer,Func f)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
59 bool
hb_parse_int(const char ** pp,const char * end,int * pv,bool whole_buffer)60 hb_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
67 bool
hb_parse_uint(const char ** pp,const char * end,unsigned int * pv,bool whole_buffer,int base)68 hb_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
93 static void free_static_C_locale ();
94 #endif
95
96 static 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 {
createhb_C_locale_lazy_loader_t99 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 }
destroyhb_C_locale_lazy_loader_t109 static void destroy (HB_LOCALE_T p)
110 {
111 HB_FREE_LOCALE (p);
112 }
get_nullhb_C_locale_lazy_loader_t113 static HB_LOCALE_T get_null ()
114 {
115 return nullptr;
116 }
117 } static_C_locale;
118
119 #if HB_USE_ATEXIT
120 static
free_static_C_locale()121 void free_static_C_locale ()
122 {
123 static_C_locale.free_instance ();
124 }
125 #endif
126
127 static HB_LOCALE_T
get_C_locale()128 get_C_locale ()
129 {
130 return static_C_locale.get_unconst ();
131 }
132 #endif /* USE_XLOCALE */
133
134 bool
hb_parse_double(const char ** pp,const char * end,double * pv,bool whole_buffer)135 hb_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