aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-10-18 13:21:09 +0200
committerMattias Andrée <m@maandree.se>2026-10-18 13:21:09 +0200
commit53b3e04d87f1f81845716e585efcba3c9f7cf9e5 (patch)
tree6daf34677c9dc5b2dbda75881a084aff0d400f88
parentAdd to codepoint data whether the codepoint is a character or not (diff)
downloadlibcmap-master.tar.gz
libcmap-master.tar.bz2
libcmap-master.tar.xz
Signed-off-by: Mattias Andrée <m@maandree.se>
-rw-r--r--Makefile5
-rw-r--r--UnicodeData.parse.c20
-rw-r--r--common.h2
-rw-r--r--libcmap.h62
-rw-r--r--libcmap_bidirectional_category_string.c46
-rw-r--r--libcmap_codepoint_list.c7
-rw-r--r--libcmap_decomposition_type_string.c28
-rw-r--r--libcmap_find_codepoint_data.c2
-rw-r--r--libcmap_general_category_string.c59
-rw-r--r--libcmap_get_codepoint_data.c123
-rw-r--r--libcmap_numeric_type_string.c15
11 files changed, 361 insertions, 8 deletions
diff --git a/Makefile b/Makefile
index 12a75ed..71ff0fc 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,11 @@ OBJ =\
libcmap_find_block.o\
libcmap_find_script.o\
libcmap_find_codepoint_data.o\
+ libcmap_get_codepoint_data.o\
+ libcmap_general_category_string.o\
+ libcmap_bidirectional_category_string.o\
+ libcmap_numeric_type_string.o\
+ libcmap_decomposition_type_string.o\
libcmap_sprint_range.o\
libcmap_snprint_range.o\
libcmap_fprint_range.o\
diff --git a/UnicodeData.parse.c b/UnicodeData.parse.c
index f9b676c..14aff33 100644
--- a/UnicodeData.parse.c
+++ b/UnicodeData.parse.c
@@ -128,6 +128,8 @@ split(char **text)
static int
output_character_data(char *text)
{
+ static int first_first = 1;
+
char *field, *numeric_value = NULL, *simple_uppercase_mapping;
unsigned long int codepoint;
const char *formatted;
@@ -138,6 +140,17 @@ output_character_data(char *text)
if (!(field = split(&text))) return 0;
add_linef(".name = \"%s\"", field);
+ if (strstr(field, ", First>")) {
+ if (first_first) {
+ ret |= printf("static const struct libcmap_range gaplist[] = {\n");
+ first_first = 0;
+ } else {
+ ret |= printf(",\n");
+ }
+ ret |= printf("\t{UINT32_C(0x%04lX)", codepoint);
+ } else if (strstr(field, ", Last>")) {
+ ret |= printf(", UINT32_C(0x%04lX)}", codepoint);
+ }
if (!(field = split(&text))) return 0;
add_linef(", .general_category = GENERAL_CATEGORY_%s", field);
@@ -215,7 +228,10 @@ output_character_data(char *text)
add_linef(", .bidirectional_mirrored = BIDIRECTIONAL_MIRRORED_%s", field);
if (!(field = split(&text))) return 0;
- add_linef(", .unicode_1_name = \"%s\"", field);
+ if (*field)
+ add_linef(", .unicode_1_name = \"%s\"", field);
+ else
+ add_linef(", .unicode_1_name = NULL");
if (!(field = split(&text))) return 0; /* ISO 10646 comment field -- always empty as of Unicode 5.2.0 */
@@ -371,6 +387,8 @@ output(void)
uint32_t *seq = NULL;
size_t i, seqlen = 0u, off, end, ext;
+ ret |= printf("\n};\n");
+
if (!nsegments) {
fprintf(stderr, "%s: character list is empty\n", argv0);
exit(1);
diff --git a/common.h b/common.h
index 0007af2..6b7bbff 100644
--- a/common.h
+++ b/common.h
@@ -1,6 +1,8 @@
/* See LICENSE file for copyright and license details. */
#include "libcmap.h"
+#include <errno.h>
#include <limits.h>
+#include <string.h>
#define SINGLETON_RANGE_FMT "U+%04lX"
diff --git a/libcmap.h b/libcmap.h
index 0f765a1..7893445 100644
--- a/libcmap.h
+++ b/libcmap.h
@@ -53,8 +53,8 @@ enum libcmap_general_category {
LIBCMAP_GENERAL_CATEGORY_LETTER_MODIFIER,
LIBCMAP_GENERAL_CATEGORY_LETTER_OTHER,
LIBCMAP_GENERAL_CATEGORY_MARK_NONSPACING = LIBCMAP_GENERAL_SUPERCATEGORY_MARK + 1u,
- LIBCMAP_GENERAL_CATEGORY_MARK_SPACING_COMBINING,
- LIBCMAP_GENERAL_CATEGORY_MARK_ENCODING,
+ LIBCMAP_GENERAL_CATEGORY_MARK_SPACING,
+ LIBCMAP_GENERAL_CATEGORY_MARK_ENCLOSING,
LIBCMAP_GENERAL_CATEGORY_NUMBER_DECIMAL_DIGIT = LIBCMAP_GENERAL_SUPERCATEGORY_NUMBER + 1u,
LIBCMAP_GENERAL_CATEGORY_NUMBER_LETTER,
LIBCMAP_GENERAL_CATEGORY_NUMBER_OTHER,
@@ -78,8 +78,11 @@ enum libcmap_general_category {
LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE,
/**
- * This category has two subcategories: noncharacter and reserved
- * If .noncharacter it is not a character, otherwise it is reserved
+ * This category has two subcategories: noncharacter and reserved.
+ * If .noncharacter it is not a character, otherwise it is reserved.
+ * Unfortunately, at the moment there is no way, in the case of
+ * reserved to distinguish between permanently reserved and not yet
+ * assigned
*/
LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED
};
@@ -342,6 +345,7 @@ extern const size_t libcmap_script_list_size;
*
* @seealso libcmap_codepoint_list_size
* @seealso libcmap_find_codepoint_data
+ * @seealso libcmap_get_codepoint_data
*/
extern const struct libcmap_codepoint_segment *const libcmap_codepoint_list;
@@ -350,6 +354,17 @@ extern const struct libcmap_codepoint_segment *const libcmap_codepoint_list;
*/
extern const size_t libcmap_codepoint_list_size;
+/**
+ * List of ranges of codepoints not covered by `libcmap_codepoint_list`
+ * (the boundaries are covered with improper entries)
+ */
+extern const struct libcmap_range *const libcmap_no_data_range_list;
+
+/**
+ * The number of elements in `libcmap_no_data_range_list`
+ */
+extern const size_t libcmap_no_data_range_list_size;
+
/**
* Find a codepoint within `libcmap_no_block`
@@ -426,6 +441,9 @@ const struct libcmap_script *libcmap_find_script(uint32_t codepoint, size_t *off
/**
* Find data about a specified codepoint
*
+ * You should generally use `libcmap_get_codepoint_data`
+ * instead of this function
+ *
* @param codepoint The codepoint
* @return Information from UnicodeData about the codepoint,
* `NULL` if not found
@@ -435,10 +453,46 @@ const struct libcmap_script *libcmap_find_script(uint32_t codepoint, size_t *off
* which is common for ideographs
*
* @seealso libcmap_codepoint_list
+ * @seealso libcmap_get_codepoint_data
*/
LIBCMAP_PURE_
const struct libcmap_codepoint_data *libcmap_find_codepoint_data(uint32_t codepoint);
+/**
+ * Get data about a specified codepoint
+ *
+ * @param codepoint The codepoint
+ * @param data_out Output parameter for the data
+ * @param buffer Buffer that the function can store data in, this data
+ * is then referenced by pointers in `*data_out`
+ * @param bufsizep Input parameter for the size of `buffer`, and
+ * output parameter for the required size of `buffer`
+ * (only set when -1 is returned with `errno` set to ERANGE)
+ * @return 1 if `codepoint` is within the range of codepoints
+ * (that is, if `codepoint` is no greater than
+ * LIBCMAP_ULTIMATE_CODEPOINT), 0 otherwise, -1 on failure
+ *
+ * @throws ERANGE `*bufsizep` was too small, but has been update with the required size
+ *
+ * `*data_out` is only updated if 1 is returned
+ *
+ * Unlike `libcmap_find_codepoint_data`, this function can
+ * synthesis the data for codepoints that are not in UnicodeData,
+ * and can correct the names where the codepoint is listing in
+ * UnicodeData as the start or end of an omitted range
+ *
+ * @seealso libcmap_codepoint_list
+ * @seealso libcmap_find_codepoint_data
+ */
+int libcmap_get_codepoint_data(uint32_t codepoint, struct libcmap_codepoint_data *data_out, void *buffer, size_t *bufsizep);
+
+
+/* TODO documentation is needed */
+LIBCMAP_CONST_ const char *libcmap_general_category_string(enum libcmap_general_category value);
+LIBCMAP_CONST_ const char *libcmap_bidirectional_category_string(enum libcmap_bidirectional_category value);
+LIBCMAP_CONST_ const char *libcmap_numeric_type_string(enum libcmap_numeric_type value);
+LIBCMAP_CONST_ const char *libcmap_decomposition_type_string(enum libcmap_decomposition_type value);
+
/**
* Print a string representing a Unicode codepoint range
diff --git a/libcmap_bidirectional_category_string.c b/libcmap_bidirectional_category_string.c
new file mode 100644
index 0000000..4cbd116
--- /dev/null
+++ b/libcmap_bidirectional_category_string.c
@@ -0,0 +1,46 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const char *
+libcmap_bidirectional_category_string(enum libcmap_bidirectional_category value)
+{
+ switch ((enum libcmap_bidirectional_supercategory)value) {
+ case LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_STRONG: return "strong";
+ case LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_WEAK: return "weak";
+ case LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_NEUTRAL: return "neutral";
+ case LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_EXPLICIT: return "explicit";
+ default: break;
+ }
+
+ switch (value) {
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT: return "Left-to-right";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT: return "Right-to-left";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ARABIC: return "Arabic right-to-left";
+
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER: return "European number";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_SEPARATOR: return "European number separator";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_TERMINATOR: return "European number terminator";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_ARABIC_NUMBER: return "Arabic number";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_COMMON_SEPARATOR: return "Common separator";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_NONSPACING_MARK: return "Non-spacing mark";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_BOUNDARY_NEUTRAL: return "Boundary neutral";
+
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_PARAGRAPH_SEPARATOR: return "Paragraph separator";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_SEGMENT_SEPARATOR: return "Segment separator";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_WHITESPACE: return "Whitespace";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_OTHER_NEUTRALS: return "Other neutrals";
+
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_EMBEDDING: return "Left-to-right embedding";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_OVERRIDE: return "Left-to-right override";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_EMBEDDING: return "Right-to-left embedding";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_OVERRIDE: return "Right-to-left override";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_FORMAT: return "Pop directional format";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_ISOLATE: return "Left-to-right isolate";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ISOLATE: return "Right-to-left isolate";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_FIRST_STRONG_ISOLATE: return "First strong isolate";
+ case LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_ISOLATE: return "Pop directional isolate";
+
+ default: return NULL;
+ }
+}
diff --git a/libcmap_codepoint_list.c b/libcmap_codepoint_list.c
index d706441..c747236 100644
--- a/libcmap_codepoint_list.c
+++ b/libcmap_codepoint_list.c
@@ -8,8 +8,8 @@
#define GENERAL_CATEGORY_Lm LIBCMAP_GENERAL_CATEGORY_LETTER_MODIFIER
#define GENERAL_CATEGORY_Lo LIBCMAP_GENERAL_CATEGORY_LETTER_OTHER
#define GENERAL_CATEGORY_Mn LIBCMAP_GENERAL_CATEGORY_MARK_NONSPACING
-#define GENERAL_CATEGORY_Mc LIBCMAP_GENERAL_CATEGORY_MARK_SPACING_COMBINING
-#define GENERAL_CATEGORY_Me LIBCMAP_GENERAL_CATEGORY_MARK_ENCODING
+#define GENERAL_CATEGORY_Mc LIBCMAP_GENERAL_CATEGORY_MARK_SPACING
+#define GENERAL_CATEGORY_Me LIBCMAP_GENERAL_CATEGORY_MARK_ENCLOSING
#define GENERAL_CATEGORY_Nd LIBCMAP_GENERAL_CATEGORY_NUMBER_DECIMAL_DIGIT
#define GENERAL_CATEGORY_Nl LIBCMAP_GENERAL_CATEGORY_NUMBER_LETTER
#define GENERAL_CATEGORY_No LIBCMAP_GENERAL_CATEGORY_NUMBER_OTHER
@@ -66,3 +66,6 @@
const struct libcmap_codepoint_segment *const libcmap_codepoint_list = list;
const size_t libcmap_codepoint_list_size = sizeof(list) / sizeof(*list);
+
+const struct libcmap_range *const libcmap_no_data_range_list = gaplist;
+const size_t libcmap_no_data_range_list_size = sizeof(gaplist) / sizeof(*gaplist);
diff --git a/libcmap_decomposition_type_string.c b/libcmap_decomposition_type_string.c
new file mode 100644
index 0000000..f8ea38d
--- /dev/null
+++ b/libcmap_decomposition_type_string.c
@@ -0,0 +1,28 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const char *
+libcmap_decomposition_type_string(enum libcmap_decomposition_type value)
+{
+ switch (value) {
+ case LIBCMAP_DECOMPOSITION_TYPE_CANONICAL: return "Canonical";
+ case LIBCMAP_DECOMPOSITION_TYPE_FONT: return "Font";
+ case LIBCMAP_DECOMPOSITION_TYPE_NO_BREAK: return "No-break";
+ case LIBCMAP_DECOMPOSITION_TYPE_INITIAL: return "Initial";
+ case LIBCMAP_DECOMPOSITION_TYPE_MEDIAL: return "Medial";
+ case LIBCMAP_DECOMPOSITION_TYPE_FINAL: return "Final";
+ case LIBCMAP_DECOMPOSITION_TYPE_ISOLATED: return "Isolated";
+ case LIBCMAP_DECOMPOSITION_TYPE_CIRCLE: return "Circle";
+ case LIBCMAP_DECOMPOSITION_TYPE_SUPER: return "Superscript";
+ case LIBCMAP_DECOMPOSITION_TYPE_SUB: return "Subscript";
+ case LIBCMAP_DECOMPOSITION_TYPE_VERTICAL: return "Vertical";
+ case LIBCMAP_DECOMPOSITION_TYPE_WIDE: return "Wide";
+ case LIBCMAP_DECOMPOSITION_TYPE_NARROW: return "Narrow";
+ case LIBCMAP_DECOMPOSITION_TYPE_SMALL: return "Small";
+ case LIBCMAP_DECOMPOSITION_TYPE_SQUARE: return "Square";
+ case LIBCMAP_DECOMPOSITION_TYPE_FRACTION: return "Fraction";
+ case LIBCMAP_DECOMPOSITION_TYPE_COMPAT: return "Compat";
+ default: return NULL;
+ }
+}
diff --git a/libcmap_find_codepoint_data.c b/libcmap_find_codepoint_data.c
index cd2e52f..8b048c0 100644
--- a/libcmap_find_codepoint_data.c
+++ b/libcmap_find_codepoint_data.c
@@ -21,5 +21,5 @@ libcmap_find_codepoint_data(uint32_t codepoint)
}
}
- return NULL;
+ return NULL;
}
diff --git a/libcmap_general_category_string.c b/libcmap_general_category_string.c
new file mode 100644
index 0000000..2860efe
--- /dev/null
+++ b/libcmap_general_category_string.c
@@ -0,0 +1,59 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const char *
+libcmap_general_category_string(enum libcmap_general_category value)
+{
+ switch ((enum libcmap_general_supercategory)value) {
+ case LIBCMAP_GENERAL_SUPERCATEGORY_LETTER: return "Letter";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_MARK: return "Mark";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_NUMBER: return "Number";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_PUNCTUATION: return "Punctuation";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_SYMBOL: return "Symbol";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_SEPARATOR: return "Separator";
+ case LIBCMAP_GENERAL_SUPERCATEGORY_OTHER: return "Other";
+ default: break;
+ }
+
+ switch (value) {
+ case LIBCMAP_GENERAL_CATEGORY_LETTER_UPPERCASE: return "Uppercase";
+ case LIBCMAP_GENERAL_CATEGORY_LETTER_LOWERCASE: return "Lowercase";
+ case LIBCMAP_GENERAL_CATEGORY_LETTER_TITLECASE: return "Titlecase";
+ case LIBCMAP_GENERAL_CATEGORY_LETTER_MODIFIER: return "Modifier";
+ case LIBCMAP_GENERAL_CATEGORY_LETTER_OTHER: return "Other";
+
+ case LIBCMAP_GENERAL_CATEGORY_MARK_NONSPACING: return "Non-spacing";
+ case LIBCMAP_GENERAL_CATEGORY_MARK_SPACING: return "Spacing";
+ case LIBCMAP_GENERAL_CATEGORY_MARK_ENCLOSING: return "Enclosing";
+
+ case LIBCMAP_GENERAL_CATEGORY_NUMBER_DECIMAL_DIGIT: return "Decimal digit";
+ case LIBCMAP_GENERAL_CATEGORY_NUMBER_LETTER: return "Letter";
+ case LIBCMAP_GENERAL_CATEGORY_NUMBER_OTHER: return "Other";
+
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CONNECTOR: return "Connector";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_DASH: return "Dash";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OPEN: return "Open";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CLOSE: return "Close";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_INITIAL_QUOTE: return "Initial quote";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_FINAL_QUOTE: return "Finak quote";
+ case LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OTHER: return "Other";
+
+ case LIBCMAP_GENERAL_CATEGORY_SYMBOL_MATH: return "Math";
+ case LIBCMAP_GENERAL_CATEGORY_SYMBOL_CURRENCY: return "Currency";
+ case LIBCMAP_GENERAL_CATEGORY_SYMBOL_MODIFIER: return "Modifier";
+ case LIBCMAP_GENERAL_CATEGORY_SYMBOL_OTHER: return "Other";
+
+ case LIBCMAP_GENERAL_CATEGORY_SEPARATOR_SPACE: return "Space";
+ case LIBCMAP_GENERAL_CATEGORY_SEPARATOR_LINE: return "Line";
+ case LIBCMAP_GENERAL_CATEGORY_SEPARATOR_PARAGRAPH: return "Paragraph";
+
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_CONTROL: return "Control";
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_FORMAT: return "Format";
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_SURROGATE: return "Surrogate";
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE: return "Private-use";
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED: return "Not assigned";
+
+ default: return NULL;
+ }
+}
diff --git a/libcmap_get_codepoint_data.c b/libcmap_get_codepoint_data.c
new file mode 100644
index 0000000..553636d
--- /dev/null
+++ b/libcmap_get_codepoint_data.c
@@ -0,0 +1,123 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+static int
+construct_codepoint_label(const char *metalabel, uint32_t codepoint, void *buffer, size_t *bufsizep)
+{
+ /* See Unicode Core Spec 4.8.2 Code Point Labels */
+
+ size_t req = sizeof("-NNNN") + strlen(metalabel) - 2u * (size_t)(*metalabel == '<');
+ char *p = buffer;
+
+ if (codepoint >> 16) req += 1u;
+ if (codepoint >> 20) req += 1u;
+
+ if (*bufsizep < req) {
+ *bufsizep = req;
+ errno = ERANGE;
+ return -1;
+ }
+
+ p = stpcpy(buffer, &metalabel[*metalabel == '<']);
+ p -= *metalabel == '<';
+ *p++ = '-';
+ if (codepoint >> 20) *p++ = "0123456789ABCDEF"[(codepoint >> 20) & 15u];
+ if (codepoint >> 16) *p++ = "0123456789ABCDEF"[(codepoint >> 16) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 12) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 8) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 4) & 15u];
+ *p++ = "0123456789ABCDEF"[(codepoint >> 0) & 15u];
+ *p = '\0';
+
+ return 0;
+}
+
+
+int
+libcmap_get_codepoint_data(uint32_t codepoint, struct libcmap_codepoint_data *data_out, void *buffer, size_t *bufsizep)
+{
+ const struct libcmap_codepoint_data *data;
+ size_t i, namelen;
+ const char *metalabel;
+
+ memset(data_out, 0, sizeof(*data_out));
+ data_out->name = NULL;
+ data_out->unicode_1_name = NULL;
+ data_out->numeric_value = NULL;
+ data_out->decomposition_mapping = NULL;
+
+ if (codepoint > LIBCMAP_ULTIMATE_CODEPOINT)
+ return 0;
+
+ if ((0xFDD0u <= codepoint && codepoint <= 0xFDEFu) || (codepoint & 0xFFFEu) == 0xFFFEu) {
+ if (data_out) {
+ if (construct_codepoint_label("noncharacter", codepoint, buffer, bufsizep))
+ return -1;
+ data_out->name = buffer;
+ data_out->general_category = LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED;
+ data_out->noncharacter = 1u;
+ }
+ return 1;
+ }
+
+ for (i = 0u; i < libcmap_no_data_range_list_size; i++) {
+ if (codepoint <= libcmap_no_data_range_list[i].last) {
+ if (libcmap_no_data_range_list[i].first > codepoint)
+ break;
+ if (!data_out)
+ return 1;
+ data = libcmap_find_codepoint_data(libcmap_no_data_range_list[i].first);
+ switch ((int)data->general_category) {
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_CONTROL: metalabel = "control"; goto have_metalabel;
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_SURROGATE: metalabel = "surrogate"; goto have_metalabel;
+ case LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE: metalabel = "private-use"; goto have_metalabel;
+ default:
+ namelen = strlen(data->name);
+ namelen -= sizeof(", First") - 1u;
+ if (namelen + 1u > *bufsizep) {
+ *bufsizep = namelen + 1u;
+ errno = ERANGE;
+ return -1;
+ }
+ memcpy(buffer, data->name, namelen - 1u);
+ ((char *)buffer)[namelen - 1u] = '>';
+ ((char *)buffer)[namelen] = '\0';
+ break;
+
+ have_metalabel:
+ if (construct_codepoint_label(metalabel, codepoint, buffer, bufsizep))
+ return -1;
+ break;
+ }
+ *data_out = *data;
+ data_out->name = buffer;
+ return 1;
+ }
+ }
+
+ data = libcmap_find_codepoint_data(codepoint);
+ if (!data) {
+ if (data_out) {
+ if (construct_codepoint_label("reserved", codepoint, buffer, bufsizep))
+ return -1;
+ data_out->name = buffer;
+ data_out->general_category = LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED;
+ data_out->noncharacter = 0u;
+ }
+ return 1;
+ }
+
+ if (data_out) {
+ if (data->name[0u] == '<') {
+ if (construct_codepoint_label(data->name, codepoint, buffer, bufsizep))
+ return -1;
+ *data_out = *data;
+ data_out->name = buffer;
+ } else {
+ *data_out = *data;
+ }
+ }
+
+ return 1;
+}
diff --git a/libcmap_numeric_type_string.c b/libcmap_numeric_type_string.c
new file mode 100644
index 0000000..e9ea113
--- /dev/null
+++ b/libcmap_numeric_type_string.c
@@ -0,0 +1,15 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const char *
+libcmap_numeric_type_string(enum libcmap_numeric_type value)
+{
+ switch (value) {
+ case LIBCMAP_NUMERIC_TYPE_NONE: return "None";
+ case LIBCMAP_NUMERIC_TYPE_DECIMAL: return "Decimal";
+ case LIBCMAP_NUMERIC_TYPE_DIGIT: return "Digit";
+ case LIBCMAP_NUMERIC_TYPE_NUMERIC: return "Numeric";
+ default: return NULL;
+ }
+}