1 // C99 port from c++ is protected by a GNU Lesser GPLv3
2 // Copyright © 2013 Sylvain BERTRAND <sylvain.bertrand@gmail.com>
3 // <sylware@legeek.net>
9 #include "hb-private.h"
10 #include "hb-atomic-private.h"
12 //this is actually hb_language_t type
13 struct hb_language_impl_t
{
17 static const char canon_map
[256] = {
18 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
19 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
20 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '-', 0, 0,
21 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0,
22 '-', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
23 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, '-',
24 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
25 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0
29 lang_equal(hb_language_t v1
,
32 const unsigned char *p1
= (const unsigned char*)v1
;
33 const unsigned char *p2
= (const unsigned char*)v2
;
35 while (*p1
&& *p1
== canon_map
[*p2
])
37 return *p1
== canon_map
[*p2
];
40 struct hb_language_item_t
{
42 struct hb_language_item_t
*next
;
47 lang_assign(const char *s
)
49 hb_language_t lang
= (hb_language_t
)strdup(s
);
50 for (unsigned char *p
= (unsigned char *)lang
; *p
; p
++)
55 /* Thread-safe lock-free language list */
57 static struct hb_language_item_t
*lang_items
;
59 static struct hb_language_item_t
*
60 language_item_find_or_insert(const char *key
)
62 struct hb_language_item_t
*first_lang_item
= hb_atomic_ptr_get(&lang_items
);
65 for (struct hb_language_item_t
*lang_item
= first_lang_item
; lang_item
;
66 lang_item
= lang_item
->next
)
67 if (lang_equal(lang_item
->lang
, key
))
70 //Not found; allocate one.
71 struct hb_language_item_t
*lang_item
= calloc(1, sizeof(*lang_item
));
74 lang_item
->next
= first_lang_item
;
75 lang_item
->lang
= lang_assign(key
);
77 if (hb_atomic_ptr_cmpexch(&lang_items
, &first_lang_item
, &lang_item
))
84 hb_language_from_string(const char *str
, int len
)
86 if (!str
|| !len
|| !*str
)
87 return HB_LANGUAGE_INVALID
;
91 len
= MIN(len
, (int)sizeof(strbuf
) - 1);
92 str
= (char*)memcpy(strbuf
, str
, len
);
96 struct hb_language_item_t
*item
= language_item_find_or_insert(str
);
98 return item
? item
->lang
: HB_LANGUAGE_INVALID
;
102 hb_tag_from_string(const char *str
, int len
)
107 if (!str
|| !len
|| !*str
)
110 if (len
< 0 || len
> 4)
112 for (i
= 0; i
< (unsigned)len
&& str
[i
]; ++i
)
116 return HB_TAG_CHAR4(tag
);
120 hb_language_to_string(hb_language_t language
)
122 //This is actually NULL-safe!