/* Copyright © 2026 Lingenic LLC. All rights reserved. */
/* Licensed under the Lingenic Source-Available License v2.3. */
/* Production use requires a separate license from Licensor. */
/* See LICENSE.md and COPYRIGHT in the project root. */
/*-----------------------------------------------------------------------------
* Lingenic-Text
* Formally Verified Unicode Text Processing Library
*
* C API for the SPARK/Ada core (Unicode 17.0).
*
* The library core is formally verified with GNATprove: absence of
* runtime errors and functional correctness contracts are machine-checked.
* This C API is a thin validation shim: every argument is checked against
* the precondition of the proved subprogram it calls; violations return
* LT_ERR instead of invoking the core.
*
* Usage:
* lingenic_text_cinit(); // Ada elaboration (once)
* if (lt_init("path/to/ucd") != 0) // load UCD data tables
* ...error...
* ... call lt_* functions ...
* lingenic_text_cfinal(); // optional, at shutdown
*
* Link with: -llingenic_text_c (lib-c/liblingenic_text_c.a)
*
* Conventions:
* - all byte buffers are UTF-8 unless stated otherwise;
* - positions and indices are 0-based byte offsets;
* - functions return LT_ERR (-1) on invalid arguments or when the
* required modules are not initialized.
*---------------------------------------------------------------------------*/
#ifndef LINGENIC_TEXT_H
#define LINGENIC_TEXT_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/*---------------------------------------------------------------------------
* Error code
*---------------------------------------------------------------------------*/
#define LT_ERR (-1) /* invalid arguments / not initialized / internal */
/*---------------------------------------------------------------------------
* Elaboration (generated by gprbuild for the standalone library)
*---------------------------------------------------------------------------*/
/* Runs Ada elaboration for the library. Call once, before lt_init. */
extern void lingenic_text_cinit (void);
/* Runs Ada finalization. Optional; call at process shutdown. */
extern void lingenic_text_cfinal (void);
/*---------------------------------------------------------------------------
* Initialization
*---------------------------------------------------------------------------*/
/* Initialize all modules from the Unicode Character Database directory
* (the directory holding UnicodeData.txt, allkeys.txt, ...).
*
* Returns 0 on success, or the number of the stage that failed:
* 1 = properties, 2 = normalization, 3 = emoji, 4 = idna,
* 5 = bidi, 6 = case mapping, 7 = collation.
* Returns LT_ERR on invalid argument. */
int lt_init (const char *ucd_dir);
/* 1 if all modules are initialized, 0 otherwise. */
int lt_initialized (void);
/*---------------------------------------------------------------------------
* UTF-8 (RFC 3629)
*---------------------------------------------------------------------------*/
/* Decode one UTF-8 sequence at offset pos.
* Returns 1 if valid (*cp and *seq_len set), 0 if invalid at pos
* (*seq_len set to 1 for resynchronization), LT_ERR on bad arguments. */
int lt_utf8_decode (const uint8_t *buf, size_t len, size_t pos,
uint32_t *cp, size_t *seq_len);
/* Encode codepoint cp into buf (capacity cap). Writes 1..4 bytes.
* Returns 0 on success (*len set), LT_ERR if cp is not a Unicode scalar
* value or the buffer is too small. */
int lt_utf8_encode (uint32_t cp, uint8_t *buf, size_t cap, size_t *len);
/*---------------------------------------------------------------------------
* Segmentation (UAX #29, UAX #14)
*
* On success *next_pos is the offset of the next boundary after pos
* (pos < *next_pos <= len). Iterate from pos = 0 to enumerate all
* boundaries. Returns 0 on success, LT_ERR otherwise.
*---------------------------------------------------------------------------*/
int lt_next_grapheme_break (const uint8_t *text, size_t len, size_t pos,
size_t *next_pos);
int lt_next_word_break (const uint8_t *text, size_t len, size_t pos,
size_t *next_pos);
int lt_next_sentence_break (const uint8_t *text, size_t len, size_t pos,
size_t *next_pos);
int lt_next_line_break (const uint8_t *text, size_t len, size_t pos,
size_t *next_pos);
/*---------------------------------------------------------------------------
* Normalization (UAX #15)
*---------------------------------------------------------------------------*/
#define LT_NFD 0
#define LT_NFC 1
#define LT_NFKD 2
#define LT_NFKC 3
/* Normalize in_buf to the given form.
* Returns 0 = success (*out_len set), 1 = output buffer too small,
* 2 = invalid UTF-8 input, LT_ERR = bad arguments / not initialized. */
int lt_normalize (int form,
const uint8_t *in_buf, size_t in_len,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
#define LT_QC_YES 0
#define LT_QC_NO 1
#define LT_QC_MAYBE 2
/* Quick check (UAX #15 Section 9). Returns LT_QC_*, or LT_ERR. */
int lt_quick_check (int form, const uint8_t *in_buf, size_t in_len);
/* Definitive check. Returns 1 = normalized, 0 = not, LT_ERR on error. */
int lt_is_normalized (int form, const uint8_t *in_buf, size_t in_len);
/* Canonical Combining Class (0..254), LT_ERR on error. */
int lt_ccc (uint32_t cp);
/*---------------------------------------------------------------------------
* Case mapping (Unicode Section 3.13, full mappings)
*
* Output may be up to 3x the input length.
* Returns 0 = success (*out_len set), 1 = output buffer too small,
* 2 = invalid UTF-8 input, LT_ERR = bad arguments / not initialized.
*---------------------------------------------------------------------------*/
int lt_uppercase (const uint8_t *in_buf, size_t in_len,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
int lt_lowercase (const uint8_t *in_buf, size_t in_len,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
int lt_titlecase (const uint8_t *in_buf, size_t in_len,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
int lt_casefold (const uint8_t *in_buf, size_t in_len,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
/* D135 Cased / D136 Case_Ignorable. 1/0, LT_ERR on error. */
int lt_is_cased (uint32_t cp);
int lt_is_case_ignorable (uint32_t cp);
/*---------------------------------------------------------------------------
* Collation (UTS #10, DUCET)
*---------------------------------------------------------------------------*/
#define LT_COLLATE_NON_IGNORABLE 0
#define LT_COLLATE_SHIFTED 1
/* Compare two UTF-8 strings. *result is -1 (a < b), 0 (equal),
* 1 (a > b). Returns 0 on success, 1 if either input is invalid UTF-8
* or too long, LT_ERR on bad arguments / not initialized. */
int lt_collate (const uint8_t *a, size_t a_len,
const uint8_t *b, size_t b_len,
int option, int *result);
/* Build a binary sort key (memcmp-comparable).
* Returns 0 on success (*key_len set), 1 on failure (invalid input or
* key buffer too small), LT_ERR on bad arguments / not initialized. */
int lt_sort_key (const uint8_t *in_buf, size_t in_len, int option,
uint8_t *key, size_t key_cap, size_t *key_len);
/*---------------------------------------------------------------------------
* Bidirectional algorithm (UAX #9)
*
* Paragraphs are limited to 4096 codepoints; embedding levels are 0..126.
*---------------------------------------------------------------------------*/
#define LT_DIR_AUTO 0 /* determine direction by rules P2/P3 */
#define LT_DIR_LTR 1
#define LT_DIR_RTL 2
/* Resolve embedding levels for a UTF-8 paragraph.
* levels receives one level per codepoint (levels_cap must be >= the
* number of codepoints; len is always sufficient).
* Returns 0 on success (*num_cps and *para_level set), 1 if the
* algorithm rejects the input (invalid UTF-8, too many codepoints),
* LT_ERR on bad arguments. */
int lt_bidi_resolve (const uint8_t *text, size_t len, int direction,
uint8_t *levels, size_t levels_cap,
size_t *num_cps, uint8_t *para_level);
/* Compute the visual order (rule L2). order receives num_cps 0-based
* logical indices: order[i] is the logical index of the codepoint shown
* at visual position i. Returns 0 on success, 1 on failure, LT_ERR on
* bad arguments (num_cps must be 1..4096, levels[i] <= 126). */
int lt_bidi_reorder (const uint8_t *levels, size_t num_cps,
uint8_t para_level,
uint32_t *order, size_t order_cap);
/* Rule L4: 1 if cp should be depicted mirrored at the given embedding
* level, 0 if not, LT_ERR on error. */
int lt_bidi_needs_mirror (uint32_t cp, uint8_t level);
/*---------------------------------------------------------------------------
* East Asian Width (UAX #11)
*---------------------------------------------------------------------------*/
/* Display width in fixed-pitch cells: 1 or 2. LT_ERR on error. */
int lt_display_width (uint32_t cp);
/*---------------------------------------------------------------------------
* Emoji (UTS #51)
*---------------------------------------------------------------------------*/
/* Binary emoji properties. 1/0, LT_ERR on error. */
int lt_is_emoji (uint32_t cp);
int lt_is_emoji_presentation (uint32_t cp);
int lt_is_emoji_modifier (uint32_t cp);
int lt_is_emoji_modifier_base (uint32_t cp);
int lt_is_emoji_component (uint32_t cp);
#define LT_EMOJI_NOT_EMOJI 0
#define LT_EMOJI_CHARACTER 1 /* single emoji codepoint */
#define LT_EMOJI_PRESENTATION_SEQ 2 /* emoji + VS16 (U+FE0F) */
#define LT_EMOJI_KEYCAP_SEQ 3 /* base + VS16 + U+20E3 */
#define LT_EMOJI_MODIFIER_SEQ 4 /* modifier base + skin tone */
#define LT_EMOJI_FLAG_SEQ 5 /* regional indicator pair */
#define LT_EMOJI_TAG_SEQ 6 /* tag base + tag spec + cancel tag */
#define LT_EMOJI_ZWJ_SEQ 7 /* elements joined by ZWJ (U+200D) */
/* Classify a UTF-8 sequence (max 256 bytes) as an emoji sequence.
* Returns an LT_EMOJI_* value, or LT_ERR on error. */
int lt_emoji_classify (const uint8_t *in_buf, size_t in_len);
/*---------------------------------------------------------------------------
* Identifiers (UAX #31)
*---------------------------------------------------------------------------*/
/* XID_Start / XID_Continue. 1/0, LT_ERR on error. */
int lt_is_identifier_start (uint32_t cp);
int lt_is_identifier_part (uint32_t cp);
/*---------------------------------------------------------------------------
* IDNA (UTS #46, nontransitional processing)
*---------------------------------------------------------------------------*/
/* Option bits */
#define LT_IDNA_CHECK_HYPHENS 0x01u
#define LT_IDNA_CHECK_BIDI 0x02u
#define LT_IDNA_CHECK_JOINERS 0x04u
#define LT_IDNA_USE_STD3_RULES 0x08u
#define LT_IDNA_VERIFY_DNS_LENGTH 0x10u
#define LT_IDNA_DEFAULT 0x1Fu
/* Result codes */
#define LT_IDNA_SUCCESS 0
#define LT_IDNA_INVALID_INPUT 1
#define LT_IDNA_DISALLOWED_CODEPOINT 2
#define LT_IDNA_LABEL_TOO_LONG 3
#define LT_IDNA_DOMAIN_TOO_LONG 4
#define LT_IDNA_INVALID_HYPHEN 5
#define LT_IDNA_LEADING_COMBINING_MARK 6
#define LT_IDNA_NFC_FAILURE 7
#define LT_IDNA_BIDI_FAILURE 8
#define LT_IDNA_CONTEXTJ_FAILURE 9
#define LT_IDNA_PUNYCODE_FAILURE 10
#define LT_IDNA_BUFFER_OVERFLOW 11
#define LT_IDNA_STD3_FAILURE 12
#define LT_IDNA_TOO_MANY_LABELS 13
#define LT_IDNA_EMPTY_LABEL 14
/* Convert a UTF-8 domain name to ASCII-Compatible Encoding (Punycode).
* Returns LT_IDNA_SUCCESS with *out_len set, another LT_IDNA_* code on
* failure, or LT_ERR on bad arguments / not initialized. */
int lt_idna_to_ascii (const uint8_t *in_buf, size_t in_len,
uint32_t options,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
/* Convert a domain name (ACE or UTF-8) to Unicode (UTF-8 output). */
int lt_idna_to_unicode (const uint8_t *in_buf, size_t in_len,
uint32_t options,
uint8_t *out_buf, size_t out_cap, size_t *out_len);
/*---------------------------------------------------------------------------
* Character properties
*---------------------------------------------------------------------------*/
/* Script (UAX #24). Returns a runtime index into the script name table
* (indices are stable within one lt_init but are data-derived; use
* lt_script_name to obtain the name). LT_ERR on error. */
int lt_script (uint32_t cp);
/* Number of scripts in the name table. LT_ERR on error. */
int lt_script_count (void);
/* Copy the NUL-terminated script name for index idx into buf.
* Returns the name length, or LT_ERR if idx is out of range or the
* buffer is too small. */
int lt_script_name (int idx, char *buf, size_t cap);
/* Script_Extensions: number of scripts in cp's extension set. */
int lt_script_extension_count (uint32_t cp);
/* k-th (0-based) script index of cp's extension set. */
int lt_script_extension (uint32_t cp, int k);
/* 1 if script_idx is in cp's Script_Extensions set, 0 if not. */
int lt_in_script_extensions (uint32_t cp, int script_idx);
/* General_Category (UAX #44). Runtime index into the GC name table
* (e.g. "Lu", "Nd"); same conventions as lt_script. */
int lt_general_category (uint32_t cp);
int lt_general_category_count (void);
int lt_general_category_name (int idx, char *buf, size_t cap);
/* Grapheme_Cluster_Break values */
#define LT_GBP_OTHER 0
#define LT_GBP_CR 1
#define LT_GBP_LF 2
#define LT_GBP_CONTROL 3
#define LT_GBP_EXTEND 4
#define LT_GBP_ZWJ 5
#define LT_GBP_REGIONAL_INDICATOR 6
#define LT_GBP_PREPEND 7
#define LT_GBP_SPACINGMARK 8
#define LT_GBP_L 9
#define LT_GBP_V 10
#define LT_GBP_T 11
#define LT_GBP_LV 12
#define LT_GBP_LVT 13
int lt_grapheme_break_property (uint32_t cp);
/* Word_Break values */
#define LT_WBP_OTHER 0
#define LT_WBP_CR 1
#define LT_WBP_LF 2
#define LT_WBP_NEWLINE 3
#define LT_WBP_EXTEND 4
#define LT_WBP_ZWJ 5
#define LT_WBP_REGIONAL_INDICATOR 6
#define LT_WBP_FORMAT 7
#define LT_WBP_KATAKANA 8
#define LT_WBP_HEBREW_LETTER 9
#define LT_WBP_ALETTER 10
#define LT_WBP_SINGLE_QUOTE 11
#define LT_WBP_DOUBLE_QUOTE 12
#define LT_WBP_MIDNUMLET 13
#define LT_WBP_MIDLETTER 14
#define LT_WBP_MIDNUM 15
#define LT_WBP_NUMERIC 16
#define LT_WBP_EXTENDNUMLET 17
#define LT_WBP_WSEGSPACE 18
int lt_word_break_property (uint32_t cp);
/* Sentence_Break values */
#define LT_SBP_OTHER 0
#define LT_SBP_CR 1
#define LT_SBP_LF 2
#define LT_SBP_SEP 3
#define LT_SBP_EXTEND 4
#define LT_SBP_FORMAT 5
#define LT_SBP_SP 6
#define LT_SBP_LOWER 7
#define LT_SBP_UPPER 8
#define LT_SBP_OLETTER 9
#define LT_SBP_NUMERIC 10
#define LT_SBP_ATERM 11
#define LT_SBP_STERM 12
#define LT_SBP_SCONTINUE 13
#define LT_SBP_CLOSE 14
int lt_sentence_break_property (uint32_t cp);
/* Line_Break values (resolved per LB1) */
#define LT_LBP_OTHER 0
#define LT_LBP_BK 1
#define LT_LBP_CR 2
#define LT_LBP_LF 3
#define LT_LBP_NL 4
#define LT_LBP_CM 5
#define LT_LBP_WJ 6
#define LT_LBP_ZW 7
#define LT_LBP_GL 8
#define LT_LBP_SP 9
#define LT_LBP_ZWJ 10
#define LT_LBP_B2 11
#define LT_LBP_BA 12
#define LT_LBP_BB 13
#define LT_LBP_HY 14
#define LT_LBP_CB 15
#define LT_LBP_CL 16
#define LT_LBP_CP 17
#define LT_LBP_CP_EA 18
#define LT_LBP_EX 19
#define LT_LBP_IN 20
#define LT_LBP_NS 21
#define LT_LBP_OP 22
#define LT_LBP_OP_EA 23
#define LT_LBP_QU 24
#define LT_LBP_QU_PI 25
#define LT_LBP_QU_PF 26
#define LT_LBP_IS 27
#define LT_LBP_NU 28
#define LT_LBP_PO 29
#define LT_LBP_PR 30
#define LT_LBP_SY 31
#define LT_LBP_AL 32
#define LT_LBP_HL 33
#define LT_LBP_AK 34
#define LT_LBP_AP 35
#define LT_LBP_AS 36
#define LT_LBP_VF 37
#define LT_LBP_VI 38
#define LT_LBP_EB 39
#define LT_LBP_EM 40
#define LT_LBP_H2 41
#define LT_LBP_H3 42
#define LT_LBP_JL 43
#define LT_LBP_JV 44
#define LT_LBP_JT 45
#define LT_LBP_RI 46
#define LT_LBP_ID 47
#define LT_LBP_HH 48
int lt_line_break_property (uint32_t cp);
/* East_Asian_Width values */
#define LT_EAW_NEUTRAL 0
#define LT_EAW_AMBIGUOUS 1
#define LT_EAW_HALFWIDTH 2
#define LT_EAW_WIDE 3
#define LT_EAW_FULLWIDTH 4
#define LT_EAW_NARROW 5
int lt_east_asian_width (uint32_t cp);
/* Bidi_Class values (resolved with @missing defaults) */
#define LT_BC_DEFAULT 0
#define LT_BC_L 1
#define LT_BC_R 2
#define LT_BC_AL 3
#define LT_BC_EN 4
#define LT_BC_ES 5
#define LT_BC_ET 6
#define LT_BC_AN 7
#define LT_BC_CS 8
#define LT_BC_NSM 9
#define LT_BC_BN 10
#define LT_BC_B 11
#define LT_BC_S 12
#define LT_BC_WS 13
#define LT_BC_ON 14
#define LT_BC_LRE 15
#define LT_BC_LRO 16
#define LT_BC_RLE 17
#define LT_BC_RLO 18
#define LT_BC_PDF 19
#define LT_BC_LRI 20
#define LT_BC_RLI 21
#define LT_BC_FSI 22
#define LT_BC_PDI 23
int lt_bidi_class (uint32_t cp);
/* Joining_Type values */
#define LT_JT_U 0 /* Non_Joining (default) */
#define LT_JT_L 1 /* Left_Joining */
#define LT_JT_R 2 /* Right_Joining */
#define LT_JT_D 3 /* Dual_Joining */
#define LT_JT_C 4 /* Join_Causing */
#define LT_JT_T 5 /* Transparent */
int lt_joining_type (uint32_t cp);
/* Indic_Conjunct_Break values */
#define LT_INCB_NONE 0
#define LT_INCB_CONSONANT 1
#define LT_INCB_LINKER 2
#define LT_INCB_EXTEND 3
int lt_indic_conjunct_break (uint32_t cp);
/* Extended_Pictographic. 1/0, LT_ERR on error. */
int lt_extended_pictographic (uint32_t cp);
/* Bidi_Mirrored (UnicodeData field 9). 1/0, LT_ERR on error. */
int lt_bidi_mirrored (uint32_t cp);
#ifdef __cplusplus
}
#endif
#endif /* LINGENIC_TEXT_H */
/* Copyright © 2026 Lingenic LLC. All rights reserved. */
/* Licensed under the Lingenic Source-Available License v2.3. */
/* Production use requires a separate license from Licensor. */
/* See LICENSE.md and COPYRIGHT in the project root. */
/*-----------------------------------------------------------------------------
* Lingenic-Text
* Formally Verified Unicode Text Processing Library
*
* C API for the SPARK/Ada core (Unicode 17.0).
*
* The library core is formally verified with GNATprove: absence of
* runtime errors and functional correctness contracts are machine-checked.
* This C API is a thin validation shim: every argument is checked against
* the precondition of the proved subprogram it calls; violations return
* LT_ERR instead of invoking the core.
*
* Usage:
* lingenic_text_cinit(); // Ada elaboration (once)
* if (lt_init("path/to/ucd") != 0) // load UCD data tables
* ...error...
* ... call lt_* functions ...
* lingenic_text_cfinal(); // optional, at shutdown
*
* Link with: -llingenic_text_c (lib-c/liblingenic_text_c.a)
*
* Conventions:
* - all byte buffers are UTF-8 unless stated otherwise;
* - positions and indices are 0-based byte offsets;
* - functions return LT_ERR (-1) on invalid arguments or when the
* required modules are not initialized.
*---------------------------------------------------------------------------*/
extern "C" __cplusplus
}
/* LINGENIC_TEXT_H */