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 |
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 |
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 |
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 | { |
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 |
120 | static |
121 | void free_static_C_locale () |
122 | { |
123 | static_C_locale.free_instance (); |
124 | } |
125 | #endif |
126 | |
127 | static HB_LOCALE_T |
128 | get_C_locale () |
129 | { |
130 | return static_C_locale.get_unconst (); |
131 | } |
132 | #endif /* USE_XLOCALE */ |
133 | |
134 | bool |
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 | |