aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Makefile23
-rw-r--r--TODO1
-rw-r--r--UnicodeData.parse.c139
-rw-r--r--libcmap.h162
-rw-r--r--libcmap_codepoint_list.c68
-rw-r--r--libcmap_find_codepoint_data.c25
-rw-r--r--libcmap_unicode_version.c5
-rw-r--r--parse-common.c2
8 files changed, 422 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 7190f5f..cb1eb13 100644
--- a/Makefile
+++ b/Makefile
@@ -21,11 +21,14 @@ UNICODE_VERSION = 17.0.0
OBJ =\
+ libcmap_unicode_version.o\
libcmap_block_list.o\
libcmap_script_list.o\
+ libcmap_codepoint_list.o\
libcmap_find_in_no_block.o\
libcmap_find_block.o\
libcmap_find_script.o\
+ libcmap_find_codepoint_data.o\
libcmap_sprint_range.o\
libcmap_snprint_range.o\
libcmap_fprint_range.o\
@@ -40,22 +43,30 @@ LOBJ = $(OBJ:.o=.lo)
PARSERS =\
Scripts.parse\
- Blocks.parse
+ Blocks.parse\
+ UnicodeData.parse
all: libcmap.a libcmap.$(LIBEXT)
$(OBJ): $(HDR)
$(LOBJ): $(HDR)
$(PARSERS:=.o): parse-common.c
+$(PARSERS):
libcmap_script_list.o: Scripts.txt.c
libcmap_block_list.o: Blocks.txt.c
+libcmap_codepoint_list.o: UnicodeData.txt.c
+
+libcmap_unicode_version.o: Makefile
.c.o:
- $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+ $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) -D'UNICODE_VERSION="$(UNICODE_VERSION)"'
.c.lo:
- $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS)
+ $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS) -D'UNICODE_VERSION="$(UNICODE_VERSION)"'
+
+.o:
+ $(CC) -o $@ $<
libcmap.a: $(OBJ)
@rm -f -- $@
@@ -71,12 +82,18 @@ Scripts.$(UNICODE_VERSION).txt:
Blocks.$(UNICODE_VERSION).txt:
$(DOWNLOAD) 'https://www.unicode.org/Public/$(UNICODE_VERSION)/ucd/Blocks.txt' > $@
+UnicodeData.$(UNICODE_VERSION).txt:
+ $(DOWNLOAD) 'https://www.unicode.org/Public/$(UNICODE_VERSION)/ucd/UnicodeData.txt' > $@
+
Scripts.txt.c: Scripts.$(UNICODE_VERSION).txt Scripts.parse
./Scripts.parse < $(@:.txt.c=).$(UNICODE_VERSION).txt > $@
Blocks.txt.c: Blocks.$(UNICODE_VERSION).txt Blocks.parse
./Blocks.parse < $(@:.txt.c=).$(UNICODE_VERSION).txt > $@
+UnicodeData.txt.c: UnicodeData.$(UNICODE_VERSION).txt UnicodeData.parse
+ ./UnicodeData.parse < $(@:.txt.c=).$(UNICODE_VERSION).txt > $@
+
install: libcmap.a libcmap.$(LIBEXT)
mkdir -p -- "$(DESTDIR)$(PREFIX)/lib"
mkdir -p -- "$(DESTDIR)$(PREFIX)/include"
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..6c085d3
--- /dev/null
+++ b/TODO
@@ -0,0 +1 @@
+Add man pages
diff --git a/UnicodeData.parse.c b/UnicodeData.parse.c
new file mode 100644
index 0000000..173fb6a
--- /dev/null
+++ b/UnicodeData.parse.c
@@ -0,0 +1,139 @@
+/* See LICENSE file for copyright and license details. */
+#include "parse-common.c"
+
+
+struct segment {
+ uint32_t first, last;
+};
+
+
+static struct segment *segments = NULL;
+static size_t nsegments = 0u;
+static int ret = 0;
+
+
+static char *
+split(char **text)
+{
+ char *field = *text;
+ if (field) {
+ *text = strchr(*text, ';');
+ if (*text)
+ *(*text)++ = '\0';
+ }
+ return field;
+}
+
+
+static int
+output_character_data(char *text)
+{
+ char *field;
+
+ if (!(field = split(&text))) return 0; /* codepoint */
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(".name = \"%s\"", field);
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(", .general_category = GENERAL_CATEGORY_%s", field);
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(", .canonical_combining_classes = %su", field);
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(", .bidirectional_category = BIDIRECTIONAL_CATEGORY_%s", field);
+
+ if (!(field = split(&text))) return 0; /* TODO Character Decomposition Mapping */
+ if (!(field = split(&text))) return 0; /* TODO Decimal digit value */
+ if (!(field = split(&text))) return 0; /* TODO Digit value */
+ if (!(field = split(&text))) return 0; /* TODO Numeric value */
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(", .bidirectional_mirrored = BIDIRECTIONAL_MIRRORED_%s", field);
+
+ if (!(field = split(&text))) return 0;
+ ret |= printf(", .unicode_1_name = \"%s\"", field);
+
+ if (!(field = split(&text))) return 0; /* ISO 10646 comment field -- always empty as of Unicode 5.2.0 */
+
+ if (!(field = split(&text))) return 0; /* TODO Uppercase Mapping */
+ if (!(field = split(&text))) return 0; /* TODO Lowercase Mapping */
+ if (!(field = split(&text))) return 0; /* TODO Titlecase Mapping */
+
+ return 1;
+}
+
+
+static void
+parse_line(char *text, size_t lineno)
+{
+ unsigned long int codepoint;
+ char *end;
+
+ if (!isxdigit(*text)) {
+ malformat:
+ fprintf(stderr, "%s: line %zu in is malformatted\n", argv0, lineno);
+ exit(1);
+ }
+
+ errno = 0;
+
+ codepoint = strtoul(text, &end, 16);
+ if (errno || codepoint > ULTIMATE_CODEPOINT || *end != ';')
+ goto malformat;
+
+ if (!nsegments) {
+ new_segment:
+ ret |= printf("static const struct libcmap_codepoint_data data_from_%04lx[] = {\n", codepoint);
+ segments = realloc(segments, ++nsegments * sizeof(*segments));
+ if (!segments) {
+ fprintf(stderr, "%s: realloc %zu: %s\n", argv0, nsegments * sizeof(*segments), strerror(errno));
+ exit(1);
+ }
+ segments[nsegments - 1u].first = (uint32_t)codepoint;
+ goto new_codepoint;
+ } else if (segments[nsegments - 1u].last + 1u == (uint32_t)codepoint) {
+ ret |= printf(",\n");
+ new_codepoint:
+ segments[nsegments - 1u].last = (uint32_t)codepoint;
+ ret |= printf("\t{");
+ if (!output_character_data(text))
+ goto malformat;
+ ret |= printf("}");
+ } else {
+ if ((uint32_t)codepoint < segments[nsegments - 1u].last) {
+ fprintf(stderr, "%s: UnicodeData is not sorted\n", argv0);
+ exit(1);
+ }
+ ret |= printf("\n};\n");
+ goto new_segment;
+ }
+}
+
+
+static int
+output(void)
+{
+ size_t i;
+
+ if (!nsegments) {
+ fprintf(stderr, "%s: character list is empty\n", argv0);
+ exit(1);
+ }
+
+ ret |= printf("\n};\n");
+
+ ret |= printf("static const struct libcmap_codepoint_segment list[] = {\n");
+ for (i = 0u; i < nsegments; i++) {
+ if (i)
+ ret |= printf(",\n");
+ ret |= printf("\t{.range = {0x%04"PRIX32", 0x%04"PRIX32"}, .data = data_from_%04"PRIx32"}",
+ segments[i].first, segments[i].last, segments[i].first);
+ }
+ ret |= printf("\n};\n");
+
+ free(segments);
+
+ return ret;
+}
diff --git a/libcmap.h b/libcmap.h
index a62ddee..9c32c77 100644
--- a/libcmap.h
+++ b/libcmap.h
@@ -36,6 +36,88 @@
#define LIBCMAP_RANGE_SIZE(RANGE) ((size_t)((RANGE)->last - (RANGE)->first + 1u))
+enum libcmap_general_supercategory {
+ LIBCMAP_GENERAL_SUPERCATEGORY_LETTER = 0x0100u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_MARK = 0x0200u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_NUMBER = 0x0300u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_PUNCTUATION = 0x0400u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_SYMBOL = 0x0500u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_SEPARATOR = 0x0600u,
+ LIBCMAP_GENERAL_SUPERCATEGORY_OTHER = 0x0700u
+};
+
+enum libcmap_general_category {
+ LIBCMAP_GENERAL_CATEGORY_LETTER_UPPERCASE = LIBCMAP_GENERAL_SUPERCATEGORY_LETTER + 1u,
+ LIBCMAP_GENERAL_CATEGORY_LETTER_LOWERCASE,
+ LIBCMAP_GENERAL_CATEGORY_LETTER_TITLECASE,
+ 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_NUMBER_DECIMAL_DIGIT = LIBCMAP_GENERAL_SUPERCATEGORY_NUMBER + 1u,
+ LIBCMAP_GENERAL_CATEGORY_NUMBER_LETTER,
+ LIBCMAP_GENERAL_CATEGORY_NUMBER_OTHER,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CONNECTOR = LIBCMAP_GENERAL_SUPERCATEGORY_PUNCTUATION + 1u,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_DASH,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OPEN,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CLOSE,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_INITIAL_QUOTE,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_FINAL_QUOTE,
+ LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OTHER,
+ LIBCMAP_GENERAL_CATEGORY_SYMBOL_MATH = LIBCMAP_GENERAL_SUPERCATEGORY_SYMBOL + 1u,
+ LIBCMAP_GENERAL_CATEGORY_SYMBOL_CURRENCY,
+ LIBCMAP_GENERAL_CATEGORY_SYMBOL_MODIFIER,
+ LIBCMAP_GENERAL_CATEGORY_SYMBOL_OTHER,
+ LIBCMAP_GENERAL_CATEGORY_SEPARATOR_SPACE = LIBCMAP_GENERAL_SUPERCATEGORY_SEPARATOR + 1u,
+ LIBCMAP_GENERAL_CATEGORY_SEPARATOR_LINE,
+ LIBCMAP_GENERAL_CATEGORY_SEPARATOR_PARAGRAPH,
+ LIBCMAP_GENERAL_CATEGORY_OTHER_CONTROL = LIBCMAP_GENERAL_SUPERCATEGORY_OTHER + 1u,
+ LIBCMAP_GENERAL_CATEGORY_OTHER_FORMAT,
+ LIBCMAP_GENERAL_CATEGORY_OTHER_SURROGATE,
+ LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE,
+ LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED
+};
+
+#define LIBCMAP_GENERAL_SUPERCATEGORY_MASK 0x7F00u
+
+
+enum libcmap_bidirectional_supercategory {
+ LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_STRONG = 0x0100u,
+ LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_WEAK = 0x0200u,
+ LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_NEUTRAL = 0x0300u,
+ LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_EXPLICIT = 0x0400u
+};
+
+enum libcmap_bidirectional_category {
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT = LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_STRONG + 1u,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ARABIC,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER = LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_WEAK + 1u,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_SEPARATOR,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_TERMINATOR,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_ARABIC_NUMBER,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_COMMON_SEPARATOR,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_NONSPACING_MARK,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_BOUNDARY_NEUTRAL,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_PARAGRAPH_SEPARATOR = LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_NEUTRAL + 1u,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_SEGMENT_SEPARATOR,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_WHITESPACE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_OTHER_NEUTRALS,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_EMBEDDING = LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_EXPLICIT + 1u,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_OVERRIDE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_EMBEDDING,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_OVERRIDE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_FORMAT,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_ISOLATE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ISOLATE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_FIRST_STRONG_ISOLATE,
+ LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_ISOLATE
+};
+
+#define LIBCMAP_BIDIRECTIONAL_SUPERCATEGORY_MASK 0x7F00u
+
+
/**
* Contiguous range of Unicode codepoints
*
@@ -107,6 +189,52 @@ struct libcmap_script {
/**
+ * Information about a specific codepoint
+ */
+struct libcmap_codepoint_data {
+ /**
+ * The name as published in the Unicode Standard code charts
+ *
+ * It uniquely identifies the character unless it starts with '<'
+ */
+ const char *name;
+
+ /* TODO documentation is needed */
+ enum libcmap_general_category general_category;
+ enum libcmap_bidirectional_category bidirectional_category;
+ uint16_t canonical_combining_classes;
+ uint16_t bidirectional_mirrored;
+ const char *unicode_1_name;
+};
+
+
+/**
+ * Contiguous block of codepoints with
+ * data for each codepoint
+ */
+struct libcmap_codepoint_segment {
+ /**
+ * The range of codepoints the segment covers
+ */
+ struct libcmap_range range;
+
+ /**
+ * data for each codepoint in the segment,
+ *
+ * `.data[codepoint - .range.first]` gives the entry for
+ * a specific codepoint without [`.range.first, `.range.last`]
+ */
+ const struct libcmap_codepoint_data *data;
+};
+
+
+/**
+ * The version of the Unicode Standard that the library is
+ * compiled with data for
+ */
+extern const char *const libcmap_unicode_version;
+
+/**
* Listing of all Unicode codepoints not assigned any block
*
* This listing can potentially be empty
@@ -163,6 +291,23 @@ extern const struct libcmap_script *const libcmap_script_list;
*/
extern const size_t libcmap_script_list_size;
+/**
+ * Data about codepoints
+ *
+ * There are gaps, hence the list is segmented
+ *
+ * The list is sorted in ascending order
+ *
+ * @seealso libcmap_codepoint_list_size
+ * @seealso libcmap_find_codepoint_data
+ */
+extern const struct libcmap_codepoint_segment *const libcmap_codepoint_list;
+
+/**
+ * The number of elements in `libcmap_codepoint_list`
+ */
+extern const size_t libcmap_codepoint_list_size;
+
/**
* Find a codepoint within `libcmap_no_block`
@@ -237,6 +382,23 @@ const struct libcmap_script *libcmap_find_script(uint32_t codepoint, size_t *off
/**
+ * Find data about a specified codepoint
+ *
+ * @param codepoint The codepoint
+ * @return Information from UnicodeData about the codepoint,
+ * `NULL` if not found
+ *
+ * `NULL`-return doesn't necessary mean it is unassigned,
+ * but rather just that it doesn't appear in UnicodeData,
+ * which is common for ideographs
+ *
+ * @seealso libcmap_codepoint_list
+ */
+LIBCMAP_PURE_
+const struct libcmap_codepoint_data *libcmap_find_codepoint_data(uint32_t codepoint);
+
+
+/**
* Print a string representing a Unicode codepoint range
*
* @param buf Output buffer to print to, must be sufficiently large;
diff --git a/libcmap_codepoint_list.c b/libcmap_codepoint_list.c
new file mode 100644
index 0000000..d706441
--- /dev/null
+++ b/libcmap_codepoint_list.c
@@ -0,0 +1,68 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+#define GENERAL_CATEGORY_Lu LIBCMAP_GENERAL_CATEGORY_LETTER_UPPERCASE
+#define GENERAL_CATEGORY_Ll LIBCMAP_GENERAL_CATEGORY_LETTER_LOWERCASE
+#define GENERAL_CATEGORY_Lt LIBCMAP_GENERAL_CATEGORY_LETTER_TITLECASE
+#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_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
+#define GENERAL_CATEGORY_Pc LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CONNECTOR
+#define GENERAL_CATEGORY_Pd LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_DASH
+#define GENERAL_CATEGORY_Ps LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OPEN
+#define GENERAL_CATEGORY_Pe LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_CLOSE
+#define GENERAL_CATEGORY_Pi LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_INITIAL_QUOTE
+#define GENERAL_CATEGORY_Pf LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_FINAL_QUOTE
+#define GENERAL_CATEGORY_Po LIBCMAP_GENERAL_CATEGORY_PUNCTUATION_OTHER
+#define GENERAL_CATEGORY_Sm LIBCMAP_GENERAL_CATEGORY_SYMBOL_MATH
+#define GENERAL_CATEGORY_Sc LIBCMAP_GENERAL_CATEGORY_SYMBOL_CURRENCY
+#define GENERAL_CATEGORY_Sk LIBCMAP_GENERAL_CATEGORY_SYMBOL_MODIFIER
+#define GENERAL_CATEGORY_So LIBCMAP_GENERAL_CATEGORY_SYMBOL_OTHER
+#define GENERAL_CATEGORY_Zs LIBCMAP_GENERAL_CATEGORY_SEPARATOR_SPACE
+#define GENERAL_CATEGORY_Zl LIBCMAP_GENERAL_CATEGORY_SEPARATOR_LINE
+#define GENERAL_CATEGORY_Zp LIBCMAP_GENERAL_CATEGORY_SEPARATOR_PARAGRAPH
+#define GENERAL_CATEGORY_Cc LIBCMAP_GENERAL_CATEGORY_OTHER_CONTROL
+#define GENERAL_CATEGORY_Cf LIBCMAP_GENERAL_CATEGORY_OTHER_FORMAT
+#define GENERAL_CATEGORY_Cs LIBCMAP_GENERAL_CATEGORY_OTHER_SURROGATE
+#define GENERAL_CATEGORY_Co LIBCMAP_GENERAL_CATEGORY_OTHER_PRIVATE_USE
+/* #define GENERAL_CATEGORY_Cn LIBCMAP_GENERAL_CATEGORY_OTHER_NOT_ASSIGNED */
+
+#define BIDIRECTIONAL_CATEGORY_L LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT
+#define BIDIRECTIONAL_CATEGORY_R LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT
+#define BIDIRECTIONAL_CATEGORY_AL LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ARABIC
+#define BIDIRECTIONAL_CATEGORY_EN LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER
+#define BIDIRECTIONAL_CATEGORY_ES LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_SEPARATOR
+#define BIDIRECTIONAL_CATEGORY_ET LIBCMAP_BIDIRECTIONAL_CATEGORY_EUROPEAN_NUMBER_TERMINATOR
+#define BIDIRECTIONAL_CATEGORY_AN LIBCMAP_BIDIRECTIONAL_CATEGORY_ARABIC_NUMBER
+#define BIDIRECTIONAL_CATEGORY_CS LIBCMAP_BIDIRECTIONAL_CATEGORY_COMMON_SEPARATOR
+#define BIDIRECTIONAL_CATEGORY_NSM LIBCMAP_BIDIRECTIONAL_CATEGORY_NONSPACING_MARK
+#define BIDIRECTIONAL_CATEGORY_BN LIBCMAP_BIDIRECTIONAL_CATEGORY_BOUNDARY_NEUTRAL
+#define BIDIRECTIONAL_CATEGORY_B LIBCMAP_BIDIRECTIONAL_CATEGORY_PARAGRAPH_SEPARATOR
+#define BIDIRECTIONAL_CATEGORY_S LIBCMAP_BIDIRECTIONAL_CATEGORY_SEGMENT_SEPARATOR
+#define BIDIRECTIONAL_CATEGORY_WS LIBCMAP_BIDIRECTIONAL_CATEGORY_WHITESPACE
+#define BIDIRECTIONAL_CATEGORY_ON LIBCMAP_BIDIRECTIONAL_CATEGORY_OTHER_NEUTRALS
+#define BIDIRECTIONAL_CATEGORY_LRE LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_EMBEDDING
+#define BIDIRECTIONAL_CATEGORY_LRO LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_OVERRIDE
+#define BIDIRECTIONAL_CATEGORY_RLE LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_EMBEDDING
+#define BIDIRECTIONAL_CATEGORY_RLO LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_OVERRIDE
+#define BIDIRECTIONAL_CATEGORY_PDF LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_FORMAT
+#define BIDIRECTIONAL_CATEGORY_LRI LIBCMAP_BIDIRECTIONAL_CATEGORY_LEFT_TO_RIGHT_ISOLATE
+#define BIDIRECTIONAL_CATEGORY_RLI LIBCMAP_BIDIRECTIONAL_CATEGORY_RIGHT_TO_LEFT_ISOLATE
+#define BIDIRECTIONAL_CATEGORY_FSI LIBCMAP_BIDIRECTIONAL_CATEGORY_FIRST_STRONG_ISOLATE
+#define BIDIRECTIONAL_CATEGORY_PDI LIBCMAP_BIDIRECTIONAL_CATEGORY_POP_DIRECTIONAL_ISOLATE
+
+#define BIDIRECTIONAL_MIRRORED_Y 1u
+#define BIDIRECTIONAL_MIRRORED_N 0u
+
+
+
+#include "UnicodeData.txt.c"
+
+const struct libcmap_codepoint_segment *const libcmap_codepoint_list = list;
+const size_t libcmap_codepoint_list_size = sizeof(list) / sizeof(*list);
diff --git a/libcmap_find_codepoint_data.c b/libcmap_find_codepoint_data.c
new file mode 100644
index 0000000..cd2e52f
--- /dev/null
+++ b/libcmap_find_codepoint_data.c
@@ -0,0 +1,25 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const struct libcmap_codepoint_data *
+libcmap_find_codepoint_data(uint32_t codepoint)
+{
+ size_t low = 0u, high = libcmap_codepoint_list_size - 1u;
+ size_t i;
+
+ while (low <= high) {
+ i = low + (high - low) / 2u;
+ if (libcmap_codepoint_list[i].range.last < codepoint) {
+ low = i + 1u;
+ } else if (libcmap_codepoint_list[i].range.first > codepoint) {
+ if (!high)
+ break;
+ high = i - 1u;
+ } else {
+ return &libcmap_codepoint_list[i].data[codepoint - libcmap_codepoint_list[i].range.first];
+ }
+ }
+
+ return NULL;
+}
diff --git a/libcmap_unicode_version.c b/libcmap_unicode_version.c
new file mode 100644
index 0000000..5184701
--- /dev/null
+++ b/libcmap_unicode_version.c
@@ -0,0 +1,5 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+
+
+const char *const libcmap_unicode_version = UNICODE_VERSION;
diff --git a/parse-common.c b/parse-common.c
index 899debb..aeac342 100644
--- a/parse-common.c
+++ b/parse-common.c
@@ -1,6 +1,8 @@
/* See LICENSE file for copyright and license details. */
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>