183f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod/*
22409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Copyright © 2009,2010  Red Hat, Inc.
3cad3821f3d5b68d490b0728bd37bd57428ec809cBehdad Esfahbod * Copyright © 2011,2012  Google, Inc.
483f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *
583f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *  This is part of HarfBuzz, a text shaping library.
683f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *
783f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * Permission is hereby granted, without written agreement and without
883f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * license or royalty fees, to use, copy, modify, and distribute this
983f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * software and its documentation for any purpose, provided that the
1083f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * above copyright notice and the following two paragraphs appear in
1183f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * all copies of this software.
1283f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *
1383f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
1483f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
1583f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
1683f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
1783f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * DAMAGE.
1883f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *
1983f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
2083f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
2183f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
2283f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
2383f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
2483f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod *
2583f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod * Red Hat Author(s): Behdad Esfahbod
262409d5f8d7dd8b535ce5ea29e933f7db27d33793Behdad Esfahbod * Google Author(s): Behdad Esfahbod
2783f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod */
2883f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod
29c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod#include "hb-private.hh"
3083f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod
31b8d6183ebc4697a434776cf2aec7857d63a7d881Behdad Esfahbod#include "hb-mutex-private.hh"
32218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod#include "hb-object-private.hh"
33b8d6183ebc4697a434776cf2aec7857d63a7d881Behdad Esfahbod
3434fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod#include <locale.h>
3534fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod
36acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
37bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod/* hb_options_t */
38bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod
39bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbodhb_options_union_t _hb_options;
40bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod
41bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbodvoid
42bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod_hb_options_init (void)
43bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod{
44bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  hb_options_union_t u;
45bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  u.i = 0;
46bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  u.opts.initialized = 1;
47bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod
48bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  char *c = getenv ("HB_OPTIONS");
49bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
50bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod
51bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  /* This is idempotent and threadsafe. */
52bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod  _hb_options = u;
53bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod}
54bab02d339f39ed5168daaef9461227f78e596a2fBehdad Esfahbod
55acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
568e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod/* hb_tag_t */
578e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
5870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
5970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_tag_from_string:
60a394bb66707184c995fe2d08c80e98220e6ec0b0Khaled Hosny * @str: (array length=len) (element-type uint8_t):
6170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @len:
6270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
6370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
6470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
6570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
6670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
67b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
6870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
6983f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbodhb_tag_t
7070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbodhb_tag_from_string (const char *str, int len)
7183f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod{
7283f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod  char tag[4];
7383f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod  unsigned int i;
7483f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod
7570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod  if (!str || !len || !*str)
767ff7401c9237cda661869c1cb196d685706ac4e9Behdad Esfahbod    return HB_TAG_NONE;
777ff7401c9237cda661869c1cb196d685706ac4e9Behdad Esfahbod
784c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod  if (len < 0 || len > 4)
794c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod    len = 4;
8070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod  for (i = 0; i < (unsigned) len && str[i]; i++)
8170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod    tag[i] = str[i];
8283f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod  for (; i < 4; i++)
8383f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod    tag[i] = ' ';
8483f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod
8507233581c9d953708d3c020907c42b8b89472b89Behdad Esfahbod  return HB_TAG_CHAR4 (tag);
8683f34677bcbc6bb194940407b0fcb23575650e3dBehdad Esfahbod}
87acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
8870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
8970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_tag_to_string:
9070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @tag:
91e4d451ee55a57e1231b4076fcd1e87994f6b9528Khaled Hosny * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t):
9270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
9370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
9470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
9501c3a88543850c87483fd8671044df53b368c520Sascha Brawer * Since: 0.9.5
9670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
97e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodvoid
98e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbodhb_tag_to_string (hb_tag_t tag, char *buf)
99e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod{
100e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  buf[0] = (char) (uint8_t) (tag >> 24);
101e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  buf[1] = (char) (uint8_t) (tag >> 16);
102e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  buf[2] = (char) (uint8_t) (tag >>  8);
103e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod  buf[3] = (char) (uint8_t) (tag >>  0);
104e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod}
105e30ebd2794b37bd8ec716a258d5cb017fb1dfadcBehdad Esfahbod
106acdba3f90b232fc12fcb200dca2584481b339118Behdad Esfahbod
10739a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod/* hb_direction_t */
10839a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
10939a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbodconst char direction_strings[][4] = {
11039a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  "ltr",
11139a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  "rtl",
11239a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  "ttb",
11339a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  "btt"
11439a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod};
11539a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
11670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
11770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_direction_from_string:
118a394bb66707184c995fe2d08c80e98220e6ec0b0Khaled Hosny * @str: (array length=len) (element-type uint8_t):
11970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @len:
12070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
12170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
12270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
12370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
12470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
125b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
12670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
12739a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbodhb_direction_t
1284c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbodhb_direction_from_string (const char *str, int len)
12939a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod{
1304c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod  if (unlikely (!str || !len || !*str))
13139a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod    return HB_DIRECTION_INVALID;
13239a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
13339a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  /* Lets match loosely: just match the first letter, such that
13439a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod   * all of "ltr", "left-to-right", etc work!
13539a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod   */
13639a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  char c = TOLOWER (str[0]);
13739a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  for (unsigned int i = 0; i < ARRAY_LENGTH (direction_strings); i++)
13839a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod    if (c == direction_strings[i][0])
1394bf90f648313e35d21b427a956aa1fe762bae757Behdad Esfahbod      return (hb_direction_t) (HB_DIRECTION_LTR + i);
14039a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
14139a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  return HB_DIRECTION_INVALID;
14239a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod}
14339a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
14470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
14570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_direction_to_string:
14670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @direction:
14770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
14870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
14970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
15070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value: (transfer none):
15170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
152b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
15370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
15439a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbodconst char *
15539a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbodhb_direction_to_string (hb_direction_t direction)
15639a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod{
1574bf90f648313e35d21b427a956aa1fe762bae757Behdad Esfahbod  if (likely ((unsigned int) (direction - HB_DIRECTION_LTR)
1584bf90f648313e35d21b427a956aa1fe762bae757Behdad Esfahbod	      < ARRAY_LENGTH (direction_strings)))
1594bf90f648313e35d21b427a956aa1fe762bae757Behdad Esfahbod    return direction_strings[direction - HB_DIRECTION_LTR];
16039a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
16139a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod  return "invalid";
16239a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod}
16339a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
16439a840ae65327b173e6eb1bb291e235a8305d7a1Behdad Esfahbod
1658e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod/* hb_language_t */
1668e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
1671bc1cb3603167f5da309336f7018c8b0608ac104Behdad Esfahbodstruct hb_language_impl_t {
1683cbdf70e0a92f1c24e16c0d4dcfbec4ac59a77a3Behdad Esfahbod  const char s[1];
1693cbdf70e0a92f1c24e16c0d4dcfbec4ac59a77a3Behdad Esfahbod};
1703cbdf70e0a92f1c24e16c0d4dcfbec4ac59a77a3Behdad Esfahbod
1718e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodstatic const char canon_map[256] = {
1728e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
1738e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,   0,   0,   0,
1748e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod   0,   0,   0,   0,   0,   0,   0,   0,    0,   0,   0,   0,   0,  '-',  0,   0,
1758e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  '0', '1', '2', '3', '4', '5', '6', '7',  '8', '9',  0,   0,   0,   0,   0,   0,
1768e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1778e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,  '-',
1788e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod   0,  'a', 'b', 'c', 'd', 'e', 'f', 'g',  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1798e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  'x', 'y', 'z',  0,   0,   0,   0,   0
1808e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod};
1818e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
182f3b170bdd970e31e9dbfed94c07c3cda41269aedBehdad Esfahbodstatic bool
183093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodlang_equal (hb_language_t  v1,
184093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod	    const void    *v2)
1858e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod{
186c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod  const unsigned char *p1 = (const unsigned char *) v1;
187c57d454accff66e5f2c58006e8fb40bc020b6182Behdad Esfahbod  const unsigned char *p2 = (const unsigned char *) v2;
1888e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
189093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  while (*p1 && *p1 == canon_map[*p2])
190093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    p1++, p2++;
1918e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
192093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  return *p1 == canon_map[*p2];
1938e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod}
1948e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
1958e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod#if 0
1968e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodstatic unsigned int
1978e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodlang_hash (const void *key)
1988e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod{
1998e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  const unsigned char *p = key;
2008e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  unsigned int h = 0;
2018e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  while (canon_map[*p])
2028e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod    {
2038e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod      h = (h << 5) - h + canon_map[*p];
2048e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod      p++;
2058e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod    }
2068e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
2078e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod  return h;
2088e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod}
2098e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod#endif
2108e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
2118e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
212b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbodstruct hb_language_item_t {
213b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
214093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  struct hb_language_item_t *next;
215b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod  hb_language_t lang;
216b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
217b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod  inline bool operator == (const char *s) const {
218b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod    return lang_equal (lang, s);
219b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod  }
220b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
221b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod  inline hb_language_item_t & operator = (const char *s) {
222b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod    lang = (hb_language_t) strdup (s);
223b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod    for (unsigned char *p = (unsigned char *) lang; *p; p++)
224b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod      *p = canon_map[*p];
225b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
226b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod    return *this;
227b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod  }
228b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
229cd361c3cbe4a288e3019b9a029f44e4c5f24436cBehdad Esfahbod  void finish (void) { free ((void *) lang); }
230b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod};
231b45f32ee4e599c515ce93e44315283d236b073bbBehdad Esfahbod
232093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
233093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod/* Thread-safe lock-free language list */
234093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
235093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodstatic hb_language_item_t *langs;
236093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
23738fb30d7420a4b01f99cee31baa8c3990a1d1c5fBehdad Esfahbod#ifdef HB_USE_ATEXIT
238fb85d618f5883458bacf0ecb0894772291a2d738Chris Petersonstatic
239093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodvoid free_langs (void)
240093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod{
241093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  while (langs) {
242093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    hb_language_item_t *next = langs->next;
243093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    langs->finish ();
244093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    free (langs);
245093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    langs = next;
246093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  }
247093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod}
2480082dbeae6c25a7859960b7e791a540ad04246d9jfkthame#endif
249093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
250093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodstatic hb_language_item_t *
251093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodlang_find_or_insert (const char *key)
252093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod{
253093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbodretry:
254093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  hb_language_item_t *first_lang = (hb_language_item_t *) hb_atomic_ptr_get (&langs);
255093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
256093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  for (hb_language_item_t *lang = first_lang; lang; lang = lang->next)
257093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    if (*lang == key)
258093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod      return lang;
259093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
260093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  /* Not found; allocate one. */
261093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
262093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  if (unlikely (!lang))
263093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    return NULL;
264093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  lang->next = first_lang;
265093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  *lang = key;
266093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
267093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  if (!hb_atomic_ptr_cmpexch (&langs, first_lang, lang)) {
268675956aca01fc4e005a338af43d1c1f4f938abd1Konstantin Ritt    lang->finish ();
269093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    free (lang);
270093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod    goto retry;
271093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  }
272093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
27338fb30d7420a4b01f99cee31baa8c3990a1d1c5fBehdad Esfahbod#ifdef HB_USE_ATEXIT
27404aed572f112b96a6033cd6c3df7bdba5e29e93cBehdad Esfahbod  if (!first_lang)
27504aed572f112b96a6033cd6c3df7bdba5e29e93cBehdad Esfahbod    atexit (free_langs); /* First person registers atexit() callback. */
276093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod#endif
277093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
278093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod  return lang;
279093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod}
280093171cceca63e48e735bbf05a2c11b1b7e95ef1Behdad Esfahbod
281b8d6183ebc4697a434776cf2aec7857d63a7d881Behdad Esfahbod
28270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
28370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_language_from_string:
2848ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @str: (array length=len) (element-type uint8_t): a string representing
2858ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny *       ISO 639 language code
2868ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @len: length of the @str, or -1 if it is %NULL-terminated.
28770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
2888ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * Converts @str representing an ISO 639 language code to the corresponding
2898ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * #hb_language_t.
29070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
29104f89e8f7dfdb882e8c98afb613cba3f1d02ed7dKhaled Hosny * Return value: (transfer none):
2928ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * The #hb_language_t corresponding to the ISO 639 language code.
29370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
294b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
29570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
2968e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodhb_language_t
2974c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbodhb_language_from_string (const char *str, int len)
2988e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod{
2994c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod  if (!str || !len || !*str)
3001a64f6e19a4b483e278c85e4941107be2f71b0a4Behdad Esfahbod    return HB_LANGUAGE_INVALID;
3018e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
302f3159ba5141c2ab0e430e64742972df140f91c43Behdad Esfahbod  hb_language_item_t *item = NULL;
30348360ec03b225dfec5f90bc5cb93122203d2dd6bBehdad Esfahbod  if (len >= 0)
30448360ec03b225dfec5f90bc5cb93122203d2dd6bBehdad Esfahbod  {
305dac86026a6bae5a8a03cfe885bf93f32e5f48614Behdad Esfahbod    /* NUL-terminate it. */
306f3159ba5141c2ab0e430e64742972df140f91c43Behdad Esfahbod    char strbuf[64];
3074c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod    len = MIN (len, (int) sizeof (strbuf) - 1);
308dac86026a6bae5a8a03cfe885bf93f32e5f48614Behdad Esfahbod    memcpy (strbuf, str, len);
3094c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod    strbuf[len] = '\0';
310f3159ba5141c2ab0e430e64742972df140f91c43Behdad Esfahbod    item = lang_find_or_insert (strbuf);
3114c9fe88d30036340fe592bcbc375049b84602b8bBehdad Esfahbod  }
312f3159ba5141c2ab0e430e64742972df140f91c43Behdad Esfahbod  else
313f3159ba5141c2ab0e430e64742972df140f91c43Behdad Esfahbod    item = lang_find_or_insert (str);
3148e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
3151a64f6e19a4b483e278c85e4941107be2f71b0a4Behdad Esfahbod  return likely (item) ? item->lang : HB_LANGUAGE_INVALID;
3168e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod}
3178e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
31870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
31970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_language_to_string:
3208ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @language: an #hb_language_t to convert.
32170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
3228ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * See hb_language_from_string().
32370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
3248ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * Return value: (transfer none):
3258ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * A %NULL-terminated string representing the @language. Must not be freed by
3268ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * the caller.
32770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
328b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
32970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
3308e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodconst char *
3318e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbodhb_language_to_string (hb_language_t language)
3328e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod{
3331a64f6e19a4b483e278c85e4941107be2f71b0a4Behdad Esfahbod  /* This is actually NULL-safe! */
3343cbdf70e0a92f1c24e16c0d4dcfbec4ac59a77a3Behdad Esfahbod  return language->s;
3358e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod}
3368e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
33770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
33870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_language_get_default:
33970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
34070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
34170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
342351f68f4e01a107f62e4eb3458d7c7ae379939fbBehdad Esfahbod * Return value: (transfer none):
34370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
344b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
34570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
34634fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbodhb_language_t
34734fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbodhb_language_get_default (void)
34834fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod{
3497e7d245b332306949a19c628bacd920717434769Behdad Esfahbod  static hb_language_t default_language = HB_LANGUAGE_INVALID;
35034fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod
3517e7d245b332306949a19c628bacd920717434769Behdad Esfahbod  hb_language_t language = (hb_language_t) hb_atomic_ptr_get (&default_language);
3527e7d245b332306949a19c628bacd920717434769Behdad Esfahbod  if (unlikely (language == HB_LANGUAGE_INVALID)) {
3537e7d245b332306949a19c628bacd920717434769Behdad Esfahbod    language = hb_language_from_string (setlocale (LC_CTYPE, NULL), -1);
354d1897a98d8da40cffb57c07099a9a93cfeaacc36Chris Peterson    (void) hb_atomic_ptr_cmpexch (&default_language, HB_LANGUAGE_INVALID, language);
35534fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod  }
35634fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod
35734fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod  return default_language;
35834fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod}
35934fb5521a5fbb6b95ceff4bbac42a62628bc9f31Behdad Esfahbod
3608e4bb3cacc269ed32187aaaeaa166c64f41a0418Behdad Esfahbod
36100bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod/* hb_script_t */
36200bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
36370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
36470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_script_from_iso15924_tag:
3658ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @tag: an #hb_tag_t representing an ISO 15924 tag.
36670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
3678ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * Converts an ISO 15924 script tag to a corresponding #hb_script_t.
36870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
36970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
3708ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * An #hb_script_t corresponding to the ISO 15924 tag.
37170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
372b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
37370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
37400bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_script_t
37500bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_script_from_iso15924_tag (hb_tag_t tag)
37600bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod{
377f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod  if (unlikely (tag == HB_TAG_NONE))
378f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod    return HB_SCRIPT_INVALID;
379f144a8ea840c6452c1fece2fd988b42a8ea7c5a6Behdad Esfahbod
38000bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod  /* Be lenient, adjust case (one capital letter followed by three small letters) */
3817627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod  tag = (tag & 0xDFDFDFDFu) | 0x00202020u;
38200bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
38362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  switch (tag) {
384d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod
385d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod    /* These graduated from the 'Q' private-area codes, but
386d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod     * the old code is still aliased by Unicode, and the Qaai
387d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod     * one in use by ICU. */
388d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod    case HB_TAG('Q','a','a','i'): return HB_SCRIPT_INHERITED;
389d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod    case HB_TAG('Q','a','a','c'): return HB_SCRIPT_COPTIC;
390d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod
391d02985ec5a24c659a0a133cc6bc103f1d76bcb29Behdad Esfahbod    /* Script variants from http://unicode.org/iso15924/ */
39262879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('C','y','r','s'): return HB_SCRIPT_CYRILLIC;
39362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('L','a','t','f'): return HB_SCRIPT_LATIN;
39462879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('L','a','t','g'): return HB_SCRIPT_LATIN;
39562879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('S','y','r','e'): return HB_SCRIPT_SYRIAC;
39662879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('S','y','r','j'): return HB_SCRIPT_SYRIAC;
39762879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_TAG('S','y','r','n'): return HB_SCRIPT_SYRIAC;
39862879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  }
39900bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
40000bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod  /* If it looks right, just use the tag as a script */
4017627100f428ac0ec8509d961d368d2d25d8f0b6eBehdad Esfahbod  if (((uint32_t) tag & 0xE0E0E0E0u) == 0x40606060u)
40200bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod    return (hb_script_t) tag;
40300bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
40400bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod  /* Otherwise, return unknown */
40500bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod  return HB_SCRIPT_UNKNOWN;
40600bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod}
40700bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
40870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
40970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_script_from_string:
4108ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @str: (array length=len) (element-type uint8_t): a string representing an
4118ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny *       ISO 15924 tag.
4128ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @len: length of the @str, or -1 if it is %NULL-terminated.
41370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
4148ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * Converts a string @str representing an ISO 15924 script tag to a
4158ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
4168ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * hb_script_from_iso15924_tag().
41770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
41870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
4198ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * An #hb_script_t corresponding to the ISO 15924 tag.
42070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
421b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
42270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
42300bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_script_t
4248ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosnyhb_script_from_string (const char *str, int len)
42500bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod{
4268ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny  return hb_script_from_iso15924_tag (hb_tag_from_string (str, len));
42700bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod}
42800bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
42970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
43070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_script_to_iso15924_tag:
4318ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * @script: an #hb_script_ to convert.
43270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
4338ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * See hb_script_from_iso15924_tag().
43470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
4358ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * Return value:
4368ab797c5b86c33eab6ee024471fd3c147325d26aKhaled Hosny * An #hb_tag_t representing an ISO 15924 script tag.
43770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
438b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
43970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
44000bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_tag_t
44100bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_script_to_iso15924_tag (hb_script_t script)
44200bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod{
44362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  return (hb_tag_t) script;
44400bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod}
44500bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
44670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
44770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_script_get_horizontal_direction:
44870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @script:
44970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
45070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
45170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
45270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
45370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
454b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
45570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
45600bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_direction_t
45700bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbodhb_script_get_horizontal_direction (hb_script_t script)
45800bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod{
459fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod  /* http://goo.gl/x9ilM */
46062879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  switch ((hb_tag_t) script)
46162879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  {
462fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod    /* Unicode-1.1 additions */
46362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_ARABIC:
46462879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_HEBREW:
465fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod
466fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod    /* Unicode-3.0 additions */
46762879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_SYRIAC:
46862879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_THAANA:
46962879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod
47062879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    /* Unicode-4.0 additions */
47162879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_CYPRIOT:
47262879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod
47350e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod    /* Unicode-4.1 additions */
47450e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod    case HB_SCRIPT_KHAROSHTHI:
47550e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod
47662879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    /* Unicode-5.0 additions */
47762879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_PHOENICIAN:
47862879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_NKO:
47962879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod
48050e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod    /* Unicode-5.1 additions */
48150e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod    case HB_SCRIPT_LYDIAN:
48250e810cd0e55c25fddb0a2fd0861c51fbf65700eBehdad Esfahbod
48362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    /* Unicode-5.2 additions */
48462879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_AVESTAN:
48562879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_IMPERIAL_ARAMAIC:
48662879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_INSCRIPTIONAL_PAHLAVI:
48762879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_INSCRIPTIONAL_PARTHIAN:
48862879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_OLD_SOUTH_ARABIAN:
48962879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_OLD_TURKIC:
49062879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_SAMARITAN:
49162879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod
49262879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    /* Unicode-6.0 additions */
49362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod    case HB_SCRIPT_MANDAIC:
49462879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod
495fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod    /* Unicode-6.1 additions */
496fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod    case HB_SCRIPT_MEROITIC_CURSIVE:
497fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod    case HB_SCRIPT_MEROITIC_HIEROGLYPHS:
498fa2673c1ee954ddbbfbfca7cced7b839d7776fc0Behdad Esfahbod
499a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    /* Unicode-7.0 additions */
500a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_MANICHAEAN:
501a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_MENDE_KIKAKUI:
502a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_NABATAEAN:
503a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_OLD_NORTH_ARABIAN:
504a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_PALMYRENE:
505a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod    case HB_SCRIPT_PSALTER_PAHLAVI:
506a4a7899cd93fb9d1bc2163a4bbabfa733ee5bd52Behdad Esfahbod
50764a2726e2c6efce4379a7609024ec21eb4b5e4dcBehdad Esfahbod    /* Unicode-8.0 additions */
50864a2726e2c6efce4379a7609024ec21eb4b5e4dcBehdad Esfahbod    case HB_SCRIPT_OLD_HUNGARIAN:
50964a2726e2c6efce4379a7609024ec21eb4b5e4dcBehdad Esfahbod
510691086f131cb6c9d97e98730c27673484bf93f87Behdad Esfahbod    /* Unicode-9.0 additions */
511691086f131cb6c9d97e98730c27673484bf93f87Behdad Esfahbod    case HB_SCRIPT_ADLAM:
512691086f131cb6c9d97e98730c27673484bf93f87Behdad Esfahbod
51362879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod      return HB_DIRECTION_RTL;
51462879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  }
51500bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
51662879eebd9965179af8602ba29ac0a64a739b757Behdad Esfahbod  return HB_DIRECTION_LTR;
51700bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod}
51800bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
51900bec2c969555e76c3f84650a1d3c45308e585adBehdad Esfahbod
520218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod/* hb_user_data_array_t */
521218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod
522218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbodbool
523218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbodhb_user_data_array_t::set (hb_user_data_key_t *key,
524218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod			   void *              data,
52533ccc77902660ed4b49184e5ec99f4fd0ef63175Behdad Esfahbod			   hb_destroy_func_t   destroy,
5267babfe5a7904c26060c5b8441ca1bf23e1444f35Behdad Esfahbod			   hb_bool_t           replace)
527218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod{
528218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod  if (!key)
529218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod    return false;
53046df6828513d56cd60467e36cbe45aa06648f488Behdad Esfahbod
53133ccc77902660ed4b49184e5ec99f4fd0ef63175Behdad Esfahbod  if (replace) {
53233ccc77902660ed4b49184e5ec99f4fd0ef63175Behdad Esfahbod    if (!data && !destroy) {
5330e253e97af71e2a7ead153589f61fd579a247502Behdad Esfahbod      items.remove (key, lock);
53433ccc77902660ed4b49184e5ec99f4fd0ef63175Behdad Esfahbod      return true;
53533ccc77902660ed4b49184e5ec99f4fd0ef63175Behdad Esfahbod    }
536218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod  }
537218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod  hb_user_data_item_t item = {key, data, destroy};
538ea512f71084296be3bd893f78650def894066de0Behdad Esfahbod  bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
53946df6828513d56cd60467e36cbe45aa06648f488Behdad Esfahbod
54046df6828513d56cd60467e36cbe45aa06648f488Behdad Esfahbod  return ret;
541218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod}
542218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod
543218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbodvoid *
5447babfe5a7904c26060c5b8441ca1bf23e1444f35Behdad Esfahbodhb_user_data_array_t::get (hb_user_data_key_t *key)
545218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod{
54680c8855cfeffa028d74a25df884d0e5577c95c6cBehdad Esfahbod  hb_user_data_item_t item = {NULL, NULL, NULL};
54746df6828513d56cd60467e36cbe45aa06648f488Behdad Esfahbod
5480e253e97af71e2a7ead153589f61fd579a247502Behdad Esfahbod  return items.find (key, &item, lock) ? item.data : NULL;
54945bfa99034512e886d75b1d45a5a649647f4711fBehdad Esfahbod}
55046df6828513d56cd60467e36cbe45aa06648f488Behdad Esfahbod
551218e67b9eefa26e2e4fe43f99a84d082b185b1b0Behdad Esfahbod
552c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod/* hb_version */
553c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod
55470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
55570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_version:
55670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @major: (out): Library major version component.
55770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @minor: (out): Library minor version component.
55870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @micro: (out): Library micro version component.
55970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
56070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Returns library version as three integer components.
56170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
562b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
56370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
564c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbodvoid
565c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbodhb_version (unsigned int *major,
566c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod	    unsigned int *minor,
567c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod	    unsigned int *micro)
568c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod{
569c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod  *major = HB_VERSION_MAJOR;
570c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod  *minor = HB_VERSION_MINOR;
571c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod  *micro = HB_VERSION_MICRO;
572c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod}
573c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod
57470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
57570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * hb_version_string:
57670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
57770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Returns library version as a string with three components.
57870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
57970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value: library version string.
58070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
581b8811429b6810c4f13be087b593a862c17d9d987Behdad Esfahbod * Since: 0.9.2
58270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
583c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbodconst char *
584c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbodhb_version_string (void)
585c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod{
586c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod  return HB_VERSION_STRING;
587c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod}
588c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod
58970303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod/**
5902b051c6057920c564c13c5d6a3e6dca93446fa12Behdad Esfahbod * hb_version_atleast:
59170303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @major:
59270303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @minor:
59370303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * @micro:
59470303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
59570303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
59670303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
59770303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod * Return value:
59870303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod *
59901c3a88543850c87483fd8671044df53b368c520Sascha Brawer * Since: 0.9.30
60070303cf23b22647bf641be22c8650310128322a9Behdad Esfahbod **/
601c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbodhb_bool_t
6022b051c6057920c564c13c5d6a3e6dca93446fa12Behdad Esfahbodhb_version_atleast (unsigned int major,
6032b051c6057920c564c13c5d6a3e6dca93446fa12Behdad Esfahbod		    unsigned int minor,
6042b051c6057920c564c13c5d6a3e6dca93446fa12Behdad Esfahbod		    unsigned int micro)
605c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod{
6062b051c6057920c564c13c5d6a3e6dca93446fa12Behdad Esfahbod  return HB_VERSION_ATLEAST (major, minor, micro);
607c78f4485587cc1dee07e772c164a13fde9d2859fBehdad Esfahbod}
60872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
60972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
610b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
611bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod/* hb_feature_t and hb_variation_t */
61272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
61372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
61472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_space (const char **pp, const char *end)
61572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
61672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  while (*pp < end && ISSPACE (**pp))
61772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    (*pp)++;
61872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
61972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
62072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
62172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
62272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_char (const char **pp, const char *end, char c)
62372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
62472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  parse_space (pp, end);
62572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
62672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (*pp == end || **pp != c)
62772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return false;
62872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
62972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  (*pp)++;
63072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
63172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
63272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
63372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
63472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_uint (const char **pp, const char *end, unsigned int *pv)
63572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
63672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  char buf[32];
63772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
63872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  strncpy (buf, *pp, len);
63972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  buf[len] = '\0';
64072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
64172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  char *p = buf;
64272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  char *pend = p;
64372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  unsigned int v;
64472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
64572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  /* Intentionally use strtol instead of strtoul, such that
64672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod   * -1 turns into "big number"... */
64772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  errno = 0;
64872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  v = strtol (p, &pend, 0);
64972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (errno || p == pend)
65072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return false;
65172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
65272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  *pv = v;
65372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  *pp += pend - p;
65472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
65572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
65672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
65772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
658b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodparse_float (const char **pp, const char *end, float *pv)
659b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod{
660b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  char buf[32];
661b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
662b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  strncpy (buf, *pp, len);
663b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  buf[len] = '\0';
664b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
665b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  char *p = buf;
666b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  char *pend = p;
667b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  float v;
668b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
669b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  errno = 0;
670b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  v = strtof (p, &pend);
671b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  if (errno || p == pend)
672b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod    return false;
673b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
674b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  *pv = v;
675b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  *pp += pend - p;
676b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  return true;
677b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod}
678b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
679b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodstatic bool
68072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_bool (const char **pp, const char *end, unsigned int *pv)
68172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
68272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  parse_space (pp, end);
68372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
68472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  const char *p = *pp;
68572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  while (*pp < end && ISALPHA(**pp))
68672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    (*pp)++;
68772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
68872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  /* CSS allows on/off as aliases 1/0. */
68972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (*pp - p == 2 || 0 == strncmp (p, "on", 2))
69072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    *pv = 1;
69172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  else if (*pp - p == 3 || 0 == strncmp (p, "off", 2))
69272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    *pv = 0;
69372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  else
69472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return false;
69572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
69672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
69772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
69872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
699b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod/* hb_feature_t */
700b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
70172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
70272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_feature_value_prefix (const char **pp, const char *end, hb_feature_t *feature)
70372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
70472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (parse_char (pp, end, '-'))
70572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    feature->value = 0;
70672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  else {
70772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    parse_char (pp, end, '+');
70872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    feature->value = 1;
70972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
71072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
71172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
71272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
71372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
71472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
715b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodparse_tag (const char **pp, const char *end, hb_tag_t *tag)
71672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
71772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  parse_space (pp, end);
71872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
71972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  char quote = 0;
72072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
72172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (*pp < end && (**pp == '\'' || **pp == '"'))
72272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  {
72372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    quote = **pp;
72472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    (*pp)++;
72572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
72672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
72772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  const char *p = *pp;
72872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  while (*pp < end && ISALNUM(**pp))
72972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    (*pp)++;
73072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
73172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (p == *pp || *pp - p > 4)
73272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return false;
73372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
734b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  *tag = hb_tag_from_string (p, *pp - p);
73572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
73672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (quote)
73772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  {
73872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    /* CSS expects exactly four bytes.  And we only allow quotations for
73972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod     * CSS compatibility.  So, enforce the length. */
74072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod     if (*pp - p != 4)
74172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod       return false;
74272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    if (*pp == end || **pp != quote)
74372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      return false;
74472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    (*pp)++;
74572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
74672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
74772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return true;
74872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
74972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
75072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
75172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_feature_indices (const char **pp, const char *end, hb_feature_t *feature)
75272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
75372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  parse_space (pp, end);
75472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
75572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  bool has_start;
75672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
75772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  feature->start = 0;
75872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  feature->end = (unsigned int) -1;
75972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
76072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (!parse_char (pp, end, '['))
76172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return true;
76272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
76372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  has_start = parse_uint (pp, end, &feature->start);
76472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
76572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (parse_char (pp, end, ':')) {
76672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    parse_uint (pp, end, &feature->end);
76772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  } else {
76872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    if (has_start)
76972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      feature->end = feature->start + 1;
77072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
77172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
77272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return parse_char (pp, end, ']');
77372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
77472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
77572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
77672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_feature_value_postfix (const char **pp, const char *end, hb_feature_t *feature)
77772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
77872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  bool had_equal = parse_char (pp, end, '=');
77972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  bool had_value = parse_uint (pp, end, &feature->value) ||
78072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod                   parse_bool (pp, end, &feature->value);
78172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  /* CSS doesn't use equal-sign between tag and value.
78272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod   * If there was an equal-sign, then there *must* be a value.
78372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod   * A value without an eqaul-sign is ok, but not required. */
78472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return !had_equal || had_value;
78572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
78672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
78772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodstatic bool
78872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodparse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
78972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
79072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return parse_feature_value_prefix (pp, end, feature) &&
791b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod	 parse_tag (pp, end, &feature->tag) &&
79272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod	 parse_feature_indices (pp, end, feature) &&
79372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod	 parse_feature_value_postfix (pp, end, feature) &&
79472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod	 parse_space (pp, end) &&
79572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod	 *pp == end;
79672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
79772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
79872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod/**
79972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * hb_feature_from_string:
80072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @str: (array length=len) (element-type uint8_t): a string to parse
80172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @len: length of @str, or -1 if string is %NULL terminated
80272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @feature: (out): the #hb_feature_t to initialize with the parsed values
80372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
80472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * Parses a string into a #hb_feature_t.
80572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
80672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * TODO: document the syntax here.
80772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
80872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * Return value:
80972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * %true if @str is successfully parsed, %false otherwise.
81072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
81172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * Since: 0.9.5
81272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod **/
81372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodhb_bool_t
81472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodhb_feature_from_string (const char *str, int len,
81572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod			hb_feature_t *feature)
81672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
81772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  hb_feature_t feat;
81872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
81972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (len < 0)
82072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    len = strlen (str);
82172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
82272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (likely (parse_one_feature (&str, str + len, &feat)))
82372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  {
82472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    if (feature)
82572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      *feature = feat;
82672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    return true;
82772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
82872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
82972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (feature)
83072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    memset (feature, 0, sizeof (*feature));
83172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  return false;
83272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
83372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
83472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod/**
83572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * hb_feature_to_string:
83672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @feature: an #hb_feature_t to convert
83772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @buf: (array length=size) (out): output string
83872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * @size: the allocated size of @buf
83972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
84072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * Converts a #hb_feature_t into a %NULL-terminated string in the format
84172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * understood by hb_feature_from_string(). The client in responsible for
84272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * allocating big enough size for @buf, 128 bytes is more than enough.
84372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod *
84472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod * Since: 0.9.5
84572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod **/
84672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodvoid
84772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbodhb_feature_to_string (hb_feature_t *feature,
84872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod		      char *buf, unsigned int size)
84972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod{
85072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (unlikely (!size)) return;
85172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod
85272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  char s[128];
85372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  unsigned int len = 0;
85472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (feature->value == 0)
85572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    s[len++] = '-';
85672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  hb_tag_to_string (feature->tag, s + len);
85772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  len += 4;
85872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  while (len && s[len - 1] == ' ')
85972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    len--;
86072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (feature->start != 0 || feature->end != (unsigned int) -1)
86172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  {
86272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    s[len++] = '[';
86372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    if (feature->start)
86472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
86572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    if (feature->end != feature->start + 1) {
86672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      s[len++] = ':';
86772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod      if (feature->end != (unsigned int) -1)
86872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod	len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
86972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    }
87072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    s[len++] = ']';
87172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
87272364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  if (feature->value > 1)
87372364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  {
87472364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    s[len++] = '=';
87572364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod    len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
87672364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  }
87772364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  assert (len < ARRAY_LENGTH (s));
87872364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  len = MIN (len, size - 1);
87972364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  memcpy (buf, s, len);
88072364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod  buf[len] = '\0';
88172364103bc9d910d19f23a3764d045af79d076d5Behdad Esfahbod}
882b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
883bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod/* hb_variation_t */
884b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
885b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodstatic bool
886bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbodparse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
887b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod{
888b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  parse_char (pp, end, '='); /* Optional. */
889bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  return parse_float (pp, end, &variation->value);
890b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod}
891b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
892b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodstatic bool
893bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbodparse_one_variation (const char **pp, const char *end, hb_variation_t *variation)
894b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod{
895bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  return parse_tag (pp, end, &variation->tag) &&
896bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod	 parse_variation_value (pp, end, variation) &&
897b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod	 parse_space (pp, end) &&
898b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod	 *pp == end;
899b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod}
900b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
901d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod/**
902d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod * hb_variation_from_string:
903d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod *
904d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod * Since: 1.4.2
905d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod */
906b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodhb_bool_t
907bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbodhb_variation_from_string (const char *str, int len,
908bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod			  hb_variation_t *variation)
909b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod{
910bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  hb_variation_t var;
911b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
912b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  if (len < 0)
913b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod    len = strlen (str);
914b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
915bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  if (likely (parse_one_variation (&str, str + len, &var)))
916b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  {
917bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod    if (variation)
918bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod      *variation = var;
919b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod    return true;
920b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  }
921b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
922bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  if (variation)
923bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod    memset (variation, 0, sizeof (*variation));
924b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  return false;
925b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod}
926b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
927d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod/**
928d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod * hb_variation_to_string:
929d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod *
930d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod * Since: 1.4.2
931d2f249e745a9179943ee39c719b73e1057acbc13Behdad Esfahbod */
932b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbodvoid
933bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbodhb_variation_to_string (hb_variation_t *variation,
934b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod			char *buf, unsigned int size)
935b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod{
936b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  if (unlikely (!size)) return;
937b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
938b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  char s[128];
939b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  unsigned int len = 0;
940bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  hb_tag_to_string (variation->tag, s + len);
941b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  len += 4;
942b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  while (len && s[len - 1] == ' ')
943b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod    len--;
944b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  s[len++] = '=';
945bb1e19268f02d4aad2240c52852e72afcf0f79adBehdad Esfahbod  len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", variation->value));
946b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod
947b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  assert (len < ARRAY_LENGTH (s));
948b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  len = MIN (len, size - 1);
949b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  memcpy (buf, s, len);
950b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod  buf[len] = '\0';
951b3c0714b4bbb726b2b3e5e0416ac84cb5c6eb34eBehdad Esfahbod}
952