「‍」 Lingenic

lingenic_text

(⤓.h ◇.h); γ ≜ [2026-07-12T135619.243, 2026-07-12T135619.243] ∧ |γ| = 1

/*  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 */