File locale_support.c¶
File List > base > locale_support.c
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* locale_support.c : Locale support using LDML (XML) files
*/
#ident "$Id$"
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "porting.h"
#include "environment_variable.h"
#include "utility.h"
#include "xml_parser.h"
#include "chartype.h"
#include "error_manager.h"
#include "release_string.h"
#include "uca_support.h"
#include "unicode_support.h"
#include "message_catalog.h"
#include "language_support.h"
#include "system_parameter.h"
#include "crypt_opfunc.h"
#if !defined(WINDOWS)
#include <netinet/in.h>
#endif /* !WINDOWS */
#include "locale_support.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"
#if defined (SUPPRESS_STRLEN_WARNING)
#define strlen(s1) ((int) strlen(s1))
#endif /* defined (SUPPRESS_STRLEN_WARNING) */
#if defined(_WIN32) || defined(WINDOWS) || defined(WIN64)
#define DLL_EXPORT_PREFIX "__declspec(dllexport) "
#define LOCLIB_FILE_EXT "dll"
#else
#define DLL_EXPORT_PREFIX ""
#define LOCLIB_FILE_EXT "so"
#endif
#if defined(SA_MODE)
#define TXT_CONV_LINE_SIZE 512
#define TXT_CONV_ITEM_GROW_COUNT 128
#define LOC_CURRENT_COLL_TAIL(ld) (&(ld->collations[ld->coll_cnt].tail_coll))
const char *const ldml_ref_day_names[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
/* this must map to 'Am_Pm_name' from string_opfunc.c */
const char *const ldml_ref_am_pm_names[] = { "am", "pm", "Am", "Pm", "AM", "PM",
"a.m.", "p.m.", "A.m.", "P.m.", "A.M.", "P.M."
};
typedef struct
{
unsigned int text_cp;
unsigned int unicode_cp;
} TXT_CONV_ITEM;
/* shared data : this is used during genlocale process
* data shared by several locales are centralized here; and saved only once
* in the generated libray */
typedef enum
{
LOC_SHARED_COLLATION = 0,
LOC_SHARED_ALPHABET = 1,
LOC_SHARED_NORMALIZATION = 2
} LOC_SHARED_DATA_TYPE;
typedef struct
{
LOC_SHARED_DATA_TYPE lsd_type;
char lsd_key[COLL_NAME_SIZE];
/* print size of an integer */
#define COLL_SHARED_DATA_SIZE (10 + 2)
void *data;
LDML_CONTEXT ldml_context;
} LOC_SHARED_DATA;
static LOC_SHARED_DATA *shared_data = NULL;
static int count_shared_data = 0;
static int alloced_shared_data = 0;
static void locale_init_data (LOCALE_DATA * ld, const char *locale_name);
static void locale_destroy_alphabet_data (const ALPHABET_DATA * a);
static void locale_destroy_normalization_data (UNICODE_NORMALIZATION * norm);
static int start_element_ok (void *data, const char **attr);
static int end_element_ok (void *data, const char *el_name);
static int start_calendar (void *data, const char **attr);
static int end_dateFormatCUBRID (void *data, const char *el_name);
static int end_timeFormatCUBRID (void *data, const char *el_name);
static int end_datetimeFormatCUBRID (void *data, const char *el_name);
static int end_timestampFormatCUBRID (void *data, const char *el_name);
static int end_timetzFormatCUBRID (void *data, const char *el_name);
static int end_datetimetzFormatCUBRID (void *data, const char *el_name);
static int end_timestamptzFormatCUBRID (void *data, const char *el_name);
static int start_calendar_name_context (void *data, const char **attr);
static int start_month_day_Width (void *data, const char **attr);
static int end_month_day_Width (void *data, const char *el_name);
static int start_month (void *data, const char **attr);
static int end_month (void *data, const char *el_name);
static int start_day (void *data, const char **attr);
static int end_day (void *data, const char *el_name);
static int start_dayPeriodWidth (void *data, const char **attr);
static int start_dayPeriod (void *data, const char **attr);
static int end_dayPeriod (void *data, const char *el_name);
static int start_numbers_symbols (void *data, const char **attr);
static int start_currency (void *data, const char **attr);
static int end_number_symbol (void *data, const char *el_name);
static int start_collations (void *data, const char **attr);
static int start_one_collation (void *data, const char **attr);
static int end_one_collation (void *data, const char *el_name);
static int start_collation_settings (void *data, const char **attr);
static int start_collation_reset (void *data, const char **attr);
static int end_collation_reset (void *data, const char *el_name);
static int start_collation_rule (void *data, const char **attr);
static int start_collation_cubrid_rule (void *data, const char **attr);
static int start_collation_cubrid_rule_set_wr (void *data, const char **attr);
static int end_collation_cubrid_rule_set (void *data, const char *el_name);
static int end_collation_cubrid_rule_set_cp_ch (void *data, const char *el_name);
static int end_collation_cubrid_rule_set_ech_ecp (void *data, const char *el_name);
static int end_collation_cubrid_rule_set_w_wr (void *data, const char *el_name);
static int handle_data_collation_rule (void *data, const char *s, int len);
static int end_collation_rule (void *data, const char *el_name);
static int start_collation_x (void *data, const char **attr);
static int end_collation_x (void *data, const char *el_name);
static int end_collation_x_rule (void *data, const char *el_name);
static int end_collation_x_extend (void *data, const char *el_name);
static int end_collation_x_context (void *data, const char *el_name);
static int start_collation_logical_pos (void *data, const char **attr);
static int end_collation_logical_pos (void *data, const char *el_name);
static int start_one_alphabet (void *data, const char **attr);
static int start_upper_case_rule (void *data, const char **attr);
static int end_case_rule (void *data, const char *el_name);
static int start_lower_case_rule (void *data, const char **attr);
static int end_transform_buffer (void *data, const char *el_name);
static int start_include_collation (void *data, const char **attr);
static int start_unicode_file (void *data, const char **attr);
static int start_consoleconversion (void *data, const char **attr);
static int handle_data (void *data, const char *s, int len);
static void clear_data_buffer (XML_PARSER_DATA * pd);
static LOCALE_COLLATION *new_locale_collation (LOCALE_DATA * ld);
static TAILOR_RULE *new_collation_rule (LOCALE_DATA * ld);
static TRANSFORM_RULE *new_transform_rule (LOCALE_DATA * ld);
static CUBRID_TAILOR_RULE *new_collation_cubrid_rule (LOCALE_DATA * ld);
static void locale_alloc_collation_id (COLL_TAILORING * coll_tail);
static int locale_check_collation_id (const COLL_TAILORING * coll_tail);
static void print_debug_start_el (void *data, const char **attrs, const char *msg, const int status);
static void print_debug_end_el (void *data, const char *msg, const int status);
static void print_debug_data_content (void *data, const char *msg, const int status);
static int load_console_conv_data (LOCALE_DATA * ld, bool is_verbose);
static int locale_save_to_C_file (LOCALE_FILE lf, LOCALE_DATA * ld);
static int locale_save_calendar_to_C_file (FILE * fp, LOCALE_DATA * ld);
static int locale_save_alphabets_to_C_file (FILE * fp, LOCALE_DATA * ld);
static int locale_save_one_alphabet_to_C_file (FILE * fp, ALPHABET_DATA * a, bool save_w_identier_name,
const char *alpha_suffix);
static int locale_save_collation_data_to_C_file (FILE * fp, LOCALE_COLLATION * lc);
static int locale_save_console_conv_to_C_file (FILE * fp, LOCALE_DATA * ld);
static int locale_save_normalization_to_C_file (FILE * fp, LOCALE_DATA * ld);
static void locale_destroy_collation_tailorings (const COLL_TAILORING * ct);
static void locale_destroy_collation_data (const COLL_DATA * cd);
static void locale_destroy_alphabet_tailoring (const ALPHABET_TAILORING * cd);
static void locale_destroy_console_conversion (const TEXT_CONVERSION * tc);
static int dump_locale_alphabet (ALPHABET_DATA * ad, int dl_settings, int lower_bound, int upper_bound);
static void dump_collation_key (COLL_DATA * coll, const unsigned int key, bool print_weight, bool print_key);
static void dump_collation_contr (COLL_DATA * coll, const COLL_CONTRACTION * contr, bool print_weight,
bool print_contr);
static void dump_collation_codepoint (COLL_DATA * coll, const unsigned int cp, bool print_weight, bool print_cp);
static void dump_locale_normalization (UNICODE_NORMALIZATION * norm);
static void dump_unicode_mapping (UNICODE_MAPPING * um, const int mode);
static int dump_console_conversion (TEXT_CONVERSION * tc);
static int comp_func_coll_uca_exp_fo (const void *arg1, const void *arg2);
static int comp_func_coll_uca_exp (const void *arg1, const void *arg2);
static int comp_func_coll_uca_simple_weights_fo (const void *arg1, const void *arg2);
static int comp_func_coll_uca_simple_weights (const void *arg1, const void *arg2);
static int comp_func_parse_order_index (const void *arg1, const void *arg2);
static void locale_make_calendar_parse_order (LOCALE_DATA * ld);
static int locale_check_and_set_shared_data (const LOC_SHARED_DATA_TYPE lsd_type, const char *lsd_key, const void *data,
LDML_CONTEXT * ldml_context, LOC_SHARED_DATA ** found_entry);
static int locale_compute_coll_checksum (COLL_DATA * cd);
static int locale_alphabet_data_size (ALPHABET_DATA * a);
static int locale_alphabet_data_to_buf (ALPHABET_DATA * a, char *buf);
static int locale_compute_locale_checksum (LOCALE_DATA * ld);
static int common_collation_end_rule (void *data, LOCALE_DATA * ld, const int rule_id, TAILOR_RULE * t_rule);
static int common_collation_start_rule (void *data, const char **attr, LOCALE_DATA * ld, TAILOR_RULE * t_rule);
#endif //#if defined(SA_MODE)
static int str_pop_token (char *str_p, char **token_p, char **next_p);
#if defined(SA_MODE)
#define PRINT_DEBUG_START(d, a, m, s) \
do { \
print_debug_start_el (d, a, m, s); \
} while (0);
#define PRINT_DEBUG_END(d, m, s) \
do { \
print_debug_end_el (d, m, s); \
} while (0);
#define PRINT_DEBUG_DATA(d, m, s) \
do { \
print_debug_data_content (d, m, s); \
} while (0);
#define PRINT_TO_C_FILE_MAX_INT_LINE 10
#define PRINT_STRING_TO_C_FILE(fp, val, len) \
do { \
int istr; \
fprintf (fp, "\""); \
for (istr = 0; istr < len; istr++) \
{ \
fprintf (fp, "\\x%02X", (unsigned char) val[istr]); \
} \
fprintf (fp, "\""); \
} while (0);
#define PRINT_VAR_TO_C_FILE(fp, type, valname, val, format, d) \
do { \
fprintf (fp, "\n" DLL_EXPORT_PREFIX "const " \
type " " valname "_%s = " format ";\n", d, val); \
} while (0);
#define PRINT_STRING_VAR_TO_C_FILE(fp, valname, val, d) \
do { \
fprintf (fp, "\n" DLL_EXPORT_PREFIX "const char " valname "_%s[] = ", d); \
PRINT_STRING_TO_C_FILE (fp, val, strlen (val)); \
fprintf (fp, ";\n"); \
} while (0);
#define PRINT_STRING_ARRAY_TO_C_FILE(fp, valname, arrcount, val, d) \
do { \
int istrarr; \
fprintf(fp, "\n" DLL_EXPORT_PREFIX"const char* " valname "_%s[] = {\n", d);\
for (istrarr = 0; istrarr < arrcount; istrarr++) \
{ \
fprintf(fp, "\t"); \
PRINT_STRING_TO_C_FILE (fp, val[istrarr], strlen(val[istrarr])); \
if (istrarr < arrcount - 1) \
{ \
fprintf(fp, ",\n"); \
} \
else \
{ \
fprintf(fp, "\n"); \
} \
} \
fprintf(fp, "};\n"); \
} while (0);
#define PRINT_NUM_ARRAY_TO_C_FILE(fp, vname, vtype, intf, arrcount, val, d) \
do { \
int i_arr, j_arr; \
fprintf(fp, \
"\n" DLL_EXPORT_PREFIX "const " vtype " " vname "_%s[] = {\n", d); \
j_arr = 1; \
for (i_arr = 0; i_arr < arrcount; i_arr++) \
{ \
fprintf(fp, "\t"); \
fprintf(fp, intf, val[i_arr]); \
if (i_arr < arrcount - 1) \
{ \
fprintf(fp, ","); \
} \
j_arr++; \
if (j_arr > PRINT_TO_C_FILE_MAX_INT_LINE) \
{ \
j_arr = 1; \
fprintf(fp, "\n"); \
} \
} \
fprintf(fp, "};\n"); \
} while (0);
#define PRINT_UNNAMED_NUM_ARRAY_TO_C_FILE(fp, intf, tab, arrcount, val) \
do { \
int i_uarr, j_uarr; \
fprintf(fp, tab"{\n"); \
j_uarr = 1; \
for (i_uarr = 0; i_uarr < arrcount; i_uarr++) \
{ \
fprintf(fp, intf, val[i_uarr]); \
if (i_uarr < arrcount - 1) \
{ \
fprintf(fp, ","); \
} \
j_uarr++; \
if (j_uarr > PRINT_TO_C_FILE_MAX_INT_LINE) \
{ \
j_uarr = 1; \
fprintf(fp, "\n" tab); \
} \
} \
fprintf(fp, "\n" tab "}"); \
} while (0);
#define XML_COMMENT_START "<!-- "
#define XML_COMMENT_END " -->"
static COLL_DATA *dump_coll_data = NULL;
static char *cmp_token_name_array = NULL;
static char cmp_token_name_size = 0;
/*
* LDML element definition (XML schema)
* full name is the "path" - the names of all parent elements down to
* the element
*/
const XML_ELEMENT_DEF ldml_elem_ldml = { "ldml", 1, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_dates = { "ldml dates", 2, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_calendars = { "ldml dates calendars", 3, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_calendar = { "ldml dates calendars calendar", 4, (ELEM_START_FUNC) (&start_calendar),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_dateFormatCUBRID = { "ldml dates calendars calendar dateFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_dateFormatCUBRID), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_timeFormatCUBRID = { "ldml dates calendars calendar timeFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_timeFormatCUBRID), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_datetimeFormatCUBRID = { "ldml dates calendars calendar datetimeFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_datetimeFormatCUBRID), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_timestampFormatCUBRID = { "ldml dates calendars calendar timestampFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_timestampFormatCUBRID),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_timetzFormatCUBRID = { "ldml dates calendars calendar timetzFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_timetzFormatCUBRID),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_datetimetzFormatCUBRID = { "ldml dates calendars calendar datetimetzFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_datetimetzFormatCUBRID),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_timestamptzFormatCUBRID = { "ldml dates calendars calendar timestamptzFormatCUBRID", 5,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_timestamptzFormatCUBRID),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_months = { "ldml dates calendars calendar months", 5,
(ELEM_START_FUNC) (&start_element_ok), (ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_monthContext = { "ldml dates calendars calendar months monthContext", 6,
(ELEM_START_FUNC) (&start_calendar_name_context),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_monthWidth = { "ldml dates calendars calendar months monthContext monthWidth", 7,
(ELEM_START_FUNC) (&start_month_day_Width),
(ELEM_END_FUNC) (&end_month_day_Width), NULL
};
const XML_ELEMENT_DEF ldml_elem_month = { "ldml dates calendars calendar months monthContext monthWidth month", 8,
(ELEM_START_FUNC) (&start_month), (ELEM_END_FUNC) (&end_month),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_days = { "ldml dates calendars calendar days", 5,
(ELEM_START_FUNC) (&start_element_ok), (ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_dayContext = { "ldml dates calendars calendar days dayContext", 6,
(ELEM_START_FUNC) (&start_calendar_name_context),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_dayWidth = { "ldml dates calendars calendar days dayContext dayWidth", 7,
(ELEM_START_FUNC) (&start_month_day_Width),
(ELEM_END_FUNC) (&end_month_day_Width), NULL
};
const XML_ELEMENT_DEF ldml_elem_day = { "ldml dates calendars calendar days dayContext dayWidth day", 8,
(ELEM_START_FUNC) (&start_day), (ELEM_END_FUNC) (&end_day),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_dayPeriods = { "ldml dates calendars calendar dayPeriods", 5,
(ELEM_START_FUNC) (&start_element_ok), (ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_dayPeriodContext = { "ldml dates calendars calendar dayPeriods dayPeriodContext", 6,
(ELEM_START_FUNC) (&start_calendar_name_context),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_dayPeriodWidth = {
"ldml dates calendars calendar dayPeriods dayPeriodContext dayPeriodWidth",
7,
(ELEM_START_FUNC) (&start_dayPeriodWidth),
(ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_dayPeriod = {
"ldml dates calendars calendar dayPeriods dayPeriodContext dayPeriodWidth dayPeriod",
8,
(ELEM_START_FUNC) (&start_dayPeriod), (ELEM_END_FUNC) (&end_dayPeriod),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_numbers = { "ldml numbers", 2, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_numbers_symbols =
{ "ldml numbers symbols", 3, (ELEM_START_FUNC) (&start_numbers_symbols),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_symbol_decimal =
{ "ldml numbers symbols decimal", 4, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_number_symbol), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_symbol_group = { "ldml numbers symbols group", 4, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_number_symbol), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_currencies = { "ldml numbers currencies", 3, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_currency = { "ldml numbers currencies currency", 4,
(ELEM_START_FUNC) (&start_currency),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_collations = { "ldml collations", 2, (ELEM_START_FUNC) (&start_collations),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation = { "ldml collations collation", 3, (ELEM_START_FUNC) (&start_one_collation),
(ELEM_END_FUNC) (&end_one_collation), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_rules = { "ldml collations collation rules", 4,
(ELEM_START_FUNC) (&start_element_ok), (ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_settings = { "ldml collations collation settings", 4,
(ELEM_START_FUNC) (&start_collation_settings),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset = { "ldml collations collation rules reset", 5,
(ELEM_START_FUNC) (&start_collation_reset),
(ELEM_END_FUNC) (&end_collation_reset), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_p = { "ldml collations collation rules p", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_s = { "ldml collations collation rules s", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_t = { "ldml collations collation rules t", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_i = { "ldml collations collation rules i", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_pc = { "ldml collations collation rules pc", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_sc = { "ldml collations collation rules sc", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_tc = { "ldml collations collation rules tc", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_ic = { "ldml collations collation rules ic", 5,
(ELEM_START_FUNC) (&start_collation_rule),
(ELEM_END_FUNC) (&end_collation_rule),
(ELEM_DATA_FUNC) (&handle_data_collation_rule)
};
const XML_ELEMENT_DEF ldml_elem_collation_x = { "ldml collations collation rules x", 5,
(ELEM_START_FUNC) (&start_collation_x), (ELEM_END_FUNC) (&end_collation_x),
NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_x_p = { "ldml collations collation rules x p", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_rule),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_x_s = { "ldml collations collation rules x s", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_rule),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_x_t = { "ldml collations collation rules x t", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_rule),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_x_i = { "ldml collations collation rules x i", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_rule),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_x_extend = { "ldml collations collation rules x extend", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_extend), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_x_context = { "ldml collations collation rules x context", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_x_context), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_variable =
{ "ldml collations collation rules reset first_variable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_variable =
{ "ldml collations collation rules reset last_variable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_primary_ignorable =
{ "ldml collations collation rules reset first_primary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_primary_ignorable =
{ "ldml collations collation rules reset last_primary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_secondary_ignorable =
{ "ldml collations collation rules reset first_secondary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_secondary_ignorable =
{ "ldml collations collation rules reset last_secondary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_tertiary_ignorable =
{ "ldml collations collation rules reset first_tertiary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_tertiary_ignorable =
{ "ldml collations collation rules reset last_tertiary_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_non_ignorable =
{ "ldml collations collation rules reset first_non_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_non_ignorable =
{ "ldml collations collation rules reset last_non_ignorable", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_first_trailing =
{ "ldml collations collation rules reset first_trailing", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_reset_last_trailing =
{ "ldml collations collation rules reset last_trailing", 6,
(ELEM_START_FUNC) (&start_collation_logical_pos),
(ELEM_END_FUNC) (&end_collation_logical_pos), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules = {
"ldml collations collation cubridrules", 4,
(ELEM_START_FUNC) (&start_element_ok), (ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set = { "ldml collations collation cubridrules set", 5,
(ELEM_START_FUNC) (&start_collation_cubrid_rule),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set), NULL
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_ch = { "ldml collations collation cubridrules set ch", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_cp_ch),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_sch = { "ldml collations collation cubridrules set sch", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_cp_ch),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_ech = { "ldml collations collation cubridrules set ech", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_ech_ecp),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_cp = { "ldml collations collation cubridrules set cp", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_cp_ch),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_scp = { "ldml collations collation cubridrules set scp", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_cp_ch),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_ecp = { "ldml collations collation cubridrules set ecp", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_ech_ecp),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_w = { "ldml collations collation cubridrules set w", 6,
(ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_w_wr),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_collation_cubrid_rules_set_wr = { "ldml collations collation cubridrules set wr", 6,
(ELEM_START_FUNC) (&start_collation_cubrid_rule_set_wr),
(ELEM_END_FUNC) (&end_collation_cubrid_rule_set_w_wr),
(ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_alphabets = { "ldml alphabets", 2, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_include_collation = { "ldml collations include", 3,
(ELEM_START_FUNC) (&start_include_collation),
(ELEM_END_FUNC) (&end_element_ok),
NULL
};
const XML_ELEMENT_DEF ldml_elem_alphabet = { "ldml alphabets alphabet", 3, (ELEM_START_FUNC) (&start_one_alphabet),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_alphabet_upper = { "ldml alphabets alphabet u", 4,
(ELEM_START_FUNC) (&start_upper_case_rule),
(ELEM_END_FUNC) (&end_case_rule), NULL
};
const XML_ELEMENT_DEF ldml_elem_alphabet_upper_src =
{ "ldml alphabets alphabet u s", 5, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_transform_buffer), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_alphabet_upper_dest =
{ "ldml alphabets alphabet u d", 5, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_transform_buffer), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_alphabet_lower = { "ldml alphabets alphabet l", 4,
(ELEM_START_FUNC) (&start_lower_case_rule),
(ELEM_END_FUNC) (&end_case_rule), NULL
};
const XML_ELEMENT_DEF ldml_elem_alphabet_lower_src =
{ "ldml alphabets alphabet l s", 5, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_transform_buffer), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_alphabet_lower_dest =
{ "ldml alphabets alphabet l d", 5, (ELEM_START_FUNC) (&start_element_ok),
(ELEM_END_FUNC) (&end_transform_buffer), (ELEM_DATA_FUNC) (&handle_data)
};
const XML_ELEMENT_DEF ldml_elem_unicodefile = { "ldml unicodefile", 2, (ELEM_START_FUNC) (&start_unicode_file),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
const XML_ELEMENT_DEF ldml_elem_consoleconversion =
{ "ldml consoleconversion", 2, (ELEM_START_FUNC) (&start_consoleconversion),
(ELEM_END_FUNC) (&end_element_ok), NULL
};
/*
* LDML elements list - KEEP the order in this list !
* it is mandatory to put in schema all parent elements, before adding a new
* element */
const XML_ELEMENT_DEF *ldml_elements[] = {
&ldml_elem_ldml,
&ldml_elem_dates,
&ldml_elem_calendars,
&ldml_elem_calendar,
&ldml_elem_dateFormatCUBRID,
&ldml_timeFormatCUBRID,
&ldml_datetimeFormatCUBRID,
&ldml_timestampFormatCUBRID,
&ldml_elem_months,
&ldml_elem_monthContext,
&ldml_elem_monthWidth,
&ldml_elem_month,
&ldml_elem_days,
&ldml_elem_dayContext,
&ldml_elem_dayWidth,
&ldml_elem_day,
&ldml_elem_dayPeriods,
&ldml_elem_dayPeriodContext,
&ldml_elem_dayPeriodWidth,
&ldml_elem_dayPeriod,
&ldml_elem_numbers,
&ldml_elem_numbers_symbols,
&ldml_elem_symbol_decimal,
&ldml_elem_symbol_group,
&ldml_elem_currencies,
&ldml_elem_currency,
&ldml_elem_collations,
&ldml_elem_include_collation,
&ldml_elem_collation,
&ldml_elem_collation_rules,
&ldml_elem_collation_settings,
&ldml_elem_collation_reset,
&ldml_elem_collation_p,
&ldml_elem_collation_s,
&ldml_elem_collation_t,
&ldml_elem_collation_i,
&ldml_elem_collation_pc,
&ldml_elem_collation_sc,
&ldml_elem_collation_tc,
&ldml_elem_collation_ic,
&ldml_elem_collation_x,
&ldml_elem_collation_x_p,
&ldml_elem_collation_x_s,
&ldml_elem_collation_x_t,
&ldml_elem_collation_x_i,
&ldml_elem_collation_x_extend,
&ldml_elem_collation_x_context,
&ldml_elem_collation_reset_first_variable,
&ldml_elem_collation_reset_last_variable,
&ldml_elem_collation_reset_first_primary_ignorable,
&ldml_elem_collation_reset_last_primary_ignorable,
&ldml_elem_collation_reset_first_secondary_ignorable,
&ldml_elem_collation_reset_last_secondary_ignorable,
&ldml_elem_collation_reset_first_tertiary_ignorable,
&ldml_elem_collation_reset_last_tertiary_ignorable,
&ldml_elem_collation_reset_first_non_ignorable,
&ldml_elem_collation_reset_last_non_ignorable,
&ldml_elem_collation_reset_first_trailing,
&ldml_elem_collation_reset_last_trailing,
&ldml_elem_collation_cubrid_rules,
&ldml_elem_collation_cubrid_rules_set,
&ldml_elem_collation_cubrid_rules_set_ch,
&ldml_elem_collation_cubrid_rules_set_sch,
&ldml_elem_collation_cubrid_rules_set_ech,
&ldml_elem_collation_cubrid_rules_set_cp,
&ldml_elem_collation_cubrid_rules_set_scp,
&ldml_elem_collation_cubrid_rules_set_ecp,
&ldml_elem_collation_cubrid_rules_set_w,
&ldml_elem_collation_cubrid_rules_set_wr,
&ldml_elem_alphabets,
&ldml_elem_alphabet,
&ldml_elem_alphabet_upper,
&ldml_elem_alphabet_upper_src,
&ldml_elem_alphabet_upper_dest,
&ldml_elem_alphabet_lower,
&ldml_elem_alphabet_lower_src,
&ldml_elem_alphabet_lower_dest,
&ldml_elem_unicodefile,
&ldml_elem_consoleconversion,
&ldml_timetzFormatCUBRID,
&ldml_datetimetzFormatCUBRID,
&ldml_timestamptzFormatCUBRID,
};
/*
* start_element_ok() - Dummy XML element start function
* Used just for verbose purpose.
*
* return: always 0 (validation OK)
* data: user data
* attr: attribute/value pair array
*
* Note : this function is registered by XML elements that normally do not
* require any validation for element start, but is used only for
* debug purpose, in order to properly display each parsed XML element
*/
static int
start_element_ok (void *data, const char **attr)
{
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_element_ok() - Dummy XML element end function
* Used just for verbose purpose.
*
*
* return: always 0 (OK)
* data: user data
* el_name: element name
*
* Note : this function is registered by XML elements that normally do not
* require any action for element end, but is used only for
* debug purpose, in order to properly display each parsed XML element
*/
static int
end_element_ok (void *data, const char *el_name)
{
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_calendar() - XML element start function
* "ldml dates calendars calendar"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_calendar (void *data, const char **attr)
{
if (xml_check_att_value (attr, "type", "gregorian") != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_dateFormatCUBRID() - XML element end function
* "ldml dates calendars calendar dateFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_dateFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->dateFormat));
if (ld->data_buf_count < (int) sizeof (ld->dateFormat))
{
strcpy (ld->dateFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_timeFormatCUBRID() - XML element end function
* "ldml dates calendars calendar timeFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_timeFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->timeFormat));
if (ld->data_buf_count < (int) sizeof (ld->timeFormat))
{
strcpy (ld->timeFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_datetimeFormatCUBRID() - XML element end function
* "ldml dates calendars calendar datetimeFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_datetimeFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->datetimeFormat));
if (ld->data_buf_count < (int) sizeof (ld->datetimeFormat))
{
strcpy (ld->datetimeFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_timestampFormatCUBRID() - XML element end function
* "ldml dates calendars calendar timestampFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_timestampFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->timestampFormat));
if (ld->data_buf_count < (int) sizeof (ld->timestampFormat))
{
strcpy (ld->timestampFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_timetzFormatCUBRID() - XML element end function
* "ldml dates calendars calendar timetzFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_timetzFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->timetzFormat));
if (ld->data_buf_count < (int) sizeof (ld->timetzFormat))
{
strcpy (ld->timetzFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_datetimetzFormatCUBRID() - XML element end function
* "ldml dates calendars calendar datetimetzFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_datetimetzFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->datetimetzFormat));
if (ld->data_buf_count < (int) sizeof (ld->datetimetzFormat))
{
strcpy (ld->datetimetzFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_timestamptzFormatCUBRID() - XML element end function
* "ldml dates calendars calendar timestamptzFormatCUBRID"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_timestamptzFormatCUBRID (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->data_buf_count < (int) sizeof (ld->timestamptzFormat));
if (ld->data_buf_count < (int) sizeof (ld->timestamptzFormat))
{
strcpy (ld->timestamptzFormat, ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_calendar_name_context() - XML element start function
* "ldml dates calendars calendar months monthContext"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_calendar_name_context (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_check_att_value (attr, "type", "format") == 0)
{
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
/*
* start_month_day_Width() - XML element start function
* "ldml dates calendars calendar months monthContext monthWidth"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_month_day_Width (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
assert (ld->name_type == 0);
if (xml_check_att_value (attr, "type", "abbreviated") == 0)
{
ld->name_type = 1;
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
else if (xml_check_att_value (attr, "type", "wide") == 0)
{
ld->name_type = 2;
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
/*
* end_month_day_Width() - XML element end function
* "ldml dates calendars calendar months monthContext monthWidth"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_month_day_Width (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
assert (ld->name_type != 0);
ld->name_type = 0;
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_month() - XML element start function
* "ldml dates calendars calendar months monthContext monthWidth month"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_month (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *month_count = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_get_att_value (attr, "type", &month_count) == 0)
{
assert (month_count != NULL);
ld->curr_period = atoi (month_count);
assert (ld->curr_period > 0 && ld->curr_period <= CAL_MONTH_COUNT);
if (ld->curr_period > 0 && ld->curr_period <= CAL_MONTH_COUNT)
{
ld->curr_period = ld->curr_period - 1;
}
else
{
PRINT_DEBUG_START (data, attr, "Invalid month", -1);
return -1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
/*
* end_month() - XML element end function
* "ldml dates calendars calendar months monthContext monthWidth month"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_month (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->curr_period >= 0 && ld->curr_period < CAL_MONTH_COUNT);
assert (ld->name_type == 2 || ld->name_type == 1);
if (ld->name_type == 1)
{
assert (ld->data_buf_count < LOC_DATA_MONTH_ABBR_SIZE);
if (ld->data_buf_count < LOC_DATA_MONTH_ABBR_SIZE)
{
strcpy (ld->month_names_abbreviated[ld->curr_period], ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
}
else if (ld->name_type == 2)
{
assert (ld->data_buf_count < LOC_DATA_MONTH_WIDE_SIZE);
if (ld->data_buf_count < LOC_DATA_MONTH_WIDE_SIZE)
{
strcpy (ld->month_names_wide[ld->curr_period], ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
}
ld->curr_period = -1;
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_day() - XML element start function
* "ldml dates calendars calendar days dayContext dayWidth day"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_day (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *day_ref_name = NULL;
int i;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_get_att_value (attr, "type", &day_ref_name) != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
assert (day_ref_name != NULL);
for (i = 0; i < 7; i++)
{
if (strcmp (ldml_ref_day_names[i], day_ref_name) == 0)
{
break;
}
}
assert (i >= 0 && i < CAL_DAY_COUNT);
if (i >= 0 && i < CAL_DAY_COUNT)
{
ld->curr_period = i;
}
else
{
PRINT_DEBUG_START (data, attr, "Invalid day", -1);
return -1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_day() - XML element end function
* "ldml dates calendars calendar days dayContext dayWidth day"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_day (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->curr_period >= 0 && ld->curr_period < CAL_DAY_COUNT);
assert (ld->name_type == 2 || ld->name_type == 1);
if (ld->name_type == 1)
{
assert (ld->data_buf_count < LOC_DATA_DAY_ABBR_SIZE);
if (ld->data_buf_count < LOC_DATA_DAY_ABBR_SIZE)
{
strcpy (ld->day_names_abbreviated[ld->curr_period], ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
}
else if (ld->name_type == 2)
{
assert (ld->data_buf_count < LOC_DATA_DAY_WIDE_SIZE);
if (ld->data_buf_count < LOC_DATA_DAY_WIDE_SIZE)
{
strcpy (ld->day_names_wide[ld->curr_period], ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
}
ld->curr_period = -1;
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_dayPeriodWidth() - XML element start function
* "ldml dates calendars calendar dayPeriods dayPeriodContext dayPeriodWidth"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_dayPeriodWidth (void *data, const char **attr)
{
if (xml_check_att_value (attr, "type", "wide") == 0)
{
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
/*
* start_dayPeriod() - XML element start function
* "ldml dates calendars calendar dayPeriods dayPeriodContext dayPeriodWidth dayPeriod"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_dayPeriod (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *am_pm_ref_name = NULL;
int i;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_get_att_value (attr, "type", &am_pm_ref_name) != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
assert (am_pm_ref_name != NULL);
for (i = 0; i < CAL_AM_PM_COUNT; i++)
{
if (strcmp (ldml_ref_am_pm_names[i], am_pm_ref_name) == 0)
{
break;
}
}
assert (i >= 0 && i < CAL_AM_PM_COUNT);
if (i >= 0 && i < CAL_AM_PM_COUNT)
{
ld->curr_period = i;
}
else
{
PRINT_DEBUG_START (data, attr, "Invalid dayPeriod", -1);
return -1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_dayPeriod() - XML element end function
* "ldml dates calendars calendar dayPeriods dayPeriodContext dayPeriodWidth dayPeriod"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_dayPeriod (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* copy data buffer to locale */
assert (ld->curr_period >= 0 && ld->curr_period < CAL_AM_PM_COUNT);
assert (ld->data_buf_count < LOC_DATA_AM_PM_SIZE);
if (ld->data_buf_count < LOC_DATA_AM_PM_SIZE)
{
strcpy (ld->am_pm[ld->curr_period], ld->data_buffer);
}
else
{
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
ld->curr_period = -1;
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_numbers_symbols() - XML element start function
* "ldml numbers symbols"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_numbers_symbols (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_check_att_value (attr, "numberSystem", "latn") != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_number_symbol() - XML element end function
* "ldml numbers symbols decimal"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_number_symbol (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* number symbol is exactly one character (ASCII compatible) */
if (ld->data_buf_count == 1 && (*(ld->data_buffer) >= ' ' && (unsigned char) *(ld->data_buffer) < 0x80))
{
if (strcmp (el_name, "decimal") == 0)
{
ld->number_decimal_sym = *(ld->data_buffer);
}
else
{
ld->number_group_sym = *(ld->data_buffer);
}
}
else
{
PRINT_DEBUG_END (data, "Invalid numeric symbol", -1);
return -1;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_currency() - XML element start function
* "ldml numbers currencies currency"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_currency (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
int currency_size = 0;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* all setting are optional */
if (xml_get_att_value (attr, "type", &att_val) == 0)
{
/* Type attribute found, store it. */
if (strlen (att_val) != LOC_DATA_CURRENCY_ISO_CODE_LEN)
{
PRINT_DEBUG_START (data, attr, "Currency ISO code invalid, " "it must be 3 chars long.", -1);
return -1;
}
if (ld->default_currency_code != DB_CURRENCY_NULL)
{
PRINT_DEBUG_START (data, attr, "Currency ISO code already set.", -1);
return -1;
}
if (!intl_is_currency_symbol (att_val, &(ld->default_currency_code), ¤cy_size, CURRENCY_CHECK_MODE_ISO))
{
PRINT_DEBUG_START (data, attr, "Currency ISO code not supported", -1);
return -1;
}
}
else
{
/* If <currency> does not have a type attribute, parsing fails. */
PRINT_DEBUG_START (data, attr, "Currency tag does not have an ISO code type " "attribute.", -1);
return -1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/* LDML collation */
/*
* start_collations() - XML element start function
* "ldml collations"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collations (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *valid_locales = NULL;
int check_loc_len;
char *t_start;
char *t_end;
char *att_val_end;
bool locale_found = false;
bool search_end = false;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (xml_get_att_value (attr, "validSubLocales", &valid_locales) != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
assert (ld->locale_name != NULL);
check_loc_len = strlen (ld->locale_name);
att_val_end = valid_locales + strlen (valid_locales);
/* separate the locales_name into tokens */
t_start = t_end = valid_locales;
do
{
if (*t_end == '\0' || char_isspace ((int) *t_end))
{
/* token ended, check locale name */
if ((t_end - t_start == 3 && memcmp (t_start, "all", 3) == 0) || (t_end - t_start == 1 && *t_start == '*')
|| (t_end - t_start == check_loc_len && memcmp (ld->locale_name, t_start, t_end - t_start) == 0))
{
locale_found = true;
break;
}
if (*t_end == '\0')
{
search_end = true;
}
t_end++;
t_start = t_end;
}
else
{
t_end++;
}
}
while (!search_end);
if (!locale_found)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* start_one_collation() - XML element start function
* "ldml collations collation"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_one_collation (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
LOCALE_COLLATION *locale_coll = NULL;
char *att_val = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
locale_coll = new_locale_collation (ld);
if (locale_coll == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "memory allocation failed", -1);
return -1;
}
if (xml_get_att_value (attr, "type", &att_val) != 0)
{
PRINT_DEBUG_START (data, attr, "", 1);
return 1;
}
assert (att_val != NULL);
strncpy (locale_coll->tail_coll.coll_name, att_val, COLL_NAME_SIZE - 1);
locale_coll->tail_coll.coll_name[COLL_NAME_SIZE - 1] = '\0';
/* initialize default value for settings */
locale_coll->tail_coll.uca_opt.sett_strength = TAILOR_QUATERNARY;
locale_coll->tail_coll.uca_opt.sett_caseFirst = 1;
locale_coll->tail_coll.ldml_context.ldml_file = strdup (ld->ldml_context.ldml_file);
locale_coll->tail_coll.ldml_context.line_no = XML_GetCurrentLineNumber (pd->xml_parser);
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_one_collation() - XML element end function
* "ldml collations collation"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_one_collation (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
ld->coll_cnt++;
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* start_collation_settings() - XML element start function
* "ldml collations collation settings"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_settings (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
char err_msg[ERR_MSG_SIZE + PATH_MAX];
COLL_TAILORING *curr_coll_tail = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
att_val = NULL;
if (xml_get_att_value (attr, "id", &att_val) == 0)
{
assert (att_val != NULL);
curr_coll_tail->coll_id = atoi (att_val);
if (curr_coll_tail->coll_id < LANG_MAX_BUILTIN_COLLATIONS || curr_coll_tail->coll_id >= LANG_MAX_COLLATIONS)
{
snprintf (err_msg, sizeof (err_msg) - 1,
"File %s, line: %lu : " "Invalid collation numeric identifier : %d"
" for collation '%s'. Valid range is from %d to %d", ld->ldml_context.ldml_file,
XML_GetCurrentLineNumber (pd->xml_parser), curr_coll_tail->coll_id, curr_coll_tail->coll_name,
LANG_MAX_BUILTIN_COLLATIONS, LANG_MAX_COLLATIONS - 1);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return -1;
}
}
att_val = NULL;
/* all setting are optional */
if (xml_get_att_value (attr, "strength", &att_val) == 0)
{
T_LEVEL coll_strength = TAILOR_QUATERNARY;
if (strcasecmp (att_val, "primary") == 0 || strcmp (att_val, "1") == 0)
{
coll_strength = TAILOR_PRIMARY;
}
else if ((strcasecmp (att_val, "secondary") == 0) || (strcmp (att_val, "2") == 0))
{
coll_strength = TAILOR_SECONDARY;
}
else if ((strcasecmp (att_val, "tertiary") == 0) || (strcmp (att_val, "3") == 0))
{
coll_strength = TAILOR_TERTIARY;
}
else if ((strcasecmp (att_val, "quaternary") == 0) || (strcmp (att_val, "4") == 0))
{
coll_strength = TAILOR_QUATERNARY;
}
else if ((strcasecmp (att_val, "identical") == 0) || (strcmp (att_val, "5") == 0))
{
coll_strength = TAILOR_IDENTITY;
}
else
{
snprintf (err_msg, sizeof (err_msg) - 1,
"File %s, line: %lu : " "Invalid collation strength : '%s'" " for collation '%s'",
ld->ldml_context.ldml_file, XML_GetCurrentLineNumber (pd->xml_parser), att_val,
curr_coll_tail->coll_name);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return -1;
}
curr_coll_tail->uca_opt.sett_strength = coll_strength;
}
att_val = NULL;
if (xml_get_att_value (attr, "backwards", &att_val) == 0)
{
if (strcasecmp (att_val, "on") == 0)
{
curr_coll_tail->uca_opt.sett_backwards = true;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "caseLevel", &att_val) == 0)
{
if (strcasecmp (att_val, "on") == 0)
{
curr_coll_tail->uca_opt.sett_caseLevel = true;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "caseFirst", &att_val) == 0)
{
if (strcasecmp (att_val, "off") == 0)
{
curr_coll_tail->uca_opt.sett_caseFirst = 0;
}
else if (strcasecmp (att_val, "upper") == 0)
{
curr_coll_tail->uca_opt.sett_caseFirst = 1;
}
else if (strcasecmp (att_val, "lower") == 0)
{
curr_coll_tail->uca_opt.sett_caseFirst = 2;
}
}
/* CUBRID specific collation settings */
att_val = NULL;
if (xml_get_att_value (attr, "CUBRIDMaxWeights", &att_val) == 0)
{
assert (att_val != NULL);
curr_coll_tail->sett_max_cp = atoi (att_val);
}
att_val = NULL;
if (xml_get_att_value (attr, "DUCETContractions", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "use") == 0)
{
curr_coll_tail->uca_opt.sett_contr_policy |= CONTR_DUCET_USE;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "TailoringContractions", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "use") == 0)
{
curr_coll_tail->uca_opt.sett_contr_policy |= CONTR_TAILORING_USE;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "CUBRIDExpansions", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "use") == 0)
{
curr_coll_tail->uca_opt.sett_expansions = true;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "MatchContractionBoundary", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "true") == 0)
{
curr_coll_tail->uca_opt.sett_match_contr = MATCH_CONTR_BOUND_ALLOW;
}
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* start_collation_reset() - XML element start function
* "ldml collations collation rules reset"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_reset (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
*(ld->last_anchor_buf) = '\0';
ld->last_rule_dir = TAILOR_AFTER;
ld->last_rule_pos_type = RULE_POS_BUFFER;
ld->last_rule_level = TAILOR_UNDEFINED;
if (xml_get_att_value (attr, "before", &att_val) == 0)
{
if (strcmp (att_val, "primary") == 0)
{
ld->last_rule_level = TAILOR_PRIMARY;
}
else if (strcmp (att_val, "secondary") == 0)
{
ld->last_rule_level = TAILOR_SECONDARY;
}
else if (strcmp (att_val, "tertiary") == 0)
{
ld->last_rule_level = TAILOR_TERTIARY;
}
else if (strcmp (att_val, "quaternary") == 0)
{
ld->last_rule_level = TAILOR_QUATERNARY;
}
else
{
assert (false);
PRINT_DEBUG_START (data, attr, "Invalid value for before", -1);
return -1;
}
ld->last_rule_dir = TAILOR_BEFORE;
}
ld->last_r_buf_p = NULL;
ld->last_r_buf_size = 0;
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_collation_reset() - XML element end function
* "ldml collations collation rules reset"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_reset (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
assert (ld->data_buf_count < LOC_DATA_COLL_TWO_CHARS);
if (ld->data_buf_count < LOC_DATA_COLL_TWO_CHARS)
{
strcpy (ld->last_anchor_buf, ld->data_buffer);
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
/*
* start_collation_rule() - XML element start function
* "ldml collations collation rules p"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_rule (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
int status;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
t_rule = new_collation_rule (ld);
if (t_rule == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "memory allocation failed", -1);
return -1;
}
if (ld->last_rule_pos_type != RULE_POS_BUFFER)
{
/* nothing do to for logical position reference */
assert (t_rule->r_buf == NULL);
assert (t_rule->r_buf_size == 0);
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
status = common_collation_start_rule (data, attr, ld, t_rule);
if (status != 0)
{
return status;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* start_collation_cubrid_rule() - XML element start function
* "ldml collations collation cubridrules set"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_cubrid_rule (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
CUBRID_TAILOR_RULE *ct_rule = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
ct_rule = new_collation_cubrid_rule (ld);
if (ct_rule == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "OUT OF MEMORY", -1);
return -1;
}
PRINT_DEBUG_START (data, attr, "", 0);
clear_data_buffer (pd);
return 0;
}
/*
* start_collation_cubrid_rule_set_wr - XML element start function
* "ldml collations collation cubridrules set wr"
*
* return: NO_ERROR if it's OK to enter this element,
* ER_LOC_GEN if STEP attribute is a string exceeding the max size.
* data(in/out): user data
* attr(in): attribute/value pair array
*/
static int
start_collation_cubrid_rule_set_wr (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
CUBRID_TAILOR_RULE *ct_rule;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int err_status = NO_ERROR;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->cub_count_rules;
ct_rule = &(curr_coll_tail->cub_rules[rule_id]);
if (xml_get_att_value (attr, "step", &att_val) == 0)
{
if (strlen (att_val) > MAX_STRLEN_FOR_COLLATION_ELEMENT)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR ("Data buffer too big in <wr> attribute STEP.", ER_LOC_GEN, true);
goto exit;
}
strcpy (ct_rule->step, att_val);
ct_rule->step[strlen (att_val)] = '\0';
}
exit:
PRINT_DEBUG_START (data, attr, "", 0);
return err_status;
}
/*
* end_collation_cubrid_rule_set() - XML element end function
* "ldml collations collation cubridrules ..."
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_cubrid_rule_set (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->cub_count_rules;
/* rule finished, increase count */
curr_coll_tail->cub_count_rules++;
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1, " * SET Rule no. %d, tag name :%s *", (rule_id + 1), el_name);
PRINT_DEBUG_END (data, msg, 0);
}
return 0;
}
/*
* end_collation_cubrid_rule_set_end_cp_ch - XML element end function for
* cp, ch, scp, sch
* "ldml collations collation cubridrules ..."
*
* return: NO_ERROR(0) if parser OK,
* ER_LOC_GEN if data buffer for codepoint is too big.
* data(in/out): user data
* el_name(in): element name
*/
static int
end_collation_cubrid_rule_set_cp_ch (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
CUBRID_TAILOR_RULE *ct_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int err_status = NO_ERROR;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->cub_count_rules;
ct_rule = &(curr_coll_tail->cub_rules[rule_id]);
if (ld->data_buf_count > LOC_DATA_BUFF_SIZE)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR ("Data buffer too large in codepoint starting label.", ER_LOC_GEN, true);
goto exit;
}
memcpy (ct_rule->start_cp_buf, ld->data_buffer, ld->data_buf_count * sizeof (char));
ct_rule->start_cp_buf[ld->data_buf_count] = '\0';
memcpy (ct_rule->end_cp_buf, ld->data_buffer, ld->data_buf_count * sizeof (char));
ct_rule->end_cp_buf[ld->data_buf_count] = '\0';
if (strcmp (el_name, "ch") == 0 || strcmp (el_name, "sch") == 0)
{
ct_rule->start_cp_buf_type = BUF_TYPE_CHAR;
ct_rule->end_cp_buf_type = BUF_TYPE_CHAR;
}
else if (strcmp (el_name, "cp") == 0 || strcmp (el_name, "scp") == 0)
{
ct_rule->start_cp_buf_type = BUF_TYPE_CODE;
ct_rule->end_cp_buf_type = BUF_TYPE_CODE;
}
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1, " * SET Rule no. %d, tag name :%s *", (rule_id + 1), el_name);
PRINT_DEBUG_END (data, msg, 0);
}
exit:
clear_data_buffer (pd);
return err_status;
}
/*
* end_collation_cubrid_rule_set_end_ecp - XML element end function
* for ech/ecp.
* "ldml collations collation cubridrules ..."
*
* return: NO_ERROR if parser OK
* ER_LOC_GEN if buffer data too big
* data(in/out): user data
* el_name(in): element name
*/
static int
end_collation_cubrid_rule_set_ech_ecp (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
CUBRID_TAILOR_RULE *ct_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int err_status = NO_ERROR;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
if (ld->data_buf_count > LOC_DATA_BUFF_SIZE)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR ("Data buffer too large in codepoint end label.", ER_LOC_GEN, true);
goto exit;
}
rule_id = curr_coll_tail->cub_count_rules;
ct_rule = &(curr_coll_tail->cub_rules[rule_id]);
memcpy (ct_rule->end_cp_buf, ld->data_buffer, ld->data_buf_count * sizeof (char));
ct_rule->end_cp_buf[ld->data_buf_count] = '\0';
if (strcmp (el_name, "ech") == 0)
{
ct_rule->end_cp_buf_type = BUF_TYPE_CHAR;
}
else if (strcmp (el_name, "ecp") == 0)
{
ct_rule->end_cp_buf_type = BUF_TYPE_CODE;
}
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1, "* SET Rule no. %d, tag name :%s *", (rule_id + 1), el_name);
PRINT_DEBUG_END (data, msg, 0);
}
exit:
clear_data_buffer (pd);
return err_status;
}
/*
* end_collation_cubrid_rule_set_w_wr() - XML element end function for w / wr.
* "ldml collations collation cubridrules ..."
*
* return: NO_ERROR if parser OK,
* ER_LOC_GEN if parser NOK and stop parsing.
* data(in/out): user data
* el_name(in): element name
*/
static int
end_collation_cubrid_rule_set_w_wr (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
CUBRID_TAILOR_RULE *ct_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int err_status = NO_ERROR;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->cub_count_rules;
ct_rule = &(curr_coll_tail->cub_rules[rule_id]);
if (ld->data_buf_count > LOC_DATA_BUFF_SIZE)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR ("Data buffer too large in weight label.", ER_LOC_GEN, true);
goto exit;
}
memcpy (ct_rule->start_weight, ld->data_buffer, ld->data_buf_count * sizeof (char));
ct_rule->start_weight[ld->data_buf_count] = '\0';
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1, "* SET Rule no. %d, tag name :%s *", (rule_id + 1), el_name);
PRINT_DEBUG_END (data, msg, 0);
}
exit:
clear_data_buffer (pd);
return err_status;
}
/*
* handle_data_collation_rule() - XML element data content handle function
* "ldml collations collation rules p"
*
* return: 0 handling OK, non-zero if handling NOK and stop parsing
* (data): user data
* (s): content buffer
* (len): length of buffer
*/
static int
handle_data_collation_rule (void *data, const char *s, int len)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
assert (len >= 0);
t_rule = &(curr_coll_tail->rules[curr_coll_tail->count_rules]);
char *const realloc_t_buf = (char *) realloc (t_rule->t_buf, t_rule->t_buf_size + len);
if (realloc_t_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_DATA (data, "memory allocation failed", -1);
return -1;
}
else
{
t_rule->t_buf = realloc_t_buf;
}
/* copy partial data to data buffer */
memcpy (t_rule->t_buf + t_rule->t_buf_size, s, len);
t_rule->t_buf_size += len;
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
if (len < 32 && len < ERR_MSG_SIZE)
{
memcpy (msg, s, len);
msg[len] = '\0';
}
else
{
char msg2[33];
memcpy (msg2, s, 32);
msg2[32] = '\0';
snprintf (msg, sizeof (msg) - 1, "%s | %d bytes", msg2, len);
}
PRINT_DEBUG_DATA (data, msg, 0);
}
return 0;
}
/*
* end_collation_rule() - XML element end function
* "ldml collations collation rules p"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_rule (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int status;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
/* rule finished, increase count */
rule_id = curr_coll_tail->count_rules++;
t_rule = &(curr_coll_tail->rules[rule_id]);
if (strcmp (el_name, "p") == 0)
{
t_rule->level = TAILOR_PRIMARY;
}
else if (strcmp (el_name, "s") == 0)
{
t_rule->level = TAILOR_SECONDARY;
}
else if (strcmp (el_name, "t") == 0)
{
t_rule->level = TAILOR_TERTIARY;
}
else if (strcmp (el_name, "i") == 0)
{
t_rule->level = TAILOR_IDENTITY;
}
else if (strcmp (el_name, "pc") == 0)
{
t_rule->level = TAILOR_PRIMARY;
t_rule->multiple_chars = true;
}
else if (strcmp (el_name, "sc") == 0)
{
t_rule->level = TAILOR_SECONDARY;
t_rule->multiple_chars = true;
}
else if (strcmp (el_name, "tc") == 0)
{
t_rule->level = TAILOR_TERTIARY;
t_rule->multiple_chars = true;
}
else if (strcmp (el_name, "ic") == 0)
{
t_rule->level = TAILOR_IDENTITY;
t_rule->multiple_chars = true;
}
else
{
assert (false);
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_END (data, "Invalid element name", -1);
return -1;
}
status = common_collation_end_rule (data, ld, rule_id, t_rule);
if (status != 0)
{
return status;
}
return 0;
}
/*
* start_collation_x() - XML element start function
* "ldml collations collation rules x"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_x (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
int status;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
t_rule = new_collation_rule (ld);
if (t_rule == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "memory allocation failed", -1);
return -1;
}
if (ld->last_rule_pos_type != RULE_POS_BUFFER)
{
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_START (data, attr, "Last <reset> tag is invalid", -1);
return -1;
}
status = common_collation_start_rule (data, attr, ld, t_rule);
if (status != 0)
{
return status;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_collation_x - XML element end function
* "ldml collations collation rules x"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_x (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
/* rule finished, increase count */
rule_id = curr_coll_tail->count_rules++;
t_rule = &(curr_coll_tail->rules[rule_id]);
/* BEFORE applies only for the first rule after <reset> */
ld->last_rule_dir = TAILOR_AFTER;
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1, " * X_Rule %d, L :%d, Dir:%d, PosType:%d, Mc:%d *", rule_id, t_rule->level,
t_rule->direction, t_rule->r_pos_type, t_rule->multiple_chars);
PRINT_DEBUG_END (data, msg, 0);
}
return 0;
}
/*
* end_collation_x_rule - XML element end function
* "ldml collations collation rules x p"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_x_rule (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
int status;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->count_rules;
t_rule = &(curr_coll_tail->rules[rule_id]);
assert (strlen (ld->data_buffer) == ld->data_buf_count);
char *const realloc_t_buf = (char *) realloc (t_rule->t_buf, t_rule->t_buf_size + ld->data_buf_count);
if (realloc_t_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_END (data, "memory allocation failed", -1);
return -1;
}
else
{
t_rule->t_buf = realloc_t_buf;
}
/* copy partial data to rule tailoring buffer (character to be modified) */
memcpy (t_rule->t_buf + t_rule->t_buf_size, ld->data_buffer, ld->data_buf_count);
t_rule->t_buf_size += ld->data_buf_count;
if (strcmp (el_name, "p") == 0)
{
t_rule->level = TAILOR_PRIMARY;
}
else if (strcmp (el_name, "s") == 0)
{
t_rule->level = TAILOR_SECONDARY;
}
else if (strcmp (el_name, "t") == 0)
{
t_rule->level = TAILOR_TERTIARY;
}
else if (strcmp (el_name, "i") == 0)
{
t_rule->level = TAILOR_IDENTITY;
}
else
{
assert (false);
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_END (data, "Invalid element name", -1);
return -1;
}
status = common_collation_end_rule (data, ld, rule_id, t_rule);
if (status != 0)
{
return status;
}
clear_data_buffer ((XML_PARSER_DATA *) data);
return 0;
}
/*
* end_collation_x_extend - XML element end function
* "ldml collations collation rules x extend"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_x_extend (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->count_rules;
t_rule = &(curr_coll_tail->rules[rule_id]);
assert (t_rule->r_buf != NULL);
assert (ld->data_buf_count > 0);
char *const realloc_r_buf = (char *) realloc (t_rule->r_buf, t_rule->r_buf_size + ld->data_buf_count);
if (realloc_r_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_END (data, "memory allocation failed", -1);
return -1;
}
else
{
t_rule->r_buf = realloc_r_buf;
}
memcpy (t_rule->r_buf + t_rule->r_buf_size, ld->data_buffer, ld->data_buf_count);
t_rule->r_buf_size += ld->data_buf_count;
clear_data_buffer ((XML_PARSER_DATA *) data);
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/*
* end_collation_x_context - XML element end function
* "ldml collations collation rules x context"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_x_context (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
int rule_id;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
rule_id = curr_coll_tail->count_rules;
t_rule = &(curr_coll_tail->rules[rule_id]);
assert (strlen (ld->data_buffer) < LOC_DATA_COLL_TWO_CHARS);
if (strlen (ld->data_buffer) >= LOC_DATA_COLL_TWO_CHARS)
{
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_END (data, "Too much data", -1);
return -1;
}
if (t_rule->t_buf_size < ld->data_buf_count)
{
char *const realloc_t_buf = (char *) realloc (t_rule->t_buf, ld->data_buf_count);
if (realloc_t_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_END (data, "memory allocation failed", -1);
return -1;
}
else
{
t_rule->t_buf = realloc_t_buf;
}
}
memcpy (t_rule->t_buf, ld->data_buffer, ld->data_buf_count);
t_rule->t_buf_size = ld->data_buf_count;
clear_data_buffer ((XML_PARSER_DATA *) data);
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
int rule_id = curr_coll_tail->count_rules;
snprintf (msg, sizeof (msg) - 1, "* Rule %d *", rule_id);
PRINT_DEBUG_END (data, msg, 0);
}
else
{
PRINT_DEBUG_END (data, "", 0);
}
return 0;
}
/*
* start_collation_logical_pos() - XML element start function
* "ldml collations collation rules reset first_variable"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_collation_logical_pos (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_collation_logical_pos() - XML element end function
* "ldml collations collation rules reset first_variable"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_collation_logical_pos (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (strcmp (el_name, "first_variable") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_VAR;
}
else if (strcmp (el_name, "last_variable") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_VAR;
}
else if (strcmp (el_name, "first_primary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_PRI_IGN;
}
else if (strcmp (el_name, "last_primary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_PRI_IGN;
}
else if (strcmp (el_name, "first_secondary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_SEC_IGN;
}
else if (strcmp (el_name, "last_secondary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_SEC_IGN;
}
else if (strcmp (el_name, "first_tertiary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_TERT_IGN;
}
else if (strcmp (el_name, "last_tertiary_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_TERT_IGN;
}
else if (strcmp (el_name, "first_non_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_NON_IGN;
}
else if (strcmp (el_name, "last_non_ignorable") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_NON_IGN;
}
else if (strcmp (el_name, "first_trailing") == 0)
{
ld->last_rule_pos_type = RULE_POS_FIRST_TRAIL;
}
else if (strcmp (el_name, "last_trailing") == 0)
{
ld->last_rule_pos_type = RULE_POS_LAST_TRAIL;
}
else
{
assert (false);
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_END (data, "Internal LDML parser error", -1);
return -1;
}
PRINT_DEBUG_END (data, "", 0);
return 0;
}
/* Alphabet XML elements handling */
/*
* start_one_alphabet() - XML element start function
* "ldml alphabets alphabet"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_one_alphabet (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (ld->alpha_tailoring.alphabet_mode != 0 || ld->alpha_tailoring.count_rules != 0
|| ld->alpha_tailoring.sett_max_letters != -1)
{
PRINT_DEBUG_START (data, attr, "Only one alphabet is allowed", -1);
return -1;
}
att_val = NULL;
if (xml_get_att_value (attr, "CUBRIDMaxLetters", &att_val) == 0)
{
assert (att_val != NULL);
ld->alpha_tailoring.sett_max_letters = atoi (att_val);
}
att_val = NULL;
if (xml_get_att_value (attr, "CUBRIDAlphabetMode", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "ASCII") == 0)
{
ld->alpha_tailoring.alphabet_mode = 2;
}
else if (strcasecmp (att_val, "UNICODEDATAFILE") == 0)
{
ld->alpha_tailoring.alphabet_mode = 0;
}
else
{
PRINT_DEBUG_START (data, attr, "Invalid value for CUBRIDAlphabetMode." "Expected ASCII or UNICODEDATAFILE",
-1);
return -1;
}
}
ld->alpha_tailoring.ldml_context.ldml_file = strdup (ld->ldml_context.ldml_file);
ld->alpha_tailoring.ldml_context.line_no = XML_GetCurrentLineNumber (pd->xml_parser);
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* start_upper_case_rule() - XML element start function
* "ldml alphabets alphabet u"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_upper_case_rule (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TRANSFORM_RULE *tf_rule = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
tf_rule = new_transform_rule (ld);
if (tf_rule == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "OUT OF MEMORY", -1);
return -1;
}
tf_rule->type = TR_UPPER;
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_case_rule() - XML element end function
* "ldml alphabets alphabet u"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_case_rule (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TRANSFORM_RULE *tf_rule = NULL;
int rule_id;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
/* rule finished, increase count */
rule_id = ld->alpha_tailoring.count_rules++;
tf_rule = &(ld->alpha_tailoring.rules[rule_id]);
if (pd->verbose)
{
char msg[64];
unsigned char *dummy = NULL;
unsigned int cp_src = intl_utf8_to_cp ((unsigned char *) tf_rule->src, tf_rule->src_size,
&dummy);
unsigned int cp_dest = intl_utf8_to_cp ((unsigned char *) tf_rule->dest, tf_rule->dest_size,
&dummy);
sprintf (msg, " * Case Rule %d, Src :%0X, Dest:%0X *", rule_id, cp_src, cp_dest);
PRINT_DEBUG_END (data, msg, 0);
}
else
{
PRINT_DEBUG_END (data, "", 0);
}
return 0;
}
/*
* start_lower_case_rule() - XML element start function
* "ldml alphabets alphabet l"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_lower_case_rule (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TRANSFORM_RULE *tf_rule = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
tf_rule = new_transform_rule (ld);
if (tf_rule == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "OUT OF MEMORY", -1);
return -1;
}
tf_rule->type = TR_LOWER;
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* end_transform_buffer() - XML element end function
* "ldml alphabets alphabet u s"
*
* return: 0 parser OK, non-zero value if parser NOK and stop parsing
* data: user data
* el_name: element name
*/
static int
end_transform_buffer (void *data, const char *el_name)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
TRANSFORM_RULE *tf_rule = NULL;
char *tf_buf = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
assert (ld->alpha_tailoring.count_rules < ld->alpha_tailoring.max_rules);
tf_rule = &(ld->alpha_tailoring.rules[ld->alpha_tailoring.count_rules]);
if (ld->data_buf_count <= 0)
{
PRINT_DEBUG_END (data, "Expecting non-empty string", -1);
pd->xml_error = XML_CUB_ERR_PARSER;
goto error_exit;
}
tf_buf = (char *) malloc (ld->data_buf_count);
if (tf_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_END (data, "memory allocation failed", -1);
goto error_exit;
}
memcpy (tf_buf, ld->data_buffer, ld->data_buf_count);
assert (tf_rule->type == TR_LOWER || tf_rule->type == TR_UPPER);
if (strcmp (el_name, "s") == 0)
{
if (tf_rule->src != NULL || tf_rule->src_size != 0)
{
PRINT_DEBUG_END (data, "duplicate source for case rule", -1);
pd->xml_error = XML_CUB_ERR_PARSER;
goto error_exit;
}
tf_rule->src = tf_buf;
tf_rule->src_size = ld->data_buf_count;
}
else if (strcmp (el_name, "d") == 0)
{
if (tf_rule->dest != NULL || tf_rule->dest_size != 0)
{
PRINT_DEBUG_END (data, "duplicate destination for case rule", -1);
pd->xml_error = XML_CUB_ERR_PARSER;
goto error_exit;
}
tf_rule->dest = tf_buf;
tf_rule->dest_size = ld->data_buf_count;
}
else
{
assert (false);
PRINT_DEBUG_END (data, "Internal LDML parser error", -1);
pd->xml_error = XML_CUB_ERR_PARSER;
goto error_exit;
}
PRINT_DEBUG_END (data, "", 0);
clear_data_buffer ((XML_PARSER_DATA *) data);
return 0;
error_exit:
clear_data_buffer ((XML_PARSER_DATA *) data);
return -1;
}
/*
* start_consoleconversion() - XML element start function
* "ldml consoleconversion"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_consoleconversion (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (*(ld->txt_conv_prm.nl_lang_str) != '\0' || *(ld->txt_conv_prm.conv_file) != '\0'
|| *(ld->txt_conv_prm.win_codepages) != '\0')
{
PRINT_DEBUG_START (data, attr, "Only one console conversion is allowed", -1);
return -1;
}
att_val = NULL;
if (xml_get_att_value (attr, "type", &att_val) == 0)
{
assert (att_val != NULL);
if (strcasecmp (att_val, "ISO") == 0)
{
ld->txt_conv_prm.conv_type = TEXT_CONV_GENERIC_1BYTE;
}
else if (strcasecmp (att_val, "DBCS") == 0)
{
ld->txt_conv_prm.conv_type = TEXT_CONV_GENERIC_2BYTE;
}
else if (strcasecmp (att_val, "ISO88591") == 0)
{
ld->txt_conv_prm.conv_type = TEXT_CONV_ISO_88591_BUILTIN;
}
else if (strcasecmp (att_val, "ISO88599") == 0)
{
ld->txt_conv_prm.conv_type = TEXT_CONV_ISO_88599_BUILTIN;
}
else
{
PRINT_DEBUG_START (data, attr, "Invalid value for type." "Expecting ISO88591 or ISO or EUC", -1);
return -1;
}
}
att_val = NULL;
if (xml_get_att_value (attr, "windows_codepage", &att_val) == 0)
{
assert (att_val != NULL);
if (strlen (att_val) > (int) sizeof (ld->txt_conv_prm.win_codepages) - 1)
{
PRINT_DEBUG_START (data, attr, "Invalid attribute value", -1);
return -1;
}
strcpy (ld->txt_conv_prm.win_codepages, att_val);
}
att_val = NULL;
if (xml_get_att_value (attr, "linux_charset", &att_val) == 0)
{
assert (att_val != NULL);
if (strlen (att_val) > (int) sizeof (ld->txt_conv_prm.nl_lang_str) - 1)
{
PRINT_DEBUG_START (data, attr, "Invalid attribute value", -1);
return -1;
}
strcpy (ld->txt_conv_prm.nl_lang_str, att_val);
}
att_val = NULL;
if (xml_get_att_value (attr, "file", &att_val) == 0)
{
assert (att_val != NULL);
if (strlen (att_val) > (int) sizeof (ld->txt_conv_prm.conv_file) - 1)
{
PRINT_DEBUG_START (data, attr, "Invalid attribute value", -1);
return -1;
}
strcpy (ld->txt_conv_prm.conv_file, att_val);
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/* General LDML handling functions */
/*
* handle_data() - XML element data content handle function
* generic data handling function
*
* return: 0 handling OK, non-zero if handling NOK and stop parsing
* (data): user data
* (s): content buffer
* (len): length of buffer
*/
static int
handle_data (void *data, const char *s, int len)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char msg[64];
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
assert (len >= 0);
if (ld->data_buf_count + len >= LOC_DATA_BUFF_SIZE)
{
pd->xml_error = XML_CUB_ERR_PARSER;
sprintf (msg, "Too much data : %d + %d bytes", ld->data_buf_count, len);
PRINT_DEBUG_DATA (data, msg, -1);
return -1;
}
/* copy partial data to data buffer */
memcpy (ld->data_buffer + ld->data_buf_count, s, len);
ld->data_buf_count += len;
ld->data_buffer[ld->data_buf_count] = '\0';
if (pd->verbose)
{
char msg[64];
if (len < 64)
{
memcpy (msg, s, len);
msg[len] = '\0';
}
else
{
char msg2[33];
memcpy (msg2, s, 32);
msg2[32] = '\0';
sprintf (msg, "%s | %d bytes", msg2, len);
}
PRINT_DEBUG_DATA (data, msg, 0);
}
return 0;
}
/*
* clear_data_buffer() - clears the data content buffer
*
* return:
* pd(in): parser data
*/
static void
clear_data_buffer (XML_PARSER_DATA * pd)
{
LOCALE_DATA *ld = NULL;
assert (pd != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
ld->data_buf_count = 0;
*(ld->data_buffer) = '\0';
}
/*
* new_locale_collation() - creates new collation in the locale struct
*
* return: rule
* ld(in): locale data
*/
static LOCALE_COLLATION *
new_locale_collation (LOCALE_DATA * ld)
{
LOCALE_COLLATION *loc_collation = NULL;
assert (ld != NULL);
/* check number of rules, increase array if necessary */
LOCALE_COLLATION *const realloc_collations
= (LOCALE_COLLATION *) realloc (ld->collations, sizeof (LOCALE_COLLATION) * (ld->coll_cnt + 1));
if (realloc_collations == NULL)
{
return NULL;
}
else
{
ld->collations = realloc_collations;
}
loc_collation = &(ld->collations[ld->coll_cnt]);
memset (loc_collation, 0, sizeof (LOCALE_COLLATION));
loc_collation->tail_coll.sett_max_cp = -1;
loc_collation->tail_coll.uca_opt.sett_contr_policy = CONTR_IGNORE;
return loc_collation;
}
/*
* new_collation_rule() - creates new collation tailoring rule
*
* return: rule
* ld(in): locale data
*/
static TAILOR_RULE *
new_collation_rule (LOCALE_DATA * ld)
{
TAILOR_RULE *t_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
assert (ld != NULL);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
/* check number of rules, increase array if necessary */
if (curr_coll_tail->count_rules + 1 >= curr_coll_tail->max_rules)
{
TAILOR_RULE *const realloc_rules = (TAILOR_RULE *) realloc (curr_coll_tail->rules,
sizeof (TAILOR_RULE) * (curr_coll_tail->max_rules +
LOC_DATA_TAILOR_RULES_COUNT_GROW));
if (realloc_rules == NULL)
{
return NULL;
}
else
{
curr_coll_tail->rules = realloc_rules;
}
curr_coll_tail->max_rules += LOC_DATA_TAILOR_RULES_COUNT_GROW;
}
/* will use slot indicated by 'coll->count_rules' */
t_rule = &(curr_coll_tail->rules[curr_coll_tail->count_rules]);
memset (t_rule, 0, sizeof (TAILOR_RULE));
return t_rule;
}
/*
* new_transform_rule() - creates new transform rule
*
* return: rule
* ld(in): locale data
*/
static TRANSFORM_RULE *
new_transform_rule (LOCALE_DATA * ld)
{
TRANSFORM_RULE *tf_rule = NULL;
assert (ld != NULL);
/* check number of rules, increase array if necessary */
if (ld->alpha_tailoring.count_rules + 1 >= ld->alpha_tailoring.max_rules)
{
TRANSFORM_RULE *const realloc_alpha_tailoring_rules = (TRANSFORM_RULE *) realloc (ld->alpha_tailoring.rules,
sizeof (TRANSFORM_RULE) *
(ld->alpha_tailoring.max_rules +
LOC_DATA_TAILOR_RULES_COUNT_GROW));
if (realloc_alpha_tailoring_rules == NULL)
{
return NULL;
}
else
{
ld->alpha_tailoring.rules = realloc_alpha_tailoring_rules;
}
ld->alpha_tailoring.max_rules += LOC_DATA_TAILOR_RULES_COUNT_GROW;
}
/* will use slot indicated by 'alpha_tailoring->count_rules' */
tf_rule = &(ld->alpha_tailoring.rules[ld->alpha_tailoring.count_rules]);
memset (tf_rule, 0, sizeof (TRANSFORM_RULE));
return tf_rule;
}
/*
* new_collation_cubrid_rule - creates new collation tailoring rule
*
* return: rule
* ld(in): locale data
*/
static CUBRID_TAILOR_RULE *
new_collation_cubrid_rule (LOCALE_DATA * ld)
{
CUBRID_TAILOR_RULE *ct_rule = NULL;
COLL_TAILORING *curr_coll_tail = NULL;
assert (ld != NULL);
curr_coll_tail = LOC_CURRENT_COLL_TAIL (ld);
/* check number of absolute rules, increase array if necessary */
if (curr_coll_tail->cub_count_rules + 1 >= curr_coll_tail->cub_max_rules)
{
CUBRID_TAILOR_RULE *const realloc_cub_rules = (CUBRID_TAILOR_RULE *) realloc (curr_coll_tail->cub_rules,
sizeof (CUBRID_TAILOR_RULE) *
(curr_coll_tail->max_rules +
LOC_DATA_COLL_CUBRID_TAILOR_COUNT_GROW));
if (realloc_cub_rules == NULL)
{
return NULL;
}
else
{
curr_coll_tail->cub_rules = realloc_cub_rules;
}
curr_coll_tail->cub_max_rules += LOC_DATA_COLL_CUBRID_TAILOR_COUNT_GROW;
}
/* will use slot indicated by 'coll->cub_count_rules' */
ct_rule = &(curr_coll_tail->cub_rules[curr_coll_tail->cub_count_rules]);
memset (ct_rule, 0, sizeof (CUBRID_TAILOR_RULE));
return ct_rule;
}
/*
* print_debug_start_el() - print debug info for start of XML element
*
* return:
* data(in):
* attrs(in):
* status(in): status returned from start function
*/
static void
print_debug_start_el (void *data, const char **attrs, const char *msg, const int status)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
const char **curr_att;
assert (data != NULL);
assert (attrs != NULL);
if (pd->verbose)
{
int i;
assert (pd->ce != NULL);
assert (pd->ce->def != NULL);
for (i = 0; i < pd->ce->def->depth; i++)
{
printf (" ");
}
printf ("<%s", pd->ce->short_name);
for (curr_att = attrs; *curr_att != NULL; curr_att++, curr_att++)
{
printf (" %s=\"%s\"", curr_att[0], curr_att[1]);
}
if (*msg == '\0' && status == 0)
{
printf (">\n");
}
else
{
printf ("> " XML_COMMENT_START " %s ", msg);
if (status == 0)
{
printf (XML_COMMENT_END "\n");
}
else if (status == -1)
{
printf (" * NOK, Aborting ! *" XML_COMMENT_END "\n");
}
else
{
printf (" * Ignore *" XML_COMMENT_END "\n");
}
}
}
}
/*
* print_debug_end_el() - print debug info for end of XML element
*
* return:
* data(in):
* status(in): status returned from start function
*/
static void
print_debug_end_el (void *data, const char *msg, const int status)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
assert (data != NULL);
if (pd->verbose)
{
int i;
assert (pd->ce != NULL);
assert (pd->ce->def != NULL);
for (i = 0; i < pd->ce->def->depth; i++)
{
printf (" ");
}
printf ("<\\%s> ", pd->ce->short_name);
if (*msg == '\0' && status == 0)
{
printf ("\n");
}
else
{
printf (XML_COMMENT_START " %s ", msg);
if (status != 0)
{
printf (" * NOK, Aborting ! *" XML_COMMENT_END "\n");
}
else
{
printf (XML_COMMENT_END "\n");
}
}
}
}
/*
* print_debug_data_content() - print debug info data content of XML element
*
* return:
* data(in):
* status(in): status returned from start function
*/
static void
print_debug_data_content (void *data, const char *msg, const int status)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
assert (data != NULL);
if (pd->verbose)
{
int i;
assert (pd->ce != NULL);
assert (pd->ce->def != NULL);
for (i = 0; i < pd->ce->def->depth + 1; i++)
{
printf (" ");
}
assert (msg != NULL);
printf ("%s ", msg);
if (status != 0)
{
printf (XML_COMMENT_START "* NOK, Aborting ! *" XML_COMMENT_END);
}
printf ("\n");
}
}
/*
* locale_alloc_collation_id() - allocates collation id
*
* return:
*
* Note : Ranges of collation id:
* 0 - 31(*) : built-in collations (32)
* 32(*) - 46 : generic collations (language independent) (15)
* 47 - 255 : language dependent collations (208 = 26 * 8)
* Collation is name is in format: charset_lang_desc1_desc2_..
* utf8_de_exp : Collation specific to de (German) with expansions
* utf8_gen_ai_ci : Generic collation, accent and case insensitive
*
*/
static void
locale_alloc_collation_id (COLL_TAILORING * coll_tail)
{
#define ID_PER_RANGE 8
#define START_GENERIC_RANGE LANG_MAX_BUILTIN_COLLATIONS
#define START_LANG_RANGE 47
int coll_id = 0;
char coll_name[COLL_NAME_SIZE];
const char *lang_part, *desc_part;
int range_start, range_size;
strcpy (coll_name, coll_tail->coll_name);
lang_part = strchr (coll_name, '_');
if (lang_part != NULL)
{
lang_part++;
desc_part = strchr (lang_part, '_');
if (desc_part != NULL)
{
desc_part++;
}
}
else
{
desc_part = NULL;
}
if (lang_part != NULL)
{
if (strncasecmp (lang_part, "gen", 3) == 0)
{
range_start = START_GENERIC_RANGE;
range_size = (START_LANG_RANGE - START_GENERIC_RANGE) + 1;
}
else
{
int s = (int) *lang_part;
s = (char_isupper (s)) ? (s + ('a' - 'A')) : s;
s = (s > 'z') ? 'z' : ((s < 'a') ? 'a' : s);
s -= 'a';
range_start = START_LANG_RANGE + s * ID_PER_RANGE;
range_size = ID_PER_RANGE;
}
if (desc_part != NULL)
{
while (*desc_part)
{
coll_id += *desc_part++;
}
}
coll_id %= range_size;
coll_id += range_start;
}
coll_tail->coll_id = coll_id;
#undef ID_PER_RANGE
#undef START_GENERIC_RANGE
#undef START_LANG_RANGE
}
/*
* locale_check_collation_id() - checks a collation id
*
* return:
*
*
*/
static int
locale_check_collation_id (const COLL_TAILORING * coll_tail)
{
char err_msg[ERR_MSG_SIZE];
static int taken_collations[LANG_MAX_COLLATIONS] = { 0 };
assert (coll_tail->coll_id >= LANG_MAX_BUILTIN_COLLATIONS && coll_tail->coll_id < LANG_MAX_COLLATIONS);
if (taken_collations[coll_tail->coll_id] != 0)
{
snprintf (err_msg, sizeof (err_msg) - 1,
"Invalid collation numeric identifier : %d" " for collation '%s'. Id is already taken.",
coll_tail->coll_id, coll_tail->coll_name);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return ER_LOC_GEN;
}
taken_collations[coll_tail->coll_id] = 1;
return NO_ERROR;
}
/*
* load_console_conv_data() - Loads the console conversion file (standardised
* and availabe at Unicode.org).
* Returns: error code
* ld(in/out) : locale data
* is_verbose(in) :
*/
static int
load_console_conv_data (LOCALE_DATA * ld, bool is_verbose)
{
TXT_CONV_ITEM *txt_conv_array = NULL;
FILE *fp = NULL;
char *end_p;
char err_msg[ERR_MSG_SIZE];
char str[TXT_CONV_LINE_SIZE];
char conv_file_name[PATH_MAX];
int status = NO_ERROR;
int line_count = 0;
int txt_conv_max_items = 0;
int txt_conv_count_items = 0;
unsigned int i;
unsigned int cp_text = 0;
unsigned int cp_unicode = 0;
TXT_CONV_ITEM min_values = { 0xffff, 0xffff };
TXT_CONV_ITEM max_values = { 0, 0 };
assert (ld != NULL);
if (ld->txt_conv_prm.conv_type == TEXT_CONV_NO_CONVERSION)
{
if (is_verbose)
{
printf ("No console conversion data\n");
}
return status;
}
if (ld->txt_conv_prm.conv_type == TEXT_CONV_ISO_88591_BUILTIN
|| ld->txt_conv_prm.conv_type == TEXT_CONV_ISO_88599_BUILTIN)
{
if (is_verbose)
{
printf ("Built-in console conversion\n");
}
ld->txt_conv.conv_type = ld->txt_conv_prm.conv_type;
return status;
}
strncpy (conv_file_name, ld->txt_conv_prm.conv_file, sizeof (conv_file_name) - 1);
conv_file_name[sizeof (conv_file_name) - 1] = '\0';
fp = fopen_ex (conv_file_name, "rt");
if (fp == NULL)
{
envvar_codepagedir_file (conv_file_name, sizeof (conv_file_name), ld->txt_conv_prm.conv_file);
fp = fopen_ex (conv_file_name, "rt");
}
if (fp == NULL)
{
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Cannot open file %s", ld->txt_conv_prm.conv_file);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
if (is_verbose)
{
printf ("Using file: %s\n", conv_file_name);
}
memset (ld->txt_conv.byte_flag, 0, sizeof (ld->txt_conv.byte_flag));
while (fgets (str, sizeof (str), fp))
{
char *s;
line_count++;
s = str;
/* skip white spaces */
while (char_isspace (*s))
{
s++;
}
if (*s == '\0' || *s == '#')
{
continue;
}
str_to_uint32 (&cp_text, &end_p, s, 16);
/* skip codepoints values above 0xFFFF */
if (cp_text > 0xffff || (cp_text > 0xff && ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_1BYTE))
{
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Codepoint value too big" " in file :%s at line %d",
ld->txt_conv_prm.conv_file, line_count);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
/* skip first token */
while (!char_isspace (*s))
{
s++;
}
/* skip white spaces */
while (char_isspace (*s))
{
s++;
}
if (*s == '\0' || *s == '#')
{
if (ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_2BYTE)
{
assert (cp_text <= 0xff);
if (strncasecmp (s, "#DBCS", 5) == 0)
{
ld->txt_conv.byte_flag[cp_text] = 1;
}
else
{
ld->txt_conv.byte_flag[cp_text] = 2;
}
}
continue;
}
str_to_uint32 (&cp_unicode, &end_p, s, 16);
/* first codepoints which maps the same character are not included */
if (((ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_1BYTE && cp_text < 0x80)
|| ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_2BYTE) && (cp_text == cp_unicode
&& min_values.text_cp == 0xffff
&& min_values.unicode_cp == 0xffff))
{
continue;
}
if (cp_unicode > 0xffff)
{
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Codepoint value too big" " in file :%s at line %d",
ld->txt_conv_prm.conv_file, line_count);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
if (txt_conv_count_items >= txt_conv_max_items)
{
TXT_CONV_ITEM *const realloc_txt_conv_array = (TXT_CONV_ITEM *) realloc (txt_conv_array,
sizeof (TXT_CONV_ITEM) *
(txt_conv_max_items +
TXT_CONV_ITEM_GROW_COUNT));
if (realloc_txt_conv_array == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
else
{
txt_conv_array = realloc_txt_conv_array;
}
txt_conv_max_items += TXT_CONV_ITEM_GROW_COUNT;
}
txt_conv_array[txt_conv_count_items].text_cp = cp_text;
txt_conv_array[txt_conv_count_items].unicode_cp = cp_unicode;
min_values.text_cp = MIN (min_values.text_cp, cp_text);
min_values.unicode_cp = MIN (min_values.unicode_cp, cp_unicode);
max_values.text_cp = MAX (max_values.text_cp, cp_text);
max_values.unicode_cp = MAX (max_values.unicode_cp, cp_unicode);
txt_conv_count_items++;
}
if (is_verbose)
{
printf ("Building %d console conversion rules\n", txt_conv_count_items);
}
/* build conversions */
ld->txt_conv.text_first_cp = min_values.text_cp;
ld->txt_conv.text_last_cp = max_values.text_cp;
ld->txt_conv.utf8_first_cp = min_values.unicode_cp;
ld->txt_conv.utf8_last_cp = max_values.unicode_cp;
assert (ld->txt_conv.text_first_cp < ld->txt_conv.text_last_cp);
assert (ld->txt_conv.utf8_first_cp < ld->txt_conv.utf8_last_cp);
if (ld->txt_conv.text_last_cp == 0 || ld->txt_conv.utf8_last_cp == 0)
{
LOG_LOCALE_ERROR ("Invalid console mapping", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
ld->txt_conv.text_to_utf8 =
(CONV_CP_TO_BYTES *) malloc (sizeof (CONV_CP_TO_BYTES) *
(ld->txt_conv.text_last_cp - ld->txt_conv.text_first_cp + 1));
memset (ld->txt_conv.text_to_utf8, 0,
sizeof (CONV_CP_TO_BYTES) * (ld->txt_conv.text_last_cp - ld->txt_conv.text_first_cp + 1));
ld->txt_conv.utf8_to_text =
(CONV_CP_TO_BYTES *) malloc (sizeof (CONV_CP_TO_BYTES) *
(ld->txt_conv.utf8_last_cp - ld->txt_conv.utf8_first_cp + 1));
memset (ld->txt_conv.utf8_to_text, 0,
sizeof (CONV_CP_TO_BYTES) * (ld->txt_conv.utf8_last_cp - ld->txt_conv.utf8_first_cp + 1));
if (ld->txt_conv.text_to_utf8 == NULL || ld->txt_conv.utf8_to_text == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
for (i = 0; i < ld->txt_conv.text_last_cp - ld->txt_conv.text_first_cp + 1; i++)
{
ld->txt_conv.text_to_utf8[i].size = 1;
*(ld->txt_conv.text_to_utf8[i].bytes) = '?';
}
for (i = 0; i < ld->txt_conv.utf8_last_cp - ld->txt_conv.utf8_first_cp + 1; i++)
{
ld->txt_conv.utf8_to_text[i].size = 1;
*(ld->txt_conv.utf8_to_text[i].bytes) = '?';
}
for (i = 0; (int) i < txt_conv_count_items; i++)
{
CONV_CP_TO_BYTES *text_to_utf8_item = NULL;
CONV_CP_TO_BYTES *utf8_to_text_item = NULL;
cp_text = txt_conv_array[i].text_cp;
cp_unicode = txt_conv_array[i].unicode_cp;
assert (cp_text >= ld->txt_conv.text_first_cp && cp_text <= ld->txt_conv.text_last_cp);
assert (cp_unicode >= ld->txt_conv.utf8_first_cp && cp_unicode <= ld->txt_conv.utf8_last_cp);
text_to_utf8_item = &(ld->txt_conv.text_to_utf8[cp_text - ld->txt_conv.text_first_cp]);
utf8_to_text_item = &(ld->txt_conv.utf8_to_text[cp_unicode - ld->txt_conv.utf8_first_cp]);
text_to_utf8_item->size = intl_cp_to_utf8 (cp_unicode, text_to_utf8_item->bytes);
if (ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_1BYTE)
{
utf8_to_text_item->size = 1;
utf8_to_text_item->bytes[0] = cp_text;
}
else
{
assert (ld->txt_conv_prm.conv_type == TEXT_CONV_GENERIC_2BYTE);
utf8_to_text_item->size = intl_cp_to_dbcs (cp_text, ld->txt_conv.byte_flag, utf8_to_text_item->bytes);
}
}
assert (fp != NULL);
fclose (fp);
assert (txt_conv_array != NULL);
free (txt_conv_array);
ld->txt_conv.conv_type = ld->txt_conv_prm.conv_type;
ld->txt_conv.win_codepages = strdup (ld->txt_conv_prm.win_codepages);
ld->txt_conv.nl_lang_str = strdup (ld->txt_conv_prm.nl_lang_str);
if (ld->txt_conv.nl_lang_str == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto error;
}
return status;
error:
if (fp != NULL)
{
fclose (fp);
}
if (txt_conv_array != NULL)
{
free (txt_conv_array);
}
return status;
}
/*
* comp_func_parse_order_index - compare function for sorting parse order
* indexes for month and weekday names, based on the reversed
* binary order of the LDML tokens
*
* Note: this function is used by the genlocale tool
* The elements in the arrays should be NUL-terminated strings, stored
* in fixed length char arrays. Encoding is not relevant, the purpose
* of this comparison is to make sure that the tokenizer first tries
* to match some tokens before others which can be prefixes for them.
* E.g. In Vietnamese(vi_VN), the October translation followed by
* a space is a prefix for the translations of November and December.
*/
static int
comp_func_parse_order_index (const void *arg1, const void *arg2)
{
char *s1;
char *s2;
char pos1;
char pos2;
int cmp;
pos1 = *((char *) arg1);
pos2 = *((char *) arg2);
s1 = (char *) (cmp_token_name_array + pos1 * cmp_token_name_size);
s2 = (char *) (cmp_token_name_array + pos2 * cmp_token_name_size);
cmp = strcmp (s2, s1);
return (cmp == 0) ? (pos1 - pos2) : cmp;
}
/*
* locale_make_calendar_parse_order() - computes the order in which the
* string tokenizer should search for matches with
* weekday and month names, both wide and abbreviated.
*
* return:
* ld(in/out): LOCALE_DATA for which to do the processing
*/
static void
locale_make_calendar_parse_order (LOCALE_DATA * ld)
{
int i;
for (i = 0; i < CAL_MONTH_COUNT; i++)
{
ld->month_names_abbr_parse_order[i] = i;
ld->month_names_wide_parse_order[i] = i;
}
for (i = 0; i < CAL_DAY_COUNT; i++)
{
ld->day_names_abbr_parse_order[i] = i;
ld->day_names_wide_parse_order[i] = i;
}
for (i = 0; i < CAL_AM_PM_COUNT; i++)
{
ld->am_pm_parse_order[i] = i;
}
cmp_token_name_array = (char *) (ld->month_names_abbreviated);
cmp_token_name_size = LOC_DATA_MONTH_ABBR_SIZE;
qsort (ld->month_names_abbr_parse_order, CAL_MONTH_COUNT, sizeof (char), comp_func_parse_order_index);
cmp_token_name_array = (char *) (ld->month_names_wide);
cmp_token_name_size = LOC_DATA_MONTH_WIDE_SIZE;
qsort (ld->month_names_wide_parse_order, CAL_MONTH_COUNT, sizeof (char), comp_func_parse_order_index);
cmp_token_name_array = (char *) (ld->day_names_abbreviated);
cmp_token_name_size = LOC_DATA_DAY_ABBR_SIZE;
qsort (ld->day_names_abbr_parse_order, CAL_DAY_COUNT, sizeof (char), comp_func_parse_order_index);
cmp_token_name_array = (char *) (ld->day_names_wide);
cmp_token_name_size = LOC_DATA_DAY_WIDE_SIZE;
qsort (ld->day_names_wide_parse_order, CAL_DAY_COUNT, sizeof (char), comp_func_parse_order_index);
cmp_token_name_array = (char *) (ld->am_pm);
cmp_token_name_size = LOC_DATA_AM_PM_SIZE;
qsort (ld->am_pm_parse_order, CAL_AM_PM_COUNT, sizeof (char), comp_func_parse_order_index);
}
/*
* locale_init_data() - initializes one locale data
*
* return:
* ld(in/out):
* locale_name(in):
*/
void
locale_init_data (LOCALE_DATA * ld, const char *locale_name)
{
memset (ld, 0, sizeof (LOCALE_DATA));
ld->curr_period = -1;
assert (strlen (locale_name) < (int) sizeof (ld->locale_name));
strcpy (ld->locale_name, locale_name);
/* default number symbols */
ld->number_decimal_sym = ',';
ld->number_group_sym = '.';
ld->default_currency_code = DB_CURRENCY_NULL;
ld->alpha_tailoring.sett_max_letters = -1;
}
/*
* locale_destroy_data() - frees memory allocated for one locale data
*
* return:
* ld(in/out):
*/
void
locale_destroy_data (LOCALE_DATA * ld)
{
int i;
assert (ld != NULL);
/* collations */
for (i = 0; i < ld->coll_cnt; i++)
{
locale_destroy_collation_data (&(ld->collations[i].opt_coll));
locale_destroy_collation_tailorings (&(ld->collations[i].tail_coll));
}
free (ld->collations);
ld->collations = NULL;
ld->coll_cnt = 0;
/* alphabet tailoring */
locale_destroy_alphabet_tailoring (&(ld->alpha_tailoring));
/* alphabets */
locale_destroy_alphabet_data (&(ld->alphabet));
locale_destroy_alphabet_data (&(ld->identif_alphabet));
locale_destroy_console_conversion (&(ld->txt_conv));
locale_destroy_normalization_data (&(ld->unicode_normalization));
/* ldml context file path */
if (ld->ldml_context.ldml_file != NULL)
{
free (ld->ldml_context.ldml_file);
}
}
/*
* locale_destroy_alphabet_data() - frees memory for one locale alphabet
* return:
* a(in/out):
*
* Note : Alphabets that are common are not freed
*/
void
locale_destroy_alphabet_data (const ALPHABET_DATA * a)
{
assert (a != NULL);
if (a->lower_cp != NULL)
{
free (a->lower_cp);
}
if (a->upper_cp != NULL)
{
free (a->upper_cp);
}
memset ((void *) a, 0, sizeof (ALPHABET_DATA));
}
/*
* locale_destroy_collation_tailorings() - frees memory for one locale
* collation tailorings
* return:
* ct(in/out):
*/
static void
locale_destroy_collation_tailorings (const COLL_TAILORING * ct)
{
int i;
assert (ct != NULL);
/* collation tailorings */
for (i = 0; i < ct->count_rules; i++)
{
TAILOR_RULE *t_rule = &(ct->rules[i]);
assert (t_rule != NULL);
assert (t_rule->t_buf != NULL);
if (t_rule->t_buf != NULL)
{
assert (t_rule->t_buf_size > 0);
free (t_rule->t_buf);
}
if (t_rule->r_buf != NULL)
{
assert (t_rule->r_buf_size > 0);
free (t_rule->r_buf);
}
memset (t_rule, 0, sizeof (TAILOR_RULE));
}
if (ct->rules != NULL)
{
assert (ct->max_rules > 0);
free (ct->rules);
}
if (ct->cub_rules != NULL)
{
assert (ct->cub_max_rules > 0);
free (ct->cub_rules);
}
if (ct->ldml_context.ldml_file != NULL)
{
free (ct->ldml_context.ldml_file);
}
memset ((void *) ct, 0, sizeof (COLL_TAILORING));
}
/*
* locale_destroy_collation_data() - frees memory for collation data
* return:
* cd(in/out):
*/
static void
locale_destroy_collation_data (const COLL_DATA * cd)
{
assert (cd != NULL);
/* collation data */
if (cd->weights != NULL)
{
free (cd->weights);
}
if (cd->next_cp != NULL)
{
free (cd->next_cp);
}
/* contractions */
if (cd->uca_num != NULL)
{
free (cd->uca_num);
}
if (cd->uca_w_l13 != NULL)
{
free (cd->uca_w_l13);
}
if (cd->uca_w_l4 != NULL)
{
free (cd->uca_w_l4);
}
if (cd->cp_first_contr_array != NULL)
{
free (cd->cp_first_contr_array);
}
if (cd->contr_list != NULL)
{
free (cd->contr_list);
}
memset ((void *) cd, 0, sizeof (COLL_DATA));
}
/*
* locale_destroy_alphabet_tailoring() - frees memory for alphabet tailorings
* return:
* at(in/out):
*/
static void
locale_destroy_alphabet_tailoring (const ALPHABET_TAILORING * at)
{
int i;
assert (at != 0);
/* case tailoring */
for (i = 0; i < at->count_rules; i++)
{
TRANSFORM_RULE *tf_rule = &(at->rules[i]);
assert (tf_rule != NULL);
assert (tf_rule->src != NULL);
assert (tf_rule->dest != NULL);
if (tf_rule->src != NULL)
{
assert (tf_rule->src_size > 0);
free (tf_rule->src);
}
if (tf_rule->dest != NULL)
{
assert (tf_rule->dest_size > 0);
free (tf_rule->dest);
}
memset (tf_rule, 0, sizeof (TRANSFORM_RULE));
}
if (at->rules != NULL)
{
assert (at->max_rules > 0);
free (at->rules);
}
if (at->ldml_context.ldml_file != NULL)
{
free (at->ldml_context.ldml_file);
}
memset ((void *) at, 0, sizeof (ALPHABET_TAILORING));
}
/*
* locale_destroy_console_conversion() - frees memory for console conversion
* return:
* tc(in/out):
*/
static void
locale_destroy_console_conversion (const TEXT_CONVERSION * tc)
{
assert (tc != 0);
/* console conversion */
if (tc->nl_lang_str != NULL)
{
free (tc->nl_lang_str);
}
if (tc->win_codepages != NULL)
{
free (tc->win_codepages);
}
if (tc->text_to_utf8 != NULL)
{
free (tc->text_to_utf8);
}
if (tc->utf8_to_text != NULL)
{
free (tc->utf8_to_text);
}
memset ((void *) tc, 0, sizeof (TEXT_CONVERSION));
}
/*
* locale_compile_locale() - process locale data loaded from LDML file(s)
*
* return: error code
* lf(in): structure containing file paths
* ld(in): locale data to be processed
* is_verbose(in):
*/
int
locale_compile_locale (LOCALE_FILE * lf, LOCALE_DATA * ld, bool is_verbose)
{
XML_PARSER_DATA ldml_parser;
LOC_SHARED_DATA *norm_sh_entry = NULL;
char *locale_str = NULL;
int er_status = NO_ERROR;
int i;
assert (lf != NULL);
locale_str = lf->locale_name;
if (is_verbose)
{
printf ("\n*** Parsing LDML\n");
}
locale_init_data (ld, locale_str);
ldml_parser.ud = ld;
ldml_parser.verbose = is_verbose;
ld->ldml_context.ldml_file = strdup (lf->ldml_file);
ld->ldml_context.line_no = 1;
ldml_parser.xml_parser =
xml_init_parser (&ldml_parser, lf->ldml_file, "UTF-8", ldml_elements,
sizeof (ldml_elements) / sizeof (XML_ELEMENT_DEF *));
if (ldml_parser.xml_parser == NULL)
{
LOG_LOCALE_ERROR ("Cannot init XML parser", ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
xml_parser_exec (&ldml_parser);
if (ldml_parser.xml_error == XML_CUB_NO_ERROR)
{
if (is_verbose)
{
printf ("Parsing finished.\n");
printf ("Date format: %s\n", ld->dateFormat);
printf ("Time format: %s\n", ld->timeFormat);
printf ("Datetime format: %s\n", ld->datetimeFormat);
printf ("Timestamp format: %s\n", ld->timestampFormat);
printf ("Timetz format: %s\n", ld->timetzFormat);
printf ("Datetimetz format: %s\n", ld->datetimetzFormat);
printf ("Timestamptz format: %s\n", ld->timestamptzFormat);
}
}
else
{
char msg[ERR_MSG_SIZE];
const char *xml_err_text = (char *) XML_ErrorString (XML_GetErrorCode (ldml_parser.xml_parser));
snprintf_dots_truncate (msg, sizeof (msg) - 1,
"Error parsing file %s, " "line : %d, column : %d. Internal XML: %s",
ldml_parser.filepath, ldml_parser.xml_error_line, ldml_parser.xml_error_column,
xml_err_text);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
locale_make_calendar_parse_order (ld);
if (ld->alpha_tailoring.sett_max_letters == -1)
{
ld->alpha_tailoring.sett_max_letters = MAX_UNICODE_CHARS;
}
if (is_verbose)
{
printf ("\n*** Processing alphabet ***\nNumber of letters = %d\n", ld->alpha_tailoring.sett_max_letters);
}
if (ld->alpha_tailoring.sett_max_letters == 0)
{
ld->alphabet.l_count = ld->alpha_tailoring.sett_max_letters;
}
else
{
LOC_SHARED_DATA *alphabet_sh_entry = NULL;
LDML_CONTEXT *ldml_context = &(ld->alpha_tailoring.ldml_context);
er_status = unicode_process_alphabet (ld, is_verbose);
if (er_status != NO_ERROR)
{
goto exit;
}
if (ld->alphabet.a_type == ALPHABET_UNICODE)
{
er_status =
locale_check_and_set_shared_data (LOC_SHARED_ALPHABET, "unicode", NULL, ldml_context, &alphabet_sh_entry);
}
else if (ld->alphabet.a_type == ALPHABET_ASCII)
{
er_status =
locale_check_and_set_shared_data (LOC_SHARED_ALPHABET, "ascii", NULL, ldml_context, &alphabet_sh_entry);
}
if (er_status != NO_ERROR)
{
goto exit;
}
ld->alphabet.do_not_save = (alphabet_sh_entry != NULL) ? true : false;
alphabet_sh_entry = NULL;
if (ld->identif_alphabet.a_type == ALPHABET_UNICODE)
{
er_status =
locale_check_and_set_shared_data (LOC_SHARED_ALPHABET, "unicode", NULL, ldml_context, &alphabet_sh_entry);
}
else if (ld->identif_alphabet.a_type == ALPHABET_ASCII)
{
er_status =
locale_check_and_set_shared_data (LOC_SHARED_ALPHABET, "ascii", NULL, ldml_context, &alphabet_sh_entry);
}
if (er_status != NO_ERROR)
{
goto exit;
}
ld->identif_alphabet.do_not_save = (alphabet_sh_entry != NULL) ? true : false;
if (ld->identif_alphabet.do_not_save == false)
{
/* check that casing data matches the rule of INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER: the ratio between the
* size in bytes of lower (or upper) case character (or sequence of characters) and the size in bytes of
* original character is less than INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER */
unsigned int cp;
ALPHABET_DATA *a = &(ld->identif_alphabet);
unsigned char dummy[INTL_UTF8_MAX_CHAR_SIZE];
for (cp = 0; (int) cp < a->l_count; cp++)
{
int case_cnt, case_size, cp_size;
unsigned int *lower_cp = &(a->lower_cp[cp * a->lower_multiplier]);
unsigned int *upper_cp = &(a->upper_cp[cp * a->upper_multiplier]);
for (case_size = 0, case_cnt = 0; case_cnt < a->lower_multiplier && *lower_cp != 0;
case_cnt++, lower_cp++)
{
if (*lower_cp == cp)
{
/* character does not have lower case */
case_size = 0;
break;
}
case_size += intl_cp_to_utf8 (*lower_cp, dummy);
}
if (case_size > 0)
{
cp_size = intl_cp_to_utf8 (cp, dummy);
if (case_size > cp_size * INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1,
"Lower case " "sequence for codepoint Ux%04X is too "
"big: %d bytes; expecting at most %d", cp, case_size,
cp_size * INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
}
for (case_size = 0, case_cnt = 0; case_cnt < a->upper_multiplier && *upper_cp != 0;
case_cnt++, upper_cp++)
{
if (*upper_cp == cp)
{
/* character does not have upper case */
case_size = 0;
break;
}
case_size += intl_cp_to_utf8 (*upper_cp, dummy);
}
if (case_size > 0)
{
cp_size = intl_cp_to_utf8 (cp, dummy);
if (case_size > cp_size * INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER)
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1,
"Upper case " "sequence for codepoint Ux%04X is too "
"big: %d bytes; expecting at most %d", cp, case_size,
cp_size * INTL_IDENTIFIER_CASING_SIZE_MULTIPLIER);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
}
}
}
}
if (is_verbose)
{
printf ("\n*** Processing Unicode normalization data ***\n");
}
er_status = locale_check_and_set_shared_data (LOC_SHARED_NORMALIZATION, "normalization", NULL, NULL, &norm_sh_entry);
ld->unicode_normalization.do_not_save = (norm_sh_entry != NULL) ? true : false;
if (norm_sh_entry == NULL)
{
/* not shared, process normalization */
er_status = unicode_process_normalization (ld, is_verbose);
if (er_status != NO_ERROR)
{
goto exit;
}
}
if (is_verbose)
{
printf ("\n*** Processing console conversion data ***\n");
}
er_status = load_console_conv_data (ld, is_verbose);
if (er_status != NO_ERROR)
{
goto exit;
}
if (ld->coll_cnt == 0 && is_verbose)
{
printf ("\n*** No collation defined ***\n");
}
for (i = 0; i < ld->coll_cnt; i++)
{
LOC_SHARED_DATA *coll_sh_entry = NULL;
LOCALE_COLLATION *lc = &(ld->collations[i]);
char shared_coll_data[COLL_SHARED_DATA_SIZE];
strncpy (lc->opt_coll.coll_name, lc->tail_coll.coll_name, COLL_NAME_SIZE);
lc->opt_coll.coll_name[COLL_NAME_SIZE - 1] = '\0';
if (!lang_is_coll_name_allowed (lc->opt_coll.coll_name))
{
char msg[ERR_MSG_SIZE];
snprintf (msg, sizeof (msg) - 1,
"Collation name %s " "not allowed. It cannot contain white-spaces "
"or have same name as a built-in collation", lc->opt_coll.coll_name);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
snprintf (shared_coll_data, sizeof (shared_coll_data) - 1, "%d", lc->tail_coll.coll_id);
er_status =
locale_check_and_set_shared_data (LOC_SHARED_COLLATION, lc->tail_coll.coll_name, &shared_coll_data,
&(lc->tail_coll.ldml_context), &coll_sh_entry);
if (er_status != NO_ERROR)
{
goto exit;
}
lc->do_not_save = (coll_sh_entry != NULL) ? true : false;
if (coll_sh_entry != NULL)
{
/* check found entry */
const char *coll_sh_data = (const char *) coll_sh_entry->data;
assert (coll_sh_data != NULL);
if (strcmp (shared_coll_data, coll_sh_data) != 0)
{
/* found collation with same name buf different collation shared data (collation id) */
char msg[ERR_MSG_SIZE + 2 * PATH_MAX];
snprintf (msg, sizeof (msg) - 1,
"File: %s, line: %d : " "collation name %s (id:%d) already defined in "
"file: %s, line: %d with id: %s", lc->tail_coll.ldml_context.ldml_file,
lc->tail_coll.ldml_context.line_no, lc->tail_coll.coll_name, lc->tail_coll.coll_id,
coll_sh_entry->ldml_context.ldml_file, coll_sh_entry->ldml_context.line_no, coll_sh_data);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
er_status = ER_LOC_GEN;
goto exit;
}
else if (strcmp (lc->tail_coll.ldml_context.ldml_file, coll_sh_entry->ldml_context.ldml_file) != 0
|| lc->tail_coll.ldml_context.line_no != coll_sh_entry->ldml_context.line_no)
{
/* same collation, just put an debug info */
printf ("Warning : Definition of collation %s (id: %d) " "ignored in file: %s, line: %d. "
"Using the definition from file: %s, line: %d.\n", lc->tail_coll.coll_name, lc->tail_coll.coll_id,
lc->tail_coll.ldml_context.ldml_file, lc->tail_coll.ldml_context.line_no,
coll_sh_entry->ldml_context.ldml_file, coll_sh_entry->ldml_context.line_no);
}
continue;
}
if (lc->tail_coll.sett_max_cp == -1)
{
lc->tail_coll.sett_max_cp = MAX_UNICODE_CHARS;
}
if (is_verbose)
{
printf ("\n*** Processing collation : %s ***\n" "Number of weights = %d\n", lc->tail_coll.coll_name,
lc->tail_coll.sett_max_cp);
}
if (lc->tail_coll.sett_max_cp == 0)
{
lc->opt_coll.w_count = lc->tail_coll.sett_max_cp;
}
else
{
er_status = uca_process_collation (lc, is_verbose);
if (er_status != NO_ERROR)
{
goto exit;
}
if (lc->tail_coll.coll_id <= 0)
{
locale_alloc_collation_id (&lc->tail_coll);
}
er_status = locale_check_collation_id (&lc->tail_coll);
if (er_status != NO_ERROR)
{
goto exit;
}
lc->opt_coll.coll_id = lc->tail_coll.coll_id;
}
er_status = locale_compute_coll_checksum (&(lc->opt_coll));
if (er_status != NO_ERROR)
{
goto exit;
}
if (is_verbose)
{
printf ("ID : %d | Checksum : %s\n", lc->opt_coll.coll_id, lc->opt_coll.checksum);
}
}
er_status = locale_compute_locale_checksum (ld);
if (er_status != NO_ERROR)
{
goto exit;
}
if (is_verbose)
{
printf ("\n Locale checksum :%s\n", ld->checksum);
}
exit:
xml_destroy_parser (&ldml_parser);
uca_free_data ();
unicode_free_data ();
if (is_verbose)
{
printf ("\n\nLocale finished\n\n\n");
}
return er_status;
}
/*
* locale_mark_duplicate_collations - finds duplicate arrays within all
* collations and uses string identifiers from
* LOCALE_DATA structure to mark the arrays which will
* not be exported to the shared library, but another
* identical array will be loaded instead.
*
* return: error status
*
* ld(in): all locale data loaded from LDML and compiled
* start_index(in): index of the first working locale (in ld)
* end_index(in): index of the last working locale stored in the ld array
*/
void
locale_mark_duplicate_collations (LOCALE_DATA ** ld, int start_index, int end_index, bool is_verbose)
{
#define PRINT_DUPLICATE_SYMBOL_NAME(symbol, dupl_coll, orig_coll, do_print) \
if (do_print) \
{ \
printf ("\n *** Duplicate array: %s in collation %s is a duplicate " \
"of %s from collation %s", (symbol), \
(dupl_coll)->opt_coll.coll_name, \
(symbol), (orig_coll)->opt_coll.coll_name); \
}
int i1, i2, j1, j2;
LOCALE_COLLATION *cur_coll, *comp_coll;
LOCALE_DATA *cur_ld, *comp_ld;
/* Search for duplicate arrays. In order to avoid errors, search must be done backwards for the cursor collation,
* while searching forward in the locales; the rule of determining the identifier to be stored is that the first
* occurence is considered as the original, and all identical arrays that follow are duplicates */
for (i1 = end_index - 1; i1 >= start_index; i1--)
{
cur_ld = ld[i1];
for (j1 = cur_ld->coll_cnt - 1; j1 >= 0; j1--)
{
cur_coll = &(cur_ld->collations[j1]);
for (i2 = start_index; i2 <= i1; i2++)
{
comp_ld = ld[i2];
for (j2 = 0; (i1 == i2 && j2 < j1) || (i1 > i2 && j2 < comp_ld->coll_cnt); j2++)
{
comp_coll = &(comp_ld->collations[j2]);
/* Two COLL_INFO structures are refferenced.Compare them. */
if (cur_coll->opt_coll.w_count != comp_coll->opt_coll.w_count)
{
continue;
}
if (cur_coll->opt_coll.uca_opt.sett_expansions == comp_coll->opt_coll.uca_opt.sett_expansions)
{
if (!cur_coll->opt_coll.uca_opt.sett_expansions)
{
if (*(cur_coll->coll_ref.coll_weights_ref) == '\0'
&& memcmp (cur_coll->opt_coll.weights, comp_coll->opt_coll.weights,
sizeof (comp_coll->opt_coll.weights[0]) * cur_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_weights_ref, "%s_%s", "coll_weights",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_weights", cur_coll, comp_coll, is_verbose);
}
}
else
{
if (cur_coll->opt_coll.uca_exp_num != comp_coll->opt_coll.uca_exp_num)
{
continue;
}
if (*(cur_coll->coll_ref.coll_uca_num_ref) == '\0'
&& memcmp (cur_coll->opt_coll.uca_num, comp_coll->opt_coll.uca_num,
sizeof (comp_coll->opt_coll.uca_num[0]) * comp_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_uca_num_ref, "%s_%s", "coll_uca_num",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_uca_num", cur_coll, comp_coll, is_verbose);
}
if (*(cur_coll->coll_ref.coll_uca_w_l13_ref) == '\0'
&& memcmp (cur_coll->opt_coll.uca_w_l13, comp_coll->opt_coll.uca_w_l13,
sizeof (UCA_L13_W) * cur_coll->opt_coll.uca_exp_num *
cur_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_uca_w_l13_ref, "%s_%s", "coll_uca_w_l13",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_uca_w_l13", cur_coll, comp_coll, is_verbose);
}
if (cur_coll->opt_coll.uca_opt.sett_strength >= TAILOR_QUATERNARY
&& comp_coll->opt_coll.uca_opt.sett_strength >= TAILOR_QUATERNARY
&& *(cur_coll->coll_ref.coll_uca_w_l4_ref) == '\0'
&& memcmp (cur_coll->opt_coll.uca_w_l4, comp_coll->opt_coll.uca_w_l4,
sizeof (UCA_L4_W) * cur_coll->opt_coll.uca_exp_num *
cur_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_uca_w_l4_ref, "%s_%s", "coll_uca_w_l4",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_uca_w_l4", cur_coll, comp_coll, is_verbose);
}
}
} /* endif equal sett_expansions */
if (*(cur_coll->coll_ref.coll_next_cp_ref) == '\0'
&& memcmp (cur_coll->opt_coll.next_cp, comp_coll->opt_coll.next_cp,
sizeof (comp_coll->opt_coll.next_cp[0]) * comp_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_next_cp_ref, "%s_%s", "coll_next_cp",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_next_cp", cur_coll, comp_coll, is_verbose);
}
/* compare contraction data */
if (cur_coll->opt_coll.count_contr > 0
&& cur_coll->opt_coll.count_contr == comp_coll->opt_coll.count_contr)
{
if (cur_coll->opt_coll.contr_min_size == comp_coll->opt_coll.contr_min_size
&& *(cur_coll->coll_ref.coll_contr_list_ref) == '\0'
&& memcmp (cur_coll->opt_coll.contr_list, comp_coll->opt_coll.contr_list,
sizeof (COLL_CONTRACTION) * comp_coll->opt_coll.count_contr) == 0)
{
sprintf (cur_coll->coll_ref.coll_contr_list_ref, "%s_%s", "coll_contr_list",
comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_contr_list", cur_coll, comp_coll, is_verbose);
}
if (cur_coll->opt_coll.cp_first_contr_offset == comp_coll->opt_coll.cp_first_contr_offset
&& cur_coll->opt_coll.cp_first_contr_count == comp_coll->opt_coll.cp_first_contr_count
&& *(cur_coll->coll_ref.coll_cp_first_contr_array_ref) == '\0'
&& memcmp (cur_coll->opt_coll.cp_first_contr_array, comp_coll->opt_coll.cp_first_contr_array,
sizeof (comp_coll->opt_coll.cp_first_contr_array[0]) *
comp_coll->opt_coll.w_count) == 0)
{
sprintf (cur_coll->coll_ref.coll_cp_first_contr_array_ref, "%s_%s",
"coll_cp_first_contr_array", comp_coll->opt_coll.coll_name);
PRINT_DUPLICATE_SYMBOL_NAME ("coll_cp_first_" "contr_array", cur_coll, comp_coll, is_verbose);
}
}
}
}
}
}
#undef PRINT_DUPLICATE_SYMBOL_NAME
}
/*
* locale_save_all_to_C_file - saves all locale data to C source file, for
* later use when compiling them into a locale shared
* library.
*
* return: error code
* ld(in): locale data
* start_index(in): starting index inside ld array for locales to export
* loc_count(in): number of locales stored in the ld array
* lf(in): locale file info
*/
int
locale_save_all_to_C_file (LOCALE_DATA ** ld, int start_index, int end_index, LOCALE_FILE * lf)
{
int er_status = NO_ERROR;
int i;
for (i = start_index; i < end_index; i++)
{
er_status = locale_save_to_C_file (lf[i], ld[i]);
if (er_status != NO_ERROR)
{
break;
}
}
return er_status;
}
/*
* save_contraction_to_C_file() - saves collation contraction data to C file
*
* return: zero if save is successful, non-zero otherwise
* fp(in): file descriptor
* c(in): contraction to save
* use_expansion(in):
* use_level_4(in):
*/
static int
save_contraction_to_C_file (FILE * fp, COLL_CONTRACTION * c, bool use_expansion, bool use_level_4)
{
assert (c != NULL);
assert (fp != NULL);
fprintf (fp, "\t{\n");
fprintf (fp, "\t\t%u, \n", c->next);
fprintf (fp, "\t\t%u, \n", c->wv);
if (use_expansion)
{
assert (c->uca_num > 0 || c->uca_num <= MAX_UCA_EXP_CE);
PRINT_UNNAMED_NUM_ARRAY_TO_C_FILE (fp, "%uu", "\t\t", c->uca_num, c->uca_w_l13);
fprintf (fp, ",\n");
if (use_level_4)
{
PRINT_UNNAMED_NUM_ARRAY_TO_C_FILE (fp, "%u", "\t\t", c->uca_num, c->uca_w_l4);
}
else
{
fprintf (fp, "\t\t{ 0 }");
}
}
else
{
fprintf (fp, "\t\t{ 0 },\n\t\t{ 0 }");
}
fprintf (fp, ",\n\t\t");
PRINT_STRING_TO_C_FILE (fp, c->c_buf, strlen (c->c_buf));
fprintf (fp, ", \n");
fprintf (fp, "\t\t%u, \n", c->cp_count);
fprintf (fp, "\t\t%u, \n", c->size);
fprintf (fp, "\t\t%u \n", c->uca_num);
fprintf (fp, "} \n");
return 0;
}
/*
* locale_prepare_C_file() - saves locale data to C source file, for
* later use when generating the locale shared
* library.
*
* return: error code
* lf(in): locale file info
* ld(in): locale data
* c_file_path(in): the path to where to write the C file
*/
int
locale_prepare_C_file (void)
{
FILE *fp;
char c_file_path[PATH_MAX];
char err_msg[ERR_MSG_SIZE];
envvar_loclib_dir_file (c_file_path, sizeof (c_file_path), "locale.c");
fp = fopen_ex (c_file_path, "w");
if (fp == NULL)
{
goto error;
}
fprintf (fp, "/* GENERATED FILE - DO NOT EDIT */\n");
#if defined(WINDOWS)
fprintf (fp, "#include <stdio.h>\n");
#else
fprintf (fp, "#include <stddef.h>\n");
#endif
fprintf (fp, "#include \"locale_lib_common.h\"\n\n");
fclose (fp);
return 0;
error:
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Error opening file %s for rewrite.", c_file_path);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return ER_GENERIC_ERROR;
}
/*
* locale_save_to_C_file() - saves locale data to C source file, for
* later use when generating the locale shared
* library.
*
* return: error code
* lf(in): locale file info
* ld(in): locale data
*/
static int
locale_save_to_C_file (LOCALE_FILE lf, LOCALE_DATA * ld)
{
FILE *fp;
char c_file_path[PATH_MAX];
char err_msg[ERR_MSG_SIZE];
int i;
assert (ld != NULL);
envvar_loclib_dir_file (c_file_path, sizeof (c_file_path), "locale.c");
fp = fopen_ex (c_file_path, "a");
if (fp == NULL)
{
goto error;
}
fprintf (fp, "/*\n * %s - generated from %s \n *\n */\n", ld->locale_name, lf.ldml_file);
PRINT_STRING_VAR_TO_C_FILE (fp, "locale_name", ld->locale_name, ld->locale_name);
locale_save_calendar_to_C_file (fp, ld);
PRINT_VAR_TO_C_FILE (fp, "char", "number_decimal_sym", ld->number_decimal_sym, "'%c'", ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "char", "number_group_sym", ld->number_group_sym, "'%c'", ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "int", "default_currency_code", ld->default_currency_code, "%d", ld->locale_name);
locale_save_alphabets_to_C_file (fp, ld);
/* number of collation associated with this locale */
PRINT_VAR_TO_C_FILE (fp, "int", "count_coll", ld->coll_cnt, "%d", ld->locale_name);
for (i = 0; i < ld->coll_cnt; i++)
{
char coll_suffix[ERR_MSG_SIZE];
/* Collation names are user defined: first save fixed name variables containing collations name included in the
* LDML: collation_1_es_ES = "utf8_es_ES"; collation_2_es_ES = "utf8_es_ES_ci"; */
snprintf (coll_suffix, sizeof (coll_suffix) - 1, "%d_%s", i, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "collation", ld->collations[i].opt_coll.coll_name, coll_suffix);
if (ld->collations[i].do_not_save)
{
continue;
}
/* the collation data is decorated with the user defined name of the collation : coll_weights_utf8_es_ES = { ..
* }; coll_weights_utf8_es_ES_ci = { .. }; */
locale_save_collation_data_to_C_file (fp, &(ld->collations[i]));
}
locale_save_console_conv_to_C_file (fp, ld);
locale_save_normalization_to_C_file (fp, ld);
PRINT_STRING_VAR_TO_C_FILE (fp, "locale_checksum", ld->checksum, ld->locale_name);
fclose (fp);
return 0;
error:
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Error opening file %s for append.", c_file_path);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return ER_GENERIC_ERROR;
}
/*
* locale_save_calendar_to_C_file() - saves calendar data to C source file,
* as variables, for later use when generating the
* locale shared library.
*
* return: error code
* fp(in): file pointer where to write the data
* ld(in): locale data
*/
static int
locale_save_calendar_to_C_file (FILE * fp, LOCALE_DATA * ld)
{
assert (ld != NULL);
assert (fp != NULL);
/* calendar format strings */
PRINT_STRING_VAR_TO_C_FILE (fp, "date_format", ld->dateFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "time_format", ld->timeFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "datetime_format", ld->datetimeFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "timestamp_format", ld->timestampFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "timetz_format", ld->timetzFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "datetimetz_format", ld->datetimetzFormat, ld->locale_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "timestamptz_format", ld->timestamptzFormat, ld->locale_name);
/* calendar data arrays */
PRINT_STRING_ARRAY_TO_C_FILE (fp, "month_names_abbreviated", CAL_MONTH_COUNT, ld->month_names_abbreviated,
ld->locale_name);
PRINT_STRING_ARRAY_TO_C_FILE (fp, "month_names_wide", CAL_MONTH_COUNT, ld->month_names_wide, ld->locale_name);
PRINT_STRING_ARRAY_TO_C_FILE (fp, "day_names_abbreviated", CAL_DAY_COUNT, ld->day_names_abbreviated, ld->locale_name);
PRINT_STRING_ARRAY_TO_C_FILE (fp, "day_names_wide", CAL_DAY_COUNT, ld->day_names_wide, ld->locale_name);
PRINT_STRING_ARRAY_TO_C_FILE (fp, "am_pm", CAL_AM_PM_COUNT, ld->am_pm, ld->locale_name);
/* calendar parse order arrays */
PRINT_NUM_ARRAY_TO_C_FILE (fp, "day_names_abbr_parse_order", "char", "%u", CAL_DAY_COUNT,
ld->day_names_abbr_parse_order, ld->locale_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "day_names_wide_parse_order", "char", "%u", CAL_DAY_COUNT,
ld->day_names_wide_parse_order, ld->locale_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "month_names_abbr_parse_order", "char", "%u", CAL_MONTH_COUNT,
ld->month_names_abbr_parse_order, ld->locale_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "month_names_wide_parse_order", "char", "%u", CAL_MONTH_COUNT,
ld->month_names_wide_parse_order, ld->locale_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "am_pm_parse_order", "char", "%u", CAL_AM_PM_COUNT, ld->am_pm_parse_order,
ld->locale_name);
return 0;
}
/*
* locale_save_alphabets_to_C_file() - saves alphabet and identifier alphabet
* to C source file as variables, for later use
* when generating the locale shared library.
*
* return: error code
* fp(in): file pointer where to write the data
* a(in): alphabet data
* save_w_identier_name(in): true if alphabet is to be saved as "identifier"
* name
* alpha_suffix(in): suffix to be applied to variables names
*/
static int
locale_save_one_alphabet_to_C_file (FILE * fp, ALPHABET_DATA * a, bool save_w_identier_name, const char *alpha_suffix)
{
assert (a != NULL);
assert (fp != NULL);
if (save_w_identier_name)
{
PRINT_VAR_TO_C_FILE (fp, "int", "ident_alphabet_l_count", a->l_count, "%d", alpha_suffix);
PRINT_VAR_TO_C_FILE (fp, "int", "ident_alphabet_lower_multiplier", a->lower_multiplier, "%d", alpha_suffix);
PRINT_VAR_TO_C_FILE (fp, "int", "ident_alphabet_upper_multiplier", a->upper_multiplier, "%d", alpha_suffix);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "ident_alphabet_lower_cp", "unsigned int", "%u", a->l_count * a->lower_multiplier,
a->lower_cp, alpha_suffix);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "ident_alphabet_upper_cp", "unsigned int", "%u", a->l_count * a->upper_multiplier,
a->upper_cp, alpha_suffix);
}
else
{
PRINT_VAR_TO_C_FILE (fp, "int", "alphabet_l_count", a->l_count, "%d", alpha_suffix);
PRINT_VAR_TO_C_FILE (fp, "int", "alphabet_lower_multiplier", a->lower_multiplier, "%d", alpha_suffix);
PRINT_VAR_TO_C_FILE (fp, "int", "alphabet_upper_multiplier", a->upper_multiplier, "%d", alpha_suffix);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "alphabet_lower_cp", "unsigned int", "%u", a->l_count * a->lower_multiplier,
a->lower_cp, alpha_suffix);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "alphabet_upper_cp", "unsigned int", "%u", a->l_count * a->upper_multiplier,
a->upper_cp, alpha_suffix);
}
return 0;
}
/*
* locale_save_alphabets_to_C_file() - saves alphabet and identifier alphabet
* to C source file as variables, for later use
* when generating the locale shared library.
*
* return: error code
* fp(in): file pointer where to write the data
* ld(in): locale data
*/
static int
locale_save_alphabets_to_C_file (FILE * fp, LOCALE_DATA * ld)
{
assert (ld != NULL);
assert (fp != NULL);
/* alphabet data */
PRINT_VAR_TO_C_FILE (fp, "int", "alphabet_a_type", ld->alphabet.a_type, "%d", ld->locale_name);
if (!(ld->alphabet.do_not_save))
{
const char *alpha_suffix;
if (ld->alphabet.a_type == ALPHABET_UNICODE)
{
alpha_suffix = "unicode";
}
else if (ld->alphabet.a_type == ALPHABET_ASCII)
{
alpha_suffix = "ascii";
}
else
{
alpha_suffix = (const char *) (ld->locale_name);
}
(void) locale_save_one_alphabet_to_C_file (fp, &(ld->alphabet), false, alpha_suffix);
}
/* identifier alphabet data */
PRINT_VAR_TO_C_FILE (fp, "int", "ident_alphabet_a_type", ld->identif_alphabet.a_type, "%d", ld->locale_name);
if (!(ld->identif_alphabet.do_not_save))
{
const char *alpha_suffix;
bool save_w_identif = false;
if (ld->identif_alphabet.a_type == ALPHABET_UNICODE)
{
alpha_suffix = "unicode";
}
else if (ld->identif_alphabet.a_type == ALPHABET_ASCII)
{
alpha_suffix = "ascii";
}
else
{
alpha_suffix = (const char *) (ld->locale_name);
save_w_identif = true;
}
(void) locale_save_one_alphabet_to_C_file (fp, &(ld->identif_alphabet), save_w_identif, alpha_suffix);
}
return 0;
}
/*
* locale_save_collation_data_to_C_file() - saves collation data to C source
* file as variables, for later use when generating
* the locale shared library.
*
* return: error code
* fp(in): file pointer where to write the data
* cd(in): collation data
*/
static int
locale_save_collation_data_to_C_file (FILE * fp, LOCALE_COLLATION * lc)
{
int i;
COLL_DATA *cd = NULL;
assert (lc != NULL);
assert (fp != NULL);
cd = &(lc->opt_coll);
/* collation constants */
PRINT_VAR_TO_C_FILE (fp, "int", "coll_id", cd->coll_id, "%d", cd->coll_name);
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_name", cd->coll_name, cd->coll_name);
/* OPT_COLL.UCA_OPT members */
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_strength", cd->uca_opt.sett_strength, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_backwards", cd->uca_opt.sett_backwards ? 1 : 0, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_caseLevel", cd->uca_opt.sett_caseLevel ? 1 : 0, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_caseFirst", cd->uca_opt.sett_caseFirst, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_expansions", cd->uca_opt.sett_expansions ? 1 : 0, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_sett_contr_policy", cd->uca_opt.sett_contr_policy, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_match_contr", cd->uca_opt.sett_match_contr, "%d", cd->coll_name);
/* other OPT_COLL members */
PRINT_VAR_TO_C_FILE (fp, "int", "coll_w_count", cd->w_count, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_uca_exp_num", cd->uca_exp_num, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "int", "coll_count_contr", cd->count_contr, "%d", cd->coll_name);
/* OPT_COLL pointer and array members */
if (cd->w_count > 0)
{
if (!(cd->uca_opt.sett_expansions))
{
if (*(lc->coll_ref.coll_weights_ref) == '\0')
{
sprintf (lc->coll_ref.coll_weights_ref, "coll_weights_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_weights", "unsigned int", "%u", cd->w_count, cd->weights,
cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_weights_ref", lc->coll_ref.coll_weights_ref, cd->coll_name);
}
else
{
assert (cd->uca_exp_num > 1);
if (*(lc->coll_ref.coll_uca_w_l13_ref) == '\0')
{
sprintf (lc->coll_ref.coll_uca_w_l13_ref, "coll_uca_w_l13_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_uca_w_l13", "unsigned int", "%u", cd->uca_exp_num * cd->w_count,
cd->uca_w_l13, cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_uca_w_l13_ref", lc->coll_ref.coll_uca_w_l13_ref, cd->coll_name);
if (cd->uca_opt.sett_strength >= TAILOR_QUATERNARY)
{
if (*(lc->coll_ref.coll_uca_w_l4_ref) == '\0')
{
sprintf (lc->coll_ref.coll_uca_w_l4_ref, "coll_uca_w_l4_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_uca_w_l4", "unsigned short", "%u", cd->uca_exp_num * cd->w_count,
cd->uca_w_l4, cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_uca_w_l4_ref", lc->coll_ref.coll_uca_w_l4_ref, cd->coll_name);
}
if (*(lc->coll_ref.coll_uca_num_ref) == '\0')
{
sprintf (lc->coll_ref.coll_uca_num_ref, "coll_uca_num_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_uca_num", "char", "%d", cd->w_count, cd->uca_num, cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_uca_num_ref", lc->coll_ref.coll_uca_num_ref, cd->coll_name);
}
if (*(lc->coll_ref.coll_next_cp_ref) == '\0')
{
sprintf (lc->coll_ref.coll_next_cp_ref, "coll_next_cp_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_next_cp", "unsigned int", "%u", cd->w_count, cd->next_cp, cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_next_cp_ref", lc->coll_ref.coll_next_cp_ref, cd->coll_name);
}
if (cd->count_contr > 0)
{
PRINT_VAR_TO_C_FILE (fp, "int", "coll_contr_min_size", cd->contr_min_size, "%d", cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "coll_cp_first_contr_offset", cd->cp_first_contr_offset, "%u",
cd->coll_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "coll_cp_first_contr_count", cd->cp_first_contr_count, "%u",
cd->coll_name);
if (*(lc->coll_ref.coll_contr_list_ref) == '\0')
{
sprintf (lc->coll_ref.coll_contr_list_ref, "coll_contr_list_%s", cd->coll_name);
fprintf (fp, "" DLL_EXPORT_PREFIX "const COLL_CONTRACTION coll_contr_list_%s[] = {", cd->coll_name);
for (i = 0; i < cd->count_contr; i++)
{
fprintf (fp, "\n");
save_contraction_to_C_file (fp, &(cd->contr_list[i]), cd->uca_opt.sett_expansions,
(cd->uca_opt.sett_strength >= TAILOR_QUATERNARY));
if (i < cd->count_contr - 1)
{
fprintf (fp, ", ");
}
}
fprintf (fp, "};\n");
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_contr_list_ref", lc->coll_ref.coll_contr_list_ref, cd->coll_name);
if (*(lc->coll_ref.coll_cp_first_contr_array_ref) == '\0')
{
sprintf (lc->coll_ref.coll_cp_first_contr_array_ref, "coll_cp_first_contr_array_%s", cd->coll_name);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "coll_cp_first_contr_array", "int", "%d", (int) cd->cp_first_contr_count,
cd->cp_first_contr_array, cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_cp_first_contr_array_ref", lc->coll_ref.coll_cp_first_contr_array_ref,
cd->coll_name);
}
PRINT_STRING_VAR_TO_C_FILE (fp, "coll_checksum", cd->checksum, cd->coll_name);
return 0;
}
/*
* locale_save_console_conv_to_C_file() - saves console conversion data to
* binary file
*
* return: zero if save is successful, non-zero otherwise
* fp(in): file descriptor
* tc(in): console conversion info
*/
static int
locale_save_console_conv_to_C_file (FILE * fp, LOCALE_DATA * ld)
{
int i;
TEXT_CONVERSION *tc;
assert (ld != NULL);
assert (fp != NULL);
tc = &(ld->txt_conv);
/* TEXT_CONVERSION non-array members */
PRINT_VAR_TO_C_FILE (fp, "int", "tc_conv_type", tc->conv_type, "%d", ld->locale_name);
if (tc->conv_type != TEXT_CONV_GENERIC_1BYTE && tc->conv_type != TEXT_CONV_GENERIC_2BYTE)
{
return 0;
}
PRINT_NUM_ARRAY_TO_C_FILE (fp, "tc_is_lead_byte", "unsigned char", "%u", 256, tc->byte_flag, ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "tc_utf8_first_cp", tc->utf8_first_cp, "%u", ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "tc_utf8_last_cp", tc->utf8_last_cp, "%u", ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "tc_text_first_cp", tc->text_first_cp, "%u", ld->locale_name);
PRINT_VAR_TO_C_FILE (fp, "unsigned int", "tc_text_last_cp", tc->text_last_cp, "%u", ld->locale_name);
assert (tc->win_codepages != NULL);
PRINT_STRING_VAR_TO_C_FILE (fp, "tc_win_codepages", tc->win_codepages, ld->locale_name);
assert (tc->nl_lang_str != NULL);
PRINT_STRING_VAR_TO_C_FILE (fp, "tc_nl_lang_str", tc->nl_lang_str, ld->locale_name);
assert (tc->utf8_last_cp > tc->utf8_first_cp);
assert (tc->utf8_to_text != NULL);
fprintf (fp, "" DLL_EXPORT_PREFIX "const CONV_CP_TO_BYTES tc_utf8_to_text_%s[] = { \n", ld->locale_name);
for (i = 0; i < (int) (tc->utf8_last_cp - tc->utf8_first_cp + 1); i++)
{
fprintf (fp, "{ %u, ", tc->utf8_to_text[i].size);
PRINT_STRING_TO_C_FILE (fp, tc->utf8_to_text[i].bytes, tc->utf8_to_text[i].size);
fprintf (fp, "},\n");
}
fprintf (fp, "};\n");
assert (tc->text_last_cp > tc->text_first_cp);
assert (tc->text_to_utf8 != NULL);
fprintf (fp, "" DLL_EXPORT_PREFIX "const CONV_CP_TO_BYTES tc_text_to_utf8_%s[] = { \n", ld->locale_name);
for (i = 0; i < (int) (tc->text_last_cp - tc->text_first_cp + 1); i++)
{
fprintf (fp, "{ %u, ", tc->text_to_utf8[i].size);
PRINT_STRING_TO_C_FILE (fp, tc->text_to_utf8[i].bytes, tc->text_to_utf8[i].size);
fprintf (fp, "},\n");
}
fprintf (fp, "};\n");
return 0;
}
/*
* dump_locale_alphabet - dump the selected ALPHABET_DATA structure
* in human-readable text format.
* Returns : NO_ERROR.
* ad(in) : the ALPHABET_DATA to be dumped in text format.
* dl_settings(in): the commmand line options encoded intoa binary masked int.
* lower_bound(in): the starting codepoint for the range of items which
* -w or -c will dump.
* upper_bound(in) : the ending codepoint for the range of items which
* -w or -c will dump.
*/
static int
dump_locale_alphabet (ALPHABET_DATA * ad, int dl_settings, int lower_bound, int upper_bound)
{
#define DUMP_CP_BUF_SIZE 128
int i, cp;
unsigned char utf8_buf[INTL_UTF8_MAX_CHAR_SIZE + 1];
unsigned int *case_buf;
char out_case[DUMP_CP_BUF_SIZE];
char out_cp[DUMP_CP_BUF_SIZE];
assert (ad != NULL);
assert (lower_bound <= upper_bound);
printf ("Alphabet type: ");
if (ad->a_type == ALPHABET_UNICODE)
{
printf ("Unicode\n");
}
else if (ad->a_type == ALPHABET_ASCII)
{
printf ("ASCII\n");
}
else
{
assert (ad->a_type == ALPHABET_TAILORED);
printf ("Tailored\n");
}
printf ("Letter count: %d\n", ad->l_count);
if (ad->l_count > 0)
{
printf ("Lower multiplier: %d\n", ad->lower_multiplier);
printf ("Upper multiplier: %d\n", ad->upper_multiplier);
}
for (cp = lower_bound; cp < upper_bound; cp++)
{
memset (utf8_buf, 0, INTL_UTF8_MAX_CHAR_SIZE + 1);
intl_cp_to_utf8 (cp, utf8_buf);
printf ("CP: Ux%04X | %-4s", cp, (cp > 0x0020 ? utf8_buf : (unsigned char *) ""));
if ((dl_settings & DUMPLOCALE_IS_ALPHABET_LOWER) != 0)
{
bool print_case = true;
memset (out_cp, 0, sizeof (out_cp));
memset (out_case, 0, sizeof (out_case));
case_buf = &(ad->lower_cp[cp * ad->lower_multiplier]);
for (i = 0; i < ad->lower_multiplier; i++)
{
char temp_cp[8];
if (case_buf[i] == 0)
{
break;
}
if (case_buf[i] < 0x20)
{
print_case = false;
}
memset (utf8_buf, 0, sizeof (utf8_buf));
intl_cp_to_utf8 (case_buf[i], utf8_buf);
strcat (out_case, (char *) utf8_buf);
snprintf (temp_cp, sizeof (temp_cp) - 1, "Ux%04X", case_buf[i]);
strcat (out_cp, temp_cp);
}
printf (" | Lower : CP(s): %-12s, lower char(s): %-12s", out_cp, (print_case ? out_case : ""));
}
if ((dl_settings & DUMPLOCALE_IS_ALPHABET_UPPER) != 0)
{
bool print_case = true;
memset (out_cp, 0, sizeof (out_cp));
memset (out_case, 0, sizeof (out_case));
case_buf = &(ad->upper_cp[cp * ad->upper_multiplier]);
for (i = 0; i < ad->upper_multiplier; i++)
{
char temp_cp[8];
if (case_buf[i] == 0)
{
break;
}
if (case_buf[i] < 0x20)
{
print_case = false;
}
memset (utf8_buf, 0, sizeof (utf8_buf));
intl_cp_to_utf8 (case_buf[i], utf8_buf);
strcat (out_case, (char *) utf8_buf);
snprintf (temp_cp, sizeof (temp_cp) - 1, "Ux%04X", case_buf[i]);
strcat (out_cp, temp_cp);
}
printf (" | Upper : CP(s): %-12s, upper char(s): %-12s", out_cp, (print_case ? out_case : ""));
}
printf ("\n");
}
return NO_ERROR;
}
/*
* dump_locale_collation - dump the selected COLL_DATA structure
* in human-readable text format.
* Returns : NO_ERROR.
* coll(in) : the COLL_DATA to be dumped in text format.
* dl_settings(in): the commmand line options encoded intoa binary masked int.
* lower_bound(in): the starting codepoint for the range of items which
* -w or -c will dump.
* upper_bound(in) : the ending codepoint for the range of items which
* -w or -c will dump.
*/
static int
dump_locale_collation (COLL_DATA * coll, int dl_settings, int start_value, int end_value)
{
unsigned int *coll_key_list = NULL;
int coll_key_list_cnt = 0;
int lower_bound = 0;
int upper_bound = 0;
int err_status = NO_ERROR;
int cp, i;
assert (coll != NULL);
lower_bound = 0;
upper_bound = coll->w_count;
if (start_value > lower_bound)
{
lower_bound = start_value;
}
if (end_value > 0 && end_value < upper_bound)
{
/* if an upper bound is specified, use the "+1" to make sure that the upper bound codepoint is included in the
* dump file. */
upper_bound = end_value + 1;
}
printf ("\n");
printf ("* Collation: %s | id: %d | checksum: %s *\n", coll->coll_name, coll->coll_id, coll->checksum);
printf ("Max codepoints: %d\n", coll->w_count);
printf ("Level: %d\n", coll->uca_opt.sett_strength);
printf ("Expansions: %s\n", coll->uca_opt.sett_expansions ? "yes" : "no");
if (coll->uca_opt.sett_expansions)
{
printf ("Expansion CE num: %d\n", coll->uca_exp_num);
}
printf ("Contractions: %d\n", coll->count_contr);
if (coll->count_contr > 0)
{
printf ("Contraction min size: %d\n", coll->contr_min_size);
}
assert (coll->w_count > 0);
if (upper_bound < lower_bound)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR (msgcat_message
(MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_DUMPLOCALE, DUMPLOCALE_MSG_INVALID_CP_RANGE), ER_LOC_GEN,
true);
goto exit;
}
/* Dump collation information, cp and next_cp info, ordered by cp. */
if ((dl_settings & DUMPLOCALE_IS_COLLATION_CP_ORDER) != 0)
{
printf ("\n");
printf ("* Codepoint collation info (codepoint order) *\n");
for (cp = lower_bound; cp < upper_bound; cp++)
{
unsigned int next_id;
assert (cp >= 0 && cp < coll->w_count);
dump_collation_codepoint (coll, cp, true, true);
next_id = coll->next_cp[cp];
printf (" | Next : ");
dump_collation_key (coll, next_id, true, true);
printf ("\n");
}
}
if (coll->count_contr > 0 && (dl_settings & DUMPLOCALE_IS_COLLATION_CP_ORDER) != 0)
{
printf ("\n");
printf ("* Contraction collation info (contraction order) *\n");
for (i = 0; i < coll->count_contr; i++)
{
COLL_CONTRACTION *contr = &(coll->contr_list[i]);
dump_collation_contr (coll, contr, true, true);
printf (" | Next :");
dump_collation_key (coll, contr->next, true, true);
printf ("\n");
}
}
/* Dump weight list and corresponding codepoints, ordered by weight. */
if ((dl_settings & DUMPLOCALE_IS_COLLATION_WEIGHT_ORDER) != 0)
{
int keys_same_weight = 1;
int cp_count = upper_bound - lower_bound;
bool use_expansions;
printf ("\n");
printf ("* Collation info (weight order) *\n");
coll_key_list_cnt = cp_count + coll->count_contr;
coll_key_list = (unsigned int *) malloc (coll_key_list_cnt * sizeof (unsigned int));
if (coll_key_list == NULL)
{
err_status = ER_LOC_INIT;
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_INIT, true);
goto exit;
}
for (cp = lower_bound; cp < upper_bound; cp++)
{
coll_key_list[cp - lower_bound] = cp;
}
for (i = 0; i < coll->count_contr; i++)
{
coll_key_list[i + cp_count] = i | INTL_MASK_CONTR;
}
/* Order by weight. */
use_expansions = coll->uca_opt.sett_expansions;
dump_coll_data = coll;
if (use_expansions)
{
qsort (coll_key_list, coll_key_list_cnt, sizeof (unsigned int), comp_func_coll_uca_exp_fo);
}
else
{
qsort (coll_key_list, coll_key_list_cnt, sizeof (unsigned int), comp_func_coll_uca_simple_weights_fo);
}
/* Dump ordered (weight, key id) tuples. */
for (i = 0; i < coll_key_list_cnt; i++)
{
bool same_weights = false;
if (i > 0)
{
if (use_expansions)
{
same_weights =
(comp_func_coll_uca_exp (&(coll_key_list[i]), &(coll_key_list[i - 1])) == 0) ? true : false;
}
else
{
same_weights =
(comp_func_coll_uca_simple_weights (&(coll_key_list[i]), &(coll_key_list[i - 1])) ==
0) ? true : false;
}
}
if (i > 0 && !same_weights)
{
if (keys_same_weight > 1)
{
printf (" Keys same weight : %d\n", keys_same_weight);
}
else
{
printf ("\n");
}
dump_collation_key (coll, coll_key_list[i], true, false);
keys_same_weight = 1;
}
else
{
printf ("\n");
dump_collation_key (coll, coll_key_list[i], true, false);
keys_same_weight++;
}
printf (" | ");
dump_collation_key (coll, coll_key_list[i], false, true);
}
}
exit:
if (coll_key_list != NULL)
{
free (coll_key_list);
}
return err_status;
}
/*
* locale_dump - output the selected information on locale data in
* human-readable text format.
* Returns : error status.
* data(in): the locale data to be dumped in text format.
* lf(in) : the LOCALE_FILE i.e. binary file from which ld was imported.
* dl_settings(in): the commmand line options encoded intoa binary masked int.
* start_value(in): the starting codepoint for the range of items which
* -w or -c will dump.
* end_value(in) : the ending codepoint for the range of items which
* -w or -c will dump.
*/
int
locale_dump (void *data, LOCALE_FILE * lf, int dl_settings, int start_value, int end_value)
{
int i;
int lower_bound = 0;
int upper_bound = 0;
int alphabet_settings;
int err_status = NO_ERROR;
LANG_LOCALE_DATA *lld = NULL;
assert (data != NULL);
assert (lf != NULL);
assert (start_value <= end_value);
lld = (LANG_LOCALE_DATA *) data;
printf ("*************************************************\n");
printf ("Locale data for: %s\nLibrary file: %s\n", lf->locale_name, lf->lib_file);
printf ("Locale string: %s\n", lld->lang_name);
printf ("Locale checksum: %s\n", lld->checksum);
if ((dl_settings & DUMPLOCALE_IS_CALENDAR) != 0)
{
printf ("\n * Calendar *\n");
printf ("Date format: %s\n", lld->date_format);
printf ("Time format: %s\n", lld->time_format);
printf ("Datetime format: %s\n", lld->datetime_format);
printf ("Timestamp format: %s\n", lld->timestamp_format);
printf ("Datetime_tz format: %s\n", lld->datetimetz_format);
printf ("Timestamp_tz format: %s\n", lld->timestamptz_format);
printf ("\nAbbreviated month names:\n");
for (i = 0; i < CAL_MONTH_COUNT; i++)
{
printf ("%d. %s\n", (i + 1), lld->month_short_name[i]);
}
printf ("\nAbbreviated month names, sorted for tokenizer:\n");
for (i = 0; i < CAL_MONTH_COUNT; i++)
{
printf ("%d. %s = month %d\n", (i + 1), lld->month_short_name[(int) (lld->month_short_parse_order[i])],
(int) (lld->month_short_parse_order[i]) + 1);
}
printf ("\nWide month names:\n");
for (i = 0; i < CAL_MONTH_COUNT; i++)
{
printf ("%d. %s\n", (i + 1), lld->month_name[i]);
}
printf ("\nWide month names, sorted for tokenizer:\n");
for (i = 0; i < CAL_MONTH_COUNT; i++)
{
printf ("%d. %s = month %d\n", (i + 1), lld->month_name[(int) (lld->month_parse_order[i])],
(int) (lld->month_parse_order[i]) + 1);
}
printf ("\nAbbreviated weekday names:\n");
for (i = 0; i < CAL_DAY_COUNT; i++)
{
printf ("%d. %s\n", (i + 1), lld->day_short_name[i]);
}
printf ("\nAbbreviated weekday names, sorted for parse order:\n");
for (i = 0; i < CAL_DAY_COUNT; i++)
{
printf ("%d. %s = weekday %d\n", (i + 1), lld->day_short_name[(int) (lld->day_short_parse_order[i])],
(int) (lld->day_short_parse_order[i]) + 1);
}
printf ("\nWide weekday names:\n");
for (i = 0; i < CAL_DAY_COUNT; i++)
{
printf ("%d. %s\n", (i + 1), lld->day_name[i]);
}
printf ("\nWide weekday names, sorted for tokenizer:\n");
for (i = 0; i < CAL_DAY_COUNT; i++)
{
printf ("%d. %s = weekday %d\n", (i + 1), lld->day_name[(int) (lld->day_parse_order[i])],
(int) (lld->day_parse_order[i]) + 1);
}
printf ("\nDay periods:\n");
for (i = 0; i < CAL_AM_PM_COUNT; i++)
{
printf ("%d. %s\n", (i + 1), lld->am_pm[i]);
}
printf ("\nDay periods, sorted for tokenizer:\n");
for (i = 0; i < CAL_AM_PM_COUNT; i++)
{
printf ("%d. %s = day period %d\n", (i + 1), lld->am_pm[(int) (lld->am_pm_parse_order[i])],
(int) (lld->am_pm_parse_order[i]) + 1);
}
}
/* Display numbering information. */
if ((dl_settings & DUMPLOCALE_IS_NUMBERING) != 0)
{
printf ("\n * Numbers *\n");
printf ("Decimal separator: <%c>\n", lld->number_decimal_sym);
printf ("Separator for digit grouping: <%c>\n", lld->number_group_sym);
printf ("Default currency ISO code: %s\n", intl_get_money_ISO_symbol (lld->default_currency_code));
}
if ((dl_settings & DUMPLOCALE_IS_ALPHABET) != 0)
{
lower_bound = 0;
upper_bound = lld->alphabet.l_count;
if (start_value > lower_bound)
{
lower_bound = start_value;
}
if (end_value > 0 && end_value < upper_bound)
{
/* if an upper bound is specified, use the "+1" to make sure that the upper bound codepoint is included in
* the dump file. */
upper_bound = end_value + 1;
}
}
if (upper_bound < lower_bound)
{
err_status = ER_LOC_GEN;
LOG_LOCALE_ERROR (msgcat_message
(MSGCAT_CATALOG_UTILS, MSGCAT_UTIL_SET_DUMPLOCALE, DUMPLOCALE_MSG_INVALID_CP_RANGE), ER_LOC_GEN,
true);
goto exit;
}
/* Dump alphabet data. */
if ((dl_settings & DUMPLOCALE_IS_ALPHABET) != 0)
{
alphabet_settings = 0;
alphabet_settings |= (dl_settings & DUMPLOCALE_IS_ALPHABET_LOWER);
alphabet_settings |= (dl_settings & DUMPLOCALE_IS_ALPHABET_UPPER);
printf ("\n * Alphabet data *\n");
dump_locale_alphabet (&(lld->alphabet), alphabet_settings, lower_bound, upper_bound);
}
/* Dump identifier alphabet data. */
if ((dl_settings & DUMPLOCALE_IS_IDENTIFIER_ALPHABET) != 0)
{
alphabet_settings = 0;
if ((dl_settings & DUMPLOCALE_IS_IDENTIFIER_ALPHABET_LOWER) != 0)
{
alphabet_settings |= DUMPLOCALE_IS_ALPHABET_LOWER;
}
if ((dl_settings & DUMPLOCALE_IS_IDENTIFIER_ALPHABET_UPPER) != 0)
{
alphabet_settings |= DUMPLOCALE_IS_ALPHABET_UPPER;
}
printf ("\n");
printf ("* Identifier alphabet data *\n");
dump_locale_alphabet (&(lld->ident_alphabet), alphabet_settings, lower_bound, upper_bound);
}
/* Dump normalization data. */
if ((dl_settings & DUMPLOCALE_IS_NORMALIZATION) != 0)
{
printf ("\n");
printf ("* Normalization data *\n");
dump_locale_normalization (&(lld->unicode_norm));
}
/* Dump normalization data. */
if ((dl_settings & DUMPLOCALE_IS_TEXT_CONV) != 0)
{
printf ("\n");
printf ("* Console conversion data *\n");
dump_console_conversion (lld->txt_conv);
}
exit:
return err_status;
}
/*
* locale_dump_lib_collations() - output the selected information on
* collations data in human-readable text
* format.
* return: error code
* lib_handle(in):
* lf(in): locale file info
* dl_settings(in):
* lower_bound(in):
* upper_bound(in):
*/
int
locale_dump_lib_collations (void *lib_handle, const LOCALE_FILE * lf, int dl_settings, int start_value, int end_value)
{
int err_status = NO_ERROR;
int i, count_coll_to_load;
COLL_DATA coll;
assert (lib_handle != NULL);
assert (lf != NULL);
assert (lf->locale_name != NULL);
/* collation data */
err_status = lang_load_count_coll_from_lib (&count_coll_to_load, lib_handle, lf);
if (err_status != NO_ERROR)
{
goto exit;
}
printf ("\n\n* Collations: %d collations found *\n", count_coll_to_load);
for (i = 0; i < count_coll_to_load; i++)
{
/* get name of collation */
char *coll_name = NULL;
memset (&coll, 0, sizeof (COLL_DATA));
err_status = lang_load_get_coll_name_from_lib (i, &coll_name, lib_handle, lf);
if (err_status != NO_ERROR)
{
goto exit;
}
assert (strlen (coll_name) < (int) sizeof (coll.coll_name));
strncpy (coll.coll_name, coll_name, sizeof (coll.coll_name) - 1);
err_status = lang_load_coll_from_lib (&coll, lib_handle, lf);
if (err_status != NO_ERROR)
{
goto exit;
}
err_status = dump_locale_collation (&coll, dl_settings, start_value, end_value);
if (err_status != NO_ERROR)
{
goto exit;
}
printf ("\n\n\n");
}
exit:
return err_status;
}
/*
* comp_func_coll_uca_simple_weights_fo - compare function for sorting
* collatable elements according to simple weights order
* but applies full order
*
* Note: This function uses 'comp_func_coll_uca_simple_weights' but applies
* a full order.
* The purpose is to provide a 'deterministic comparison' to eliminate
* unpredictable results of sort algorithm (qsort).
*/
static int
comp_func_coll_uca_simple_weights_fo (const void *arg1, const void *arg2)
{
unsigned int pos1;
unsigned int pos2;
int cmp;
pos1 = *((unsigned int *) arg1);
pos2 = *((unsigned int *) arg2);
cmp = comp_func_coll_uca_simple_weights (arg1, arg2);
return (cmp == 0) ? (int) (pos1 - pos2) : cmp;
}
/*
* comp_func_coll_uca_simple_weights - compare function for sorting collatable
* elements according to simple weights order
*
* Note: this function is used by dump_locale tool
* The elements in array are 32 bit unsigned integers, keys which
* may be Unicode points or contractions (when highest bit is set)
*
*/
static int
comp_func_coll_uca_simple_weights (const void *arg1, const void *arg2)
{
unsigned int pos1;
unsigned int pos2;
unsigned int wv1, wv2;
COLL_DATA *coll = dump_coll_data;
pos1 = *((unsigned int *) arg1);
pos2 = *((unsigned int *) arg2);
assert (coll != NULL);
if (INTL_IS_NEXT_CONTR (pos1))
{
wv1 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos1)].wv;
}
else
{
wv1 = coll->weights[pos1];
}
if (INTL_IS_NEXT_CONTR (pos2))
{
wv2 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos2)].wv;
}
else
{
wv2 = coll->weights[pos2];
}
return wv1 - wv2;
}
/*
* comp_func_coll_uca_exp_fo - compare function for sorting collatable
* elements according to UCA algorithm,
* with full order
*
* Note: This function uses 'comp_func_coll_uca_exp' but applies a full order
* The purpose is to provide a 'deterministic comparison' to eliminate
* unpredictable results of sort algorithm (qsort).
*/
static int
comp_func_coll_uca_exp_fo (const void *arg1, const void *arg2)
{
unsigned int pos1;
unsigned int pos2;
int cmp;
pos1 = *((unsigned int *) arg1);
pos2 = *((unsigned int *) arg2);
cmp = comp_func_coll_uca_exp (arg1, arg2);
return (cmp == 0) ? (int) (pos1 - pos2) : cmp;
}
/*
* comp_func_coll_uca_exp - compare function for sorting collatable elements
* according to UCA algorithm
*
* Note: this function is used by dump_locale tool
* The elements in array are 32 bit unsigned integers, keys which
* may be Unicode points or contractions (when highest bit is set)
*
*/
static int
comp_func_coll_uca_exp (const void *arg1, const void *arg2)
{
unsigned int pos1;
unsigned int pos2;
COLL_DATA *coll = dump_coll_data;
unsigned char utf8_buf_1[INTL_UTF8_MAX_CHAR_SIZE + 1];
unsigned char utf8_buf_2[INTL_UTF8_MAX_CHAR_SIZE + 1];
char *str1;
char *str2;
int size1, size2;
pos1 = *((unsigned int *) arg1);
pos2 = *((unsigned int *) arg2);
assert (coll != NULL);
/* build strings from the two keys and use the UCA collation function */
if (INTL_IS_NEXT_CONTR (pos1))
{
str1 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos1)].c_buf;
size1 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos1)].size;
}
else
{
size1 = intl_cp_to_utf8 (pos1, utf8_buf_1);
utf8_buf_1[size1] = '\0';
str1 = (char *) utf8_buf_1;
}
if (INTL_IS_NEXT_CONTR (pos2))
{
str2 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos2)].c_buf;
size2 = coll->contr_list[INTL_GET_NEXT_CONTR_ID (pos2)].size;
}
else
{
size2 = intl_cp_to_utf8 (pos2, utf8_buf_2);
utf8_buf_2[size2] = '\0';
str2 = (char *) utf8_buf_2;
}
return lang_strmatch_utf8_uca_w_coll_data (coll, false, (const unsigned char *) str1, size1,
(const unsigned char *) str2, size2, NULL, false, NULL, false);
}
/*
* dump_collation_key - prints information on collation key
* (codepoint or contraction)
* Returns :
* coll(in) : collation data
* key(in) : key to print
* print_weight(in): true if weight should be printed
* print_contr(in): true if contraction info should be printed
*/
static void
dump_collation_key (COLL_DATA * coll, const unsigned int key, bool print_weight, bool print_key)
{
if (INTL_IS_NEXT_CONTR (key))
{
unsigned int contr_id = INTL_GET_NEXT_CONTR_ID (key);
COLL_CONTRACTION *contr = &(coll->contr_list[contr_id]);
dump_collation_contr (coll, contr, print_weight, print_key);
}
else
{
dump_collation_codepoint (coll, key, print_weight, print_key);
}
}
/*
* dump_collation_contr - prints information on collation contraction
* Returns :
* coll(in) : collation data
* contr(in) : contraction
* print_weight(in): true if weight should be printed
* print_contr(in): true if contraction info should be printed
*/
static void
dump_collation_contr (COLL_DATA * coll, const COLL_CONTRACTION * contr, bool print_weight, bool print_contr)
{
int i;
assert (contr != NULL);
assert (contr->cp_count <= LOC_MAX_UCA_CHARS_SEQ);
if (print_contr)
{
unsigned int cp_list[LOC_MAX_UCA_CHARS_SEQ];
bool print_utf8 = true;
int cp_count;
intl_utf8_to_cp_list ((const unsigned char *) contr->c_buf, strlen (contr->c_buf), cp_list, sizeof (cp_list),
&cp_count);
assert (cp_count == contr->cp_count);
printf ("Contr: ");
for (i = 0; i < cp_count; i++)
{
printf ("Ux%04X ", cp_list[i]);
if (cp_list[i] < 0x20)
{
print_utf8 = false;
}
}
if (print_utf8)
{
printf (" | %s", contr->c_buf);
}
}
if (!print_weight)
{
return;
}
if (coll->uca_exp_num <= 1)
{
printf (" | Weight : %04x", contr->wv);
return;
}
assert (contr->uca_num > 0 && contr->uca_num <= MAX_UCA_EXP_CE);
printf (" | Weight : ");
for (i = 0; i < (int) contr->uca_num; i++)
{
printf ("[%04X.", UCA_GET_L1_W (contr->uca_w_l13[i]));
printf ("%04X.", UCA_GET_L2_W (contr->uca_w_l13[i]));
printf ("%04X.", UCA_GET_L3_W (contr->uca_w_l13[i]));
if (coll->uca_opt.sett_strength >= TAILOR_QUATERNARY)
{
printf ("%04X]", contr->uca_w_l4[i]);
}
else
{
printf ("]");
}
}
}
/*
* dump_collation_codepoint - prints information on collation codepoint
* Returns :
* coll(in) : collation data
* cp(in) : codepoint
* print_weight(in): true if weight should be printed
*/
static void
dump_collation_codepoint (COLL_DATA * coll, const unsigned int cp, bool print_weight, bool print_cp)
{
assert (cp <= INTL_MAX_UNICODE_CP_ALLOWED);
if (print_cp)
{
unsigned char utf8_buf[INTL_UTF8_MAX_CHAR_SIZE + 1];
memset (utf8_buf, 0, INTL_UTF8_MAX_CHAR_SIZE + 1);
intl_cp_to_utf8 (cp, utf8_buf);
printf ("CP: Ux%04X | %-4s", cp, ((cp > 0x20) ? utf8_buf : (unsigned char *) ""));
}
if (!print_weight)
{
return;
}
if (coll->uca_exp_num <= 1)
{
printf (" | Weight%s: %04x", ((int) cp < coll->w_count) ? "" : "(Computed)",
(((int) cp < coll->w_count) ? (coll->weights[cp]) : (cp + 1)));
return;
}
assert (coll->uca_exp_num > 1);
assert (coll->uca_exp_num <= MAX_UCA_EXP_CE);
if ((int) cp < coll->w_count)
{
int i;
UCA_L13_W *uca_w_l13 = &(coll->uca_w_l13[cp * coll->uca_exp_num]);
printf (" | Weight : ");
assert (coll->uca_num[cp] >= 1);
assert (coll->uca_num[cp] <= MAX_UCA_EXP_CE);
for (i = 0; i < coll->uca_num[cp]; i++)
{
printf ("[%04X.", UCA_GET_L1_W (uca_w_l13[i]));
printf ("%04X.", UCA_GET_L2_W (uca_w_l13[i]));
printf ("%04X.", UCA_GET_L3_W (uca_w_l13[i]));
if (coll->uca_opt.sett_strength >= TAILOR_QUATERNARY)
{
printf ("%04X]", coll->uca_w_l4[cp * coll->uca_exp_num + i]);
}
else
{
printf ("]");
}
}
}
else
{
printf (" | Weight(Computed) : %04X", cp + 1);
}
}
/*
* locale_check_and_set_shared_data - checks if data has already been taken
* into account as shared data, otherwise
* adds the new key as shared data
* Returns : error status
* lsd_type(in): shared data type
* lsd_key(in) : key (name) of data
* data(in) : data to be stored for key
* ldml_context(in): context of LDML file
* found_entry(out): shread data entry if found
*
* Note : this is used in context of genlocale tool, to check for duplicate
* collations, normalization or alphabet data
*/
static int
locale_check_and_set_shared_data (const LOC_SHARED_DATA_TYPE lsd_type, const char *lsd_key, const void *data,
LDML_CONTEXT * ldml_context, LOC_SHARED_DATA ** found_entry)
{
#define SHARED_DATA_INCR_SIZE 32
int status = NO_ERROR;
int i;
assert (lsd_key != NULL);
assert (found_entry != NULL);
*found_entry = NULL;
for (i = 0; i < count_shared_data; i++)
{
if (lsd_type == shared_data[i].lsd_type && strcmp (lsd_key, shared_data[i].lsd_key) == 0)
{
*found_entry = &(shared_data[i]);
goto exit;
}
}
/* set new shared data */
if (alloced_shared_data <= count_shared_data)
{
LOC_SHARED_DATA *const realloc_shared_data = (LOC_SHARED_DATA *) realloc (shared_data,
sizeof (LOC_SHARED_DATA) *
(alloced_shared_data +
SHARED_DATA_INCR_SIZE));
if (realloc_shared_data == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto exit;
}
else
{
shared_data = realloc_shared_data;
}
alloced_shared_data += SHARED_DATA_INCR_SIZE;
}
memset (&(shared_data[count_shared_data]), 0, sizeof (LOC_SHARED_DATA));
shared_data[count_shared_data].lsd_type = lsd_type;
strncpy (shared_data[count_shared_data].lsd_key, lsd_key, COLL_NAME_SIZE - 1);
shared_data[count_shared_data].lsd_key[COLL_NAME_SIZE - 1] = '\0';
if (data != NULL)
{
shared_data[count_shared_data].data = strdup ((const char *) data);
if (shared_data[count_shared_data].data == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto exit;
}
}
if (ldml_context != NULL)
{
shared_data[count_shared_data].ldml_context.ldml_file = strdup (ldml_context->ldml_file);
if (shared_data[count_shared_data].ldml_context.ldml_file == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
status = ER_LOC_GEN;
goto exit;
}
shared_data[count_shared_data].ldml_context.line_no = ldml_context->line_no;
}
count_shared_data++;
exit:
return status;
#undef SHARED_DATA_INCR_SIZE
}
/*
* locale_free_shared_data -
*
* Note : this is used in context of genlocale tool.
*/
void
locale_free_shared_data (void)
{
if (shared_data != NULL)
{
int i;
assert (count_shared_data > 0);
assert (alloced_shared_data > 0);
for (i = 0; i < count_shared_data; i++)
{
if (shared_data[i].data != NULL)
{
free (shared_data[i].data);
shared_data[i].data = NULL;
}
if (shared_data[i].ldml_context.ldml_file != NULL)
{
free (shared_data[i].ldml_context.ldml_file);
shared_data[i].ldml_context.ldml_file = NULL;
}
}
free (shared_data);
shared_data = NULL;
}
alloced_shared_data = 0;
count_shared_data = 0;
}
/*
* start_unicode_file() - XML element start function
* "ldml unicodefile"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_unicode_file (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
char *att_val = NULL;
assert (data != NULL);
ld = (LOCALE_DATA *) XML_USER_DATA (pd);
if (strlen (ld->unicode_data_file) != 0)
{
PRINT_DEBUG_START (data, attr, "Only one unicodefile tag is allowed", -1);
return -1;
}
att_val = NULL;
if (xml_get_att_value (attr, "CUBRIDUnicodeDataFilePath", &att_val) == 0)
{
assert (att_val != NULL);
strncpy (ld->unicode_data_file, att_val, sizeof (ld->unicode_data_file) - 1);
ld->unicode_data_file[sizeof (ld->unicode_data_file) - 1] = '\0';
ld->alpha_tailoring.alphabet_mode = 1;
ld->unicode_mode = 1;
}
PRINT_DEBUG_START (data, attr, "", 0);
return 0;
}
/*
* locale_destroy_normalization_data() - frees memory used by the specified
* locale for storing its computed normalization data.
* return:
* ld(in/out): locale to use
*/
void
locale_destroy_normalization_data (UNICODE_NORMALIZATION * norm)
{
if (norm == NULL)
{
return;
}
if (norm->unicode_mappings != NULL)
{
free (norm->unicode_mappings);
norm->unicode_mappings = NULL;
}
if (norm->list_full_decomp != NULL)
{
free (norm->list_full_decomp);
norm->list_full_decomp = NULL;
}
if (norm->unicode_mapping_index != NULL)
{
free (norm->unicode_mapping_index);
norm->unicode_mapping_index = NULL;
}
}
/*
* locale_save_normalization_to_C_file() - saves normalization data
* to C source file as variables, for later use
* when generating the locale shared library.
*
* return: error code
* fp(in): file pointer where to write the data
* ld(in): locale data
*/
static int
locale_save_normalization_to_C_file (FILE * fp, LOCALE_DATA * ld)
{
int i;
UNICODE_MAPPING *um;
UNICODE_NORMALIZATION *norm;
assert (ld != NULL);
assert (fp != NULL);
norm = &(ld->unicode_normalization);
if (norm->do_not_save)
{
goto exit;
}
PRINT_VAR_TO_C_FILE (fp, "int", "unicode_mappings_count", norm->unicode_mappings_count, "%d",
UNICODE_NORMALIZATION_DECORATOR);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "unicode_mapping_index", "int", "%d", MAX_UNICODE_CHARS, norm->unicode_mapping_index,
UNICODE_NORMALIZATION_DECORATOR);
PRINT_NUM_ARRAY_TO_C_FILE (fp, "list_full_decomp", "int", "%d", MAX_UNICODE_CHARS, norm->list_full_decomp,
UNICODE_NORMALIZATION_DECORATOR);
fprintf (fp, "" DLL_EXPORT_PREFIX "const UNICODE_MAPPING unicode_mappings_%s[] = {", UNICODE_NORMALIZATION_DECORATOR);
for (i = 0; i < norm->unicode_mappings_count; i++)
{
um = &(norm->unicode_mappings[i]);
fprintf (fp, "\t{%u, %d, ", um->cp, um->size);
PRINT_STRING_TO_C_FILE (fp, um->buffer, um->size);
fprintf (fp, "}%s\n", (i < norm->unicode_mappings_count - 1) ? "," : "");
}
fprintf (fp, "};");
exit:
return 0;
}
#define NORM_MAPPING_DUMP_MODE_FULL 0
#define NORM_MAPPING_DUMP_MODE_COMP 1
#define NORM_MAPPING_DUMP_MODE_DECOMP 2
/*
* dump_locale_normalization - dump the selected UNICODE_NORMALIZATION
* structure in human-readable text format.
* Returns : NO_ERROR.
* norm(in) : the UNICODE_NORMALIZATION to be dumped in text format.
*/
static void
dump_locale_normalization (UNICODE_NORMALIZATION * norm)
{
int i;
printf ("Sorted list of unicode mappings: \n");
for (i = 0; i < norm->unicode_mappings_count; i++)
{
printf ("%d.\t ", i + 1);
dump_unicode_mapping (&(norm->unicode_mappings[i]), NORM_MAPPING_DUMP_MODE_FULL);
printf ("\n");
}
printf ("\n Unicode composition mappings \n");
for (i = 0; i < MAX_UNICODE_CHARS; i++)
{
int j, comp_start, comp_end;
printf ("CP: %04X | \t Comp: ", i);
if (!CP_HAS_MAPPINGS (norm->unicode_mapping_index[i]))
{
printf ("NO\n");
continue;
}
comp_start = GET_MAPPING_OFFSET (norm->unicode_mapping_index[i]);
comp_end = GET_MAPPING_OFFSET (norm->unicode_mapping_index[i + 1]);
printf ("(%2d) From: %d To: %d | \t", comp_end - comp_start, comp_start, comp_end);
for (j = comp_start; j < comp_end; j++)
{
dump_unicode_mapping (&(norm->unicode_mappings[j]), NORM_MAPPING_DUMP_MODE_COMP);
printf (" | ");
}
printf ("\n");
}
printf ("\n Unicode decomposition mappings\n");
for (i = 0; i < MAX_UNICODE_CHARS; i++)
{
int decomp_idx = norm->list_full_decomp[i];
printf ("CP: %04X | Decomp : ", i);
if (decomp_idx < 0)
{
printf ("NO\n");
continue;
}
assert (decomp_idx >= 0);
dump_unicode_mapping (&(norm->unicode_mappings[decomp_idx]), NORM_MAPPING_DUMP_MODE_DECOMP);
printf ("\n");
}
}
/*
* dump_unicode_mapping() - Dump a UNICODE_MAPPING to the console.
*
* Returns:
* um(in) : unicode mapping to dump
*/
static void
dump_unicode_mapping (UNICODE_MAPPING * um, const int mode)
{
unsigned int cp;
unsigned char *next;
unsigned char *cur_str;
if (um == NULL)
{
printf ("Null mapping.\n");
return;
}
if (mode == NORM_MAPPING_DUMP_MODE_FULL)
{
printf ("CP: %04X", um->cp);
if (um->size > 0)
{
printf (" ->");
}
}
cur_str = um->buffer;
next = cur_str;
while (next < um->buffer + um->size)
{
cp = intl_utf8_to_cp (cur_str, (int) INTL_UTF8_MAX_CHAR_SIZE, &next);
printf ("%04X ", cp);
cur_str = next;
}
if (mode == NORM_MAPPING_DUMP_MODE_COMP)
{
printf (" -> CP: %04X", um->cp);
}
}
/*
* dump_console_conversion - dump Console text conversion data structure
* in human-readable text format.
* Returns : NO_ERROR.
* tc(in): the TEXT_CONVERSION to be dumped in text format.
*/
static int
dump_console_conversion (TEXT_CONVERSION * tc)
{
unsigned char utf8_seq[INTL_UTF8_MAX_CHAR_SIZE + 1];
unsigned char cnv_utf8_buf[2 * 3 + 1];
unsigned char *cnv_utf8;
CONV_CP_TO_BYTES *c_item;
unsigned int utf8_cp, con_cp;
unsigned char *next;
int utf8_size;
unsigned char *char_to_print = NULL;
int err;
if (tc == NULL || tc->conv_type == TEXT_CONV_NO_CONVERSION)
{
printf ("\nNo console conversion for this locale.\n\n");
goto exit;
}
printf ("\nType: ");
if (tc->conv_type == TEXT_CONV_ISO_88591_BUILTIN || tc->conv_type == TEXT_CONV_ISO_88599_BUILTIN)
{
printf ("built-in %s console to UTF-8 encoding \n",
(tc->conv_type == TEXT_CONV_ISO_88591_BUILTIN) ? "ISO 8859-1" : "ISO 8859-9");
}
else
{
printf ("%s byte console to UTF-8 encoding \n", (tc->conv_type == TEXT_CONV_GENERIC_1BYTE) ? "single" : "double");
}
printf ("Windows codepages: %s\n", tc->win_codepages);
printf ("Linux LANG charset values: %s\n", tc->nl_lang_str);
if (tc->conv_type != TEXT_CONV_GENERIC_1BYTE && tc->conv_type != TEXT_CONV_GENERIC_2BYTE)
{
goto exit;
}
printf ("\nConsole to UTF-8 conversion:\n");
printf ("Console codepoint -> Unicode codepoint | Character (UTF-8) \n");
for (con_cp = 0; con_cp <= tc->text_last_cp; con_cp++)
{
unsigned char dbcs_seq[2 + 1];
int dbcs_size;
if (tc->conv_type == TEXT_CONV_GENERIC_2BYTE && con_cp <= 0xff && tc->byte_flag[con_cp] != 0)
{
printf ("%02X -> Undefined or leading byte\n", con_cp);
continue;
}
utf8_cp = con_cp;
if (con_cp >= tc->text_first_cp)
{
c_item = &(tc->text_to_utf8[con_cp - tc->text_first_cp]);
utf8_cp = intl_utf8_to_cp (c_item->bytes, c_item->size, &next);
assert ((unsigned char *) next - c_item->bytes == c_item->size);
if (utf8_cp == 0x3f)
{
assert (con_cp != 0x3f);
printf ("%04X -> Undefined codepoint\n", con_cp);
continue;
}
utf8_size = intl_cp_to_utf8 (utf8_cp, utf8_seq);
assert ((unsigned int) utf8_size < sizeof (utf8_seq));
utf8_seq[utf8_size] = '\0';
char_to_print = (utf8_cp > 0x20) ? utf8_seq : (unsigned char *) "";
dbcs_size = intl_cp_to_dbcs (con_cp, tc->byte_flag, dbcs_seq);
dbcs_seq[dbcs_size] = '\0';
cnv_utf8 = cnv_utf8_buf;
utf8_size = sizeof (cnv_utf8_buf);
if (tc->conv_type == TEXT_CONV_GENERIC_1BYTE)
{
err = intl_text_single_byte_to_utf8_ext (tc, dbcs_seq, dbcs_size, &cnv_utf8, &utf8_size);
assert (err == NO_ERROR);
}
else
{
if (dbcs_size == 2 && tc->byte_flag[dbcs_seq[0]] != 1)
{
/* invalid console codepoint */
cnv_utf8 = NULL;
}
else
{
err = intl_text_dbcs_to_utf8_ext (tc, dbcs_seq, dbcs_size, &cnv_utf8, &utf8_size);
assert (err == NO_ERROR);
}
}
if (cnv_utf8 != NULL)
{
assert ((unsigned int) utf8_size <= sizeof (cnv_utf8_buf));
char_to_print = cnv_utf8;
}
}
else
{
utf8_size = intl_cp_to_utf8 (utf8_cp, utf8_seq);
assert ((unsigned int) utf8_size < sizeof (utf8_seq));
utf8_seq[utf8_size] = '\0';
char_to_print = (utf8_cp > 0x20) ? utf8_seq : (unsigned char *) "";
}
if (con_cp <= 0xff)
{
printf ("%02X -> Ux%04X | %s\n", con_cp, utf8_cp, char_to_print);
}
else
{
printf ("%04X -> Ux%04X | %s\n", con_cp, utf8_cp, char_to_print);
}
}
if (tc->text_last_cp < ((tc->conv_type == TEXT_CONV_GENERIC_1BYTE) ? (unsigned int) 0xff : (unsigned int) 0xffff))
{
if (tc->conv_type == TEXT_CONV_GENERIC_1BYTE)
{
printf ("Range %02X - FF is not mapped\n", tc->text_last_cp + 1);
}
else
{
printf ("Range %04X - FFFF is not mapped\n", tc->text_last_cp + 1);
}
}
printf ("\n\nUTF-8 to console conversion:\n");
printf ("Unicode codepoint [Unicode character] ->" " Console codepoint | Character (UTF-8 encoding)\n");
for (utf8_cp = 0; utf8_cp <= tc->utf8_last_cp; utf8_cp++)
{
if (utf8_cp > 0x20)
{
utf8_size = intl_cp_to_utf8 (utf8_cp, utf8_seq);
assert ((unsigned int) utf8_size < sizeof (utf8_seq));
utf8_seq[utf8_size] = '\0';
}
else
{
utf8_seq[0] = ' ';
utf8_seq[1] = '\0';
}
con_cp = utf8_cp;
char_to_print = utf8_seq;
if (utf8_cp >= tc->utf8_first_cp)
{
c_item = &(tc->utf8_to_text[utf8_cp - tc->utf8_first_cp]);
con_cp = intl_dbcs_to_cp (c_item->bytes, c_item->size, tc->byte_flag, &next);
assert (next - c_item->bytes == c_item->size);
if (con_cp == 0x3f)
{
assert (utf8_cp != 0x3f);
printf ("Ux%04X [%s] -> Not mapped\n", utf8_cp, utf8_seq);
continue;
}
cnv_utf8 = cnv_utf8_buf;
utf8_size = sizeof (cnv_utf8_buf);
if (tc->conv_type == TEXT_CONV_GENERIC_1BYTE)
{
err = intl_text_single_byte_to_utf8_ext (tc, c_item->bytes, c_item->size, &cnv_utf8, &utf8_size);
assert (err == NO_ERROR);
}
else
{
err = intl_text_dbcs_to_utf8_ext (tc, c_item->bytes, c_item->size, &cnv_utf8, &utf8_size);
assert (err == NO_ERROR);
}
assert ((unsigned int) utf8_size <= sizeof (cnv_utf8_buf));
char_to_print = cnv_utf8 ? cnv_utf8 : utf8_seq;
}
if (tc->conv_type == TEXT_CONV_GENERIC_1BYTE)
{
printf ("Ux%04X [%s] -> %02X | %s\n", utf8_cp, utf8_seq, con_cp, char_to_print);
}
else
{
printf ("Ux%04X [%s] -> %04X | %s\n", utf8_cp, utf8_seq, con_cp, char_to_print);
}
}
printf ("Codepoints above Ux%04X are not mapped\n", tc->utf8_last_cp);
exit:
return 0;
}
#define BUF_PUT_INT16(buf,v) \
do { \
unsigned short nv = htons(v); \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[1]; \
buf = (char *) (buf) + 1; \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[0]; \
buf = (char *) (buf) + 1; \
} while (0)
#define BUF_PUT_INT32(buf,v) \
do { \
unsigned int nv = htonl(v); \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[3]; \
buf = (char *) (buf) + 1; \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[2]; \
buf = (char *) (buf) + 1; \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[1]; \
buf = (char *) (buf) + 1; \
*((unsigned char *) (buf)) = ((unsigned char *) &nv)[0]; \
buf = (char *) (buf) + 1; \
} while (0)
#define BUF_ALIGN(buf, align) \
((char *)((((UINTPTR)(buf) + ((UINTPTR)((align)-1)))) \
& ~((UINTPTR)((align)-1))))
/*
* locale_compute_coll_checksum() - Computes the MD5 checksum of collation
*
* Returns: error status
* coll_data(in/out):
*/
static int
locale_compute_coll_checksum (COLL_DATA * cd)
{
int input_size = 0;
char *input_buf = NULL;
char *buf_pos;
int error_code = NO_ERROR;
int cp, w;
if (cd->uca_opt.sett_expansions)
{
/* Weights L1-L3 */
input_size += cd->uca_exp_num * cd->w_count * sizeof (cd->uca_w_l13[0]);
if (cd->uca_opt.sett_strength >= TAILOR_QUATERNARY)
{
/* Weights L4 */
input_size += cd->uca_exp_num * cd->w_count * sizeof (cd->uca_w_l4[0]);
}
}
else
{
/* single level weights */
input_size += cd->w_count * sizeof (cd->weights[0]);
}
/* next_cp */
input_size += cd->w_count * sizeof (cd->next_cp[0]);
if (cd->count_contr > 0)
{
/* contractions list */
input_size += cd->count_contr * sizeof (COLL_CONTRACTION);
input_size += sizeof (cd->contr_min_size);
input_size += sizeof (cd->cp_first_contr_offset);
input_size += sizeof (cd->cp_first_contr_count);
}
input_size += sizeof (UCA_OPTIONS);
/* build buffer */
input_buf = (char *) malloc (input_size);
if (input_buf == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
return ER_LOC_GEN;
}
memset (input_buf, 0, input_size);
buf_pos = input_buf;
if (cd->uca_opt.sett_expansions)
{
for (cp = 0; cp < cd->w_count; cp++)
{
for (w = 0; w < cd->uca_exp_num; w++)
{
BUF_PUT_INT32 (buf_pos, cd->uca_w_l13[cp * cd->uca_exp_num + w]);
}
}
if (cd->uca_opt.sett_strength >= TAILOR_QUATERNARY)
{
/* Weights L4 */
for (cp = 0; cp < cd->w_count; cp++)
{
for (w = 0; w < cd->uca_exp_num; w++)
{
BUF_PUT_INT16 (buf_pos, cd->uca_w_l4[cp * cd->uca_exp_num + w]);
}
}
}
}
else
{
for (cp = 0; cp < cd->w_count; cp++)
{
BUF_PUT_INT32 (buf_pos, cd->weights[cp]);
}
}
for (cp = 0; cp < cd->w_count; cp++)
{
BUF_PUT_INT32 (buf_pos, cd->next_cp[cp]);
}
if (cd->count_contr > 0)
{
/* contractions list */
for (cp = 0; cp < cd->count_contr; cp++)
{
COLL_CONTRACTION *c = &(cd->contr_list[cp]);
BUF_PUT_INT32 (buf_pos, c->next);
BUF_PUT_INT32 (buf_pos, c->wv);
for (w = 0; w < MAX_UCA_EXP_CE; w++)
{
BUF_PUT_INT32 (buf_pos, c->uca_w_l13[w]);
}
for (w = 0; w < MAX_UCA_EXP_CE; w++)
{
BUF_PUT_INT16 (buf_pos, c->uca_w_l4[w]);
}
memcpy (buf_pos, c->c_buf, sizeof (c->c_buf));
buf_pos += sizeof (c->c_buf);
*buf_pos++ = c->cp_count;
*buf_pos++ = c->size;
*buf_pos++ = c->uca_num;
buf_pos +=
sizeof (COLL_CONTRACTION) - (2 * sizeof (int) + MAX_UCA_EXP_CE * sizeof (int) +
MAX_UCA_EXP_CE * sizeof (short) + sizeof (c->c_buf) + 3 * sizeof (char));
}
BUF_PUT_INT32 (buf_pos, cd->contr_min_size);
BUF_PUT_INT32 (buf_pos, cd->cp_first_contr_offset);
BUF_PUT_INT32 (buf_pos, cd->cp_first_contr_count);
}
BUF_PUT_INT32 (buf_pos, cd->uca_opt.sett_strength);
*buf_pos++ = (unsigned char) (cd->uca_opt.sett_backwards);
*buf_pos++ = (unsigned char) (cd->uca_opt.sett_caseLevel);
buf_pos = BUF_ALIGN (buf_pos, sizeof (int));
BUF_PUT_INT32 (buf_pos, cd->uca_opt.sett_caseFirst);
*buf_pos++ = (unsigned char) (cd->uca_opt.sett_expansions);
buf_pos = BUF_ALIGN (buf_pos, sizeof (int));
BUF_PUT_INT32 (buf_pos, cd->uca_opt.sett_contr_policy);
*buf_pos++ = (unsigned char) (cd->uca_opt.use_only_first_ce);
buf_pos = BUF_ALIGN (buf_pos, sizeof (int));
BUF_PUT_INT32 (buf_pos, cd->uca_opt.sett_match_contr);
if (buf_pos - input_buf != input_size)
{
LOG_LOCALE_ERROR ("Error on collation checksum", ER_LOC_GEN, true);
free (input_buf);
return ER_LOC_GEN;
}
assert (buf_pos - input_buf == input_size);
memset (cd->checksum, 0, sizeof (cd->checksum));
error_code = crypt_md5_buffer_hex (input_buf, input_size, cd->checksum);
free (input_buf);
return error_code;
}
/*
* locale_alphabet_data_size() - Computes the size required by alphabet data
*
* Returns: size in bytes
* a(in):
*/
static int
locale_alphabet_data_size (ALPHABET_DATA * a)
{
int input_size = 0;
input_size += sizeof (a->a_type);
input_size += a->l_count * a->lower_multiplier * sizeof (a->lower_cp[0]);
input_size += a->l_count * a->upper_multiplier * sizeof (a->upper_cp[0]);
return input_size;
}
/*
* locale_alphabet_data_to_buf() - Saves alphabet data to a buffer
*
* Returns: size in bytes
* a(in):
* buf(out):
*
* Note : this is used in for data checksum purpose
*/
static int
locale_alphabet_data_to_buf (ALPHABET_DATA * a, char *buf)
{
char *buf_pos = buf;
int cp, m;
BUF_PUT_INT32 (buf_pos, a->a_type);
for (cp = 0; cp < a->l_count; cp++)
{
for (m = 0; m < a->lower_multiplier; m++)
{
BUF_PUT_INT32 (buf_pos, a->lower_cp[cp * a->lower_multiplier + m]);
}
}
for (cp = 0; cp < a->l_count; cp++)
{
for (m = 0; m < a->upper_multiplier; m++)
{
BUF_PUT_INT32 (buf_pos, a->upper_cp[cp * a->upper_multiplier + m]);
}
}
return CAST_BUFLEN (buf_pos - buf);
}
/*
* locale_compute_locale_checksum() - Computes the MD5 checksum of locale data
*
* Returns: error status
* ld(in/out):
*/
static int
locale_compute_locale_checksum (LOCALE_DATA * ld)
{
int input_size = 0;
char *input_buf = NULL;
char *buf_pos;
int error_code = NO_ERROR;
int cp;
input_size += sizeof (ld->dateFormat);
input_size += sizeof (ld->timeFormat);
input_size += sizeof (ld->datetimeFormat);
input_size += sizeof (ld->timestampFormat);
input_size += sizeof (ld->timetzFormat);
input_size += sizeof (ld->datetimetzFormat);
input_size += sizeof (ld->timestamptzFormat);
input_size += sizeof (ld->month_names_abbreviated);
input_size += sizeof (ld->month_names_wide);
input_size += sizeof (ld->day_names_abbreviated);
input_size += sizeof (ld->day_names_wide);
input_size += sizeof (ld->am_pm);
input_size += sizeof (ld->day_names_abbr_parse_order);
input_size += sizeof (ld->day_names_wide_parse_order);
input_size += sizeof (ld->month_names_abbr_parse_order);
input_size += sizeof (ld->month_names_wide_parse_order);
input_size += sizeof (ld->am_pm_parse_order);
input_size += sizeof (ld->number_decimal_sym);
input_size += sizeof (ld->number_group_sym);
input_size += sizeof (ld->default_currency_code);
input_size += locale_alphabet_data_size (&(ld->alphabet));
input_size += locale_alphabet_data_size (&(ld->identif_alphabet));
input_size += sizeof (ld->txt_conv.conv_type);
if (ld->txt_conv.conv_type == TEXT_CONV_GENERIC_1BYTE || ld->txt_conv.conv_type == TEXT_CONV_GENERIC_2BYTE)
{
TEXT_CONVERSION *tc = &(ld->txt_conv);
input_size += sizeof (tc->byte_flag);
input_size += sizeof (tc->utf8_first_cp);
input_size += sizeof (tc->utf8_last_cp);
input_size += sizeof (tc->text_first_cp);
input_size += sizeof (tc->text_last_cp);
input_size += strlen (tc->nl_lang_str);
input_size += strlen (tc->win_codepages);
input_size += (tc->utf8_last_cp - tc->utf8_first_cp + 1) * sizeof (CONV_CP_TO_BYTES);
input_size += (tc->text_last_cp - tc->text_first_cp + 1) * sizeof (CONV_CP_TO_BYTES);
}
if (!(ld->unicode_normalization.do_not_save))
{
UNICODE_NORMALIZATION *un = &(ld->unicode_normalization);
input_size += MAX_UNICODE_CHARS * sizeof (un->unicode_mapping_index[0]);
input_size += MAX_UNICODE_CHARS * sizeof (un->list_full_decomp[0]);
input_size += un->unicode_mappings_count * sizeof (UNICODE_MAPPING);
}
/* build buffer */
input_buf = (char *) malloc (input_size);
if (input_buf == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_GEN, true);
return ER_LOC_GEN;
}
buf_pos = input_buf;
memset (input_buf, 0, input_size);
/* formats */
memcpy (buf_pos, ld->dateFormat, sizeof (ld->dateFormat));
buf_pos += sizeof (ld->dateFormat);
memcpy (buf_pos, ld->timeFormat, sizeof (ld->timeFormat));
buf_pos += sizeof (ld->timeFormat);
memcpy (buf_pos, ld->datetimeFormat, sizeof (ld->datetimeFormat));
buf_pos += sizeof (ld->datetimeFormat);
memcpy (buf_pos, ld->timestampFormat, sizeof (ld->timestampFormat));
buf_pos += sizeof (ld->timestampFormat);
memcpy (buf_pos, ld->timetzFormat, sizeof (ld->timetzFormat));
buf_pos += sizeof (ld->timetzFormat);
memcpy (buf_pos, ld->datetimetzFormat, sizeof (ld->datetimetzFormat));
buf_pos += sizeof (ld->datetimetzFormat);
memcpy (buf_pos, ld->timestamptzFormat, sizeof (ld->timestamptzFormat));
buf_pos += sizeof (ld->timestamptzFormat);
/* calendar names */
memcpy (buf_pos, ld->month_names_abbreviated, sizeof (ld->month_names_abbreviated));
buf_pos += sizeof (ld->month_names_abbreviated);
memcpy (buf_pos, ld->month_names_wide, sizeof (ld->month_names_wide));
buf_pos += sizeof (ld->month_names_wide);
memcpy (buf_pos, ld->day_names_abbreviated, sizeof (ld->day_names_abbreviated));
buf_pos += sizeof (ld->day_names_abbreviated);
memcpy (buf_pos, ld->day_names_wide, sizeof (ld->day_names_wide));
buf_pos += sizeof (ld->day_names_wide);
memcpy (buf_pos, ld->am_pm, sizeof (ld->am_pm));
buf_pos += sizeof (ld->am_pm);
/* calendar parsing order */
memcpy (buf_pos, ld->day_names_abbr_parse_order, sizeof (ld->day_names_abbr_parse_order));
buf_pos += sizeof (ld->day_names_abbr_parse_order);
memcpy (buf_pos, ld->day_names_wide_parse_order, sizeof (ld->day_names_wide_parse_order));
buf_pos += sizeof (ld->day_names_wide_parse_order);
memcpy (buf_pos, ld->month_names_abbr_parse_order, sizeof (ld->month_names_abbr_parse_order));
buf_pos += sizeof (ld->month_names_abbr_parse_order);
memcpy (buf_pos, ld->month_names_wide_parse_order, sizeof (ld->month_names_wide_parse_order));
buf_pos += sizeof (ld->month_names_wide_parse_order);
memcpy (buf_pos, ld->am_pm_parse_order, sizeof (ld->am_pm_parse_order));
buf_pos += sizeof (ld->am_pm_parse_order);
/* number symbols */
memcpy (buf_pos, &(ld->number_decimal_sym), sizeof (ld->number_decimal_sym));
buf_pos += sizeof (ld->number_decimal_sym);
memcpy (buf_pos, &(ld->number_group_sym), sizeof (ld->number_group_sym));
buf_pos += sizeof (ld->number_group_sym);
BUF_PUT_INT32 (buf_pos, ld->default_currency_code);
/* alphabets */
buf_pos += locale_alphabet_data_to_buf (&(ld->alphabet), buf_pos);
buf_pos += locale_alphabet_data_to_buf (&(ld->identif_alphabet), buf_pos);
/* text conversion */
BUF_PUT_INT32 (buf_pos, ld->txt_conv.conv_type);
if (ld->txt_conv.conv_type == TEXT_CONV_GENERIC_1BYTE || ld->txt_conv.conv_type == TEXT_CONV_GENERIC_2BYTE)
{
TEXT_CONVERSION *tc = &(ld->txt_conv);
memcpy (buf_pos, tc->byte_flag, sizeof (tc->byte_flag));
buf_pos += sizeof (tc->byte_flag);
BUF_PUT_INT32 (buf_pos, tc->utf8_first_cp);
BUF_PUT_INT32 (buf_pos, tc->utf8_last_cp);
BUF_PUT_INT32 (buf_pos, tc->text_first_cp);
BUF_PUT_INT32 (buf_pos, tc->text_last_cp);
memcpy (buf_pos, tc->nl_lang_str, strlen (tc->nl_lang_str));
buf_pos += strlen (tc->nl_lang_str);
memcpy (buf_pos, tc->win_codepages, strlen (tc->win_codepages));
buf_pos += strlen (tc->win_codepages);
memcpy (buf_pos, tc->utf8_to_text, (tc->utf8_last_cp - tc->utf8_first_cp + 1) * sizeof (CONV_CP_TO_BYTES));
buf_pos += (tc->utf8_last_cp - tc->utf8_first_cp + 1) * sizeof (CONV_CP_TO_BYTES);
memcpy (buf_pos, tc->text_to_utf8, (tc->text_last_cp - tc->text_first_cp + 1) * sizeof (CONV_CP_TO_BYTES));
buf_pos += (tc->text_last_cp - tc->text_first_cp + 1) * sizeof (CONV_CP_TO_BYTES);
}
if (!(ld->unicode_normalization.do_not_save))
{
UNICODE_NORMALIZATION *un = &(ld->unicode_normalization);
for (cp = 0; cp < MAX_UNICODE_CHARS; cp++)
{
BUF_PUT_INT32 (buf_pos, un->unicode_mapping_index[cp]);
}
for (cp = 0; cp < MAX_UNICODE_CHARS; cp++)
{
BUF_PUT_INT32 (buf_pos, un->list_full_decomp[cp]);
}
for (cp = 0; cp < un->unicode_mappings_count; cp++)
{
UNICODE_MAPPING *um = &(un->unicode_mappings[cp]);
BUF_PUT_INT32 (buf_pos, um->cp);
BUF_PUT_INT32 (buf_pos, um->size);
memcpy (buf_pos, um->buffer, sizeof (um->buffer));
buf_pos += sizeof (um->buffer);
buf_pos += sizeof (UNICODE_MAPPING) - (sizeof (um->buffer) + 2 * sizeof (int));
}
}
if (buf_pos - input_buf != input_size)
{
LOG_LOCALE_ERROR ("Error on locale checksum", ER_LOC_GEN, true);
free (input_buf);
return ER_LOC_GEN;
}
assert (buf_pos - input_buf == input_size);
memset (ld->checksum, 0, sizeof (ld->checksum));
error_code = crypt_md5_buffer_hex (input_buf, input_size, ld->checksum);
free (input_buf);
return error_code;
}
/*
* common_collation_end_rule() - finishes a collation rule
*
* Returns: error status
* data(in/out): user data
* ld(in/out): locale data
* rule_id(in): collation rule id (position in rule list)
* t_rule(in/out): collation rule
*/
static int
common_collation_end_rule (void *data, LOCALE_DATA * ld, const int rule_id, TAILOR_RULE * t_rule)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
assert (data != NULL);
assert (ld != NULL);
assert (t_rule != NULL);
if (ld->last_rule_level != TAILOR_UNDEFINED)
{
if (ld->last_rule_level != t_rule->level)
{
/* first rule must match the level of anchor */
pd->xml_error = XML_CUB_ERR_PARSER;
PRINT_DEBUG_END (data, "Rule level doesn't match reset level", -1);
return -1;
}
/* reset level of anchor : don't need to check for following rules */
ld->last_rule_level = TAILOR_UNDEFINED;
}
t_rule->direction = ld->last_rule_dir;
t_rule->r_pos_type = ld->last_rule_pos_type;
/* last tailor character is the new reference */
if (!(t_rule->multiple_chars))
{
/* reset rule position */
ld->last_rule_pos_type = RULE_POS_BUFFER;
assert (t_rule->t_buf_size > 0);
ld->last_r_buf_size = t_rule->t_buf_size;
ld->last_r_buf_p = t_rule->t_buf;
memcpy (ld->last_anchor_buf, t_rule->t_buf, t_rule->t_buf_size);
ld->last_anchor_buf[t_rule->t_buf_size] = '\0';
}
/* BEFORE applies only for the first rule after <reset> */
ld->last_rule_dir = TAILOR_AFTER;
if (pd->verbose)
{
char msg[ERR_MSG_SIZE];
int xml_line_no = XML_GetCurrentLineNumber (pd->xml_parser);
int xml_col_no = XML_GetCurrentColumnNumber (pd->xml_parser);
snprintf (msg, sizeof (msg) - 1, "* Rule %d, L :%d, Dir:%d, PosType:%d, Mc:%d ;" " XML: line: %d , col:%d *",
rule_id, t_rule->level, t_rule->direction, t_rule->r_pos_type, t_rule->multiple_chars, xml_line_no,
xml_col_no);
PRINT_DEBUG_END (data, msg, 0);
}
return 0;
}
/*
* common_collation_start_rule() - starts a collation rule
*
* Returns: error status
* data(in/out): user data
* attr(in): element name
* ld(in/out): locale data
* t_rule(in/out): collation rule
*/
static int
common_collation_start_rule (void *data, const char **attr, LOCALE_DATA * ld, TAILOR_RULE * t_rule)
{
char *ref_buf_p = NULL;
int ref_buf_size = 0;
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
assert (data != NULL);
assert (ld != NULL);
assert (t_rule != NULL);
assert (ld->last_rule_pos_type == RULE_POS_BUFFER);
strcpy (t_rule->anchor_buf, ld->last_anchor_buf);
/* reference is last reference or anchor if no last refence is available */
if (ld->last_r_buf_p == NULL)
{
ref_buf_p = ld->last_anchor_buf;
ref_buf_size = strlen (ld->last_anchor_buf);
}
else
{
ref_buf_p = ld->last_r_buf_p;
ref_buf_size = ld->last_r_buf_size;
}
assert (ref_buf_size > 0);
assert (ref_buf_p != NULL);
t_rule->r_buf = (char *) malloc (ref_buf_size);
if (t_rule->r_buf == NULL)
{
pd->xml_error = XML_CUB_OUT_OF_MEMORY;
PRINT_DEBUG_START (data, attr, "memory allocation failed", -1);
return -1;
}
memcpy (t_rule->r_buf, ref_buf_p, ref_buf_size);
t_rule->r_buf_size = ref_buf_size;
return 0;
}
/*
* start_include_collation() - XML element start function
* "ldml collations include"
*
* return: 0 validation OK enter this element , 1 validation NOK do not enter
* -1 error abort parsing
* data: user data
* attr: attribute/value pair array
*/
static int
start_include_collation (void *data, const char **attr)
{
XML_PARSER_DATA *pd = (XML_PARSER_DATA *) data;
LOCALE_DATA *ld = NULL;
XML_PARSER_DATA *new_pd = NULL;
char *att_val = NULL;
char include_file_path[PATH_MAX] = { 0 };
char *prev_ldml_file = NULL;
int prev_line_no = 0;
LDML_CONTEXT *context = NULL;
assert (data != NULL);
if (xml_get_att_value (attr, "file", &att_val) != 0)
{
LOG_LOCALE_ERROR ("<include> tag requires a valid FILE attribute.", ER_LOC_GEN, true);
PRINT_DEBUG_START (data, attr, "<include> tag requires a valid " "FILE attribute.", -1);
return -1;
}
/* build a path and check if the file exists/is accessible */
envvar_ldmldir_file (include_file_path, PATH_MAX, att_val);
new_pd = xml_create_subparser (pd, include_file_path);
ld = (LOCALE_DATA *) XML_USER_DATA (new_pd);
assert (ld != NULL);
context = &(ld->ldml_context);
prev_ldml_file = context->ldml_file;
prev_line_no = context->line_no;
context->ldml_file = strdup (include_file_path);
context->line_no = 0;
int ret;
if (new_pd == NULL)
{
char err_msg[ERR_MSG_SIZE] = { 0 };
switch (pd->xml_error)
{
case XML_CUB_ERR_INCLUDE_LOOP:
ret = snprintf (err_msg, sizeof (err_msg) - 1, "Inclusion loop found for file %s.", include_file_path);
break;
case XML_CUB_ERR_PARSER_INIT_FAIL:
ret = snprintf (err_msg, sizeof (err_msg) - 1, "Failed to initialize subparser for file path %s.",
include_file_path);
break;
case XML_CUB_OUT_OF_MEMORY:
ret = snprintf (err_msg, sizeof (err_msg) - 1, "Memory exhausted when creating subparser for file %s.",
include_file_path);
break;
}
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
PRINT_DEBUG_START (data, attr, err_msg, -1);
return -1;
}
xml_parser_exec (new_pd);
if (new_pd->xml_error == XML_CUB_ERR_FILE_MISSING)
{
char err_msg[ERR_MSG_SIZE] = { 0 };
snprintf_dots_truncate (err_msg, sizeof (err_msg) - 1, "Included file %s does not exist or " "is not accessible.",
include_file_path);
PRINT_DEBUG_START (data, attr, err_msg, -1);
LOG_LOCALE_ERROR (err_msg, ER_LOC_GEN, true);
return -1;
}
else if (new_pd->xml_error != XML_CUB_NO_ERROR)
{
char msg[ERR_MSG_SIZE] = { 0 };
const char *xml_err_text = (char *) XML_ErrorString (XML_GetErrorCode (new_pd->xml_parser));
snprintf_dots_truncate (msg, sizeof (msg) - 1, "Error parsing file %s, " "line: %d, column: %d. Internal XML: %s",
new_pd->filepath, new_pd->xml_error_line, new_pd->xml_error_column, xml_err_text);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
return -1;
}
free (context->ldml_file);
context->ldml_file = prev_ldml_file;
context->line_no = prev_line_no;
pd->next = new_pd->next;
xml_destroy_parser_data (new_pd);
free (new_pd);
return 0;
}
#endif //#if defined(SA_MODE)
/*
* str_pop_token() - Extracts a token from a string;
* A token is a sub-string surrounded by whitespaces.
* return: string token
* str_p(in): buffer with tokens
* token_p(in/out): returned token string
* next_p(in/out): pointer to next token or NULL if no more tokens
*
* Note : When found the token characters are copied into a new string
* and returned.
* The pointer to the first character following the new token in
* the buffer is returned.
*/
static int
str_pop_token (char *str_p, char **token_p, char **next_p)
{
char *p, *end, *token = NULL;
int length;
assert (str_p != NULL);
assert (token_p != NULL);
assert (next_p != NULL);
p = str_p;
while (char_isspace ((int) *p) && *p != '\0')
{
p++;
}
end = p;
while (!char_isspace ((int) *end) && *end != '\0')
{
end++;
}
length = (int) (end - p);
if (length > 0)
{
token = (char *) malloc (length + 1);
if (token == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_INIT, true);
return ER_LOC_INIT;
}
assert (token != NULL);
strncpy (token, p, length);
token[length] = '\0';
}
else
{
/* no more tokens */
end = NULL;
}
*token_p = token;
*next_p = end;
return NO_ERROR;
}
/*
* locale_get_cfg_locales() - reads the locale strings and file paths configured
*
* return: error code
* locale_files(in/out):
* p_num_locales(out): number of user defined locales
* is_lang_init(in): true if this is called in context of lang initialization
*
* Note : This funtion is called in two contexts :
* - language initialization (no error is set in this case)
* - locale generation admin tool (error is generated)
*/
int
locale_get_cfg_locales (LOCALE_FILE ** p_locale_files, int *p_num_locales, bool is_lang_init)
{
char locale_cfg_file[PATH_MAX];
char line[1024];
FILE *fp = NULL;
LOCALE_FILE *locale_files = NULL;
int num_locales;
int max_locales = 10;
char msg[ERR_MSG_SIZE];
int err_status = NO_ERROR;
assert (p_locale_files != NULL);
assert (p_num_locales != NULL);
envvar_confdir_file (locale_cfg_file, sizeof (locale_cfg_file), "cubrid_locales.txt");
fp = fopen_ex (locale_cfg_file, "rt");
if (fp == NULL)
{
if (is_lang_init)
{
/* no error is recorded, 'cubrid_locales.txt' is optional */
goto exit;
}
else
{
snprintf_dots_truncate (msg, sizeof (msg) - 1, "Cannot open file %s", locale_cfg_file);
LOG_LOCALE_ERROR (msg, ER_LOC_GEN, true);
err_status = ER_LOC_GEN;
goto exit;
}
}
locale_files = NULL;
num_locales = 0;
locale_files = (LOCALE_FILE *) malloc (max_locales * sizeof (LOCALE_FILE));
if (locale_files == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_INIT, true);
err_status = ER_LOC_INIT;
goto exit;
}
while (fgets (line, sizeof (line) - 1, fp) != NULL)
{
char *str, *next;
LOCALE_FILE *loc;
if (*line == '\0' || *line == '#' || char_isspace ((int) *line))
{
continue;
}
num_locales++;
if (num_locales >= max_locales)
{
max_locales *= 2;
LOCALE_FILE *const realloc_locale_files
= (LOCALE_FILE *) realloc (locale_files, max_locales * sizeof (LOCALE_FILE));
if (realloc_locale_files == NULL)
{
LOG_LOCALE_ERROR ("memory allocation failed", ER_LOC_INIT, true);
err_status = ER_LOC_INIT;
goto exit;
}
else
{
locale_files = realloc_locale_files;
}
}
loc = &(locale_files[num_locales - 1]);
memset (loc, 0, sizeof (LOCALE_FILE));
str = line;
err_status = str_pop_token (str, &(loc->locale_name), &next);
if (err_status != NO_ERROR)
{
goto exit;
}
if (next == NULL)
{
continue;
}
str = next;
err_status = str_pop_token (str, &(loc->ldml_file), &next);
if (err_status != NO_ERROR)
{
goto exit;
}
if (next == NULL)
{
continue;
}
str = next;
err_status = str_pop_token (str, &(loc->lib_file), &next);
if (err_status != NO_ERROR)
{
goto exit;
}
}
*p_locale_files = locale_files;
*p_num_locales = num_locales;
exit:
if (fp != NULL)
{
fclose (fp);
}
return err_status;
}
/*
* locale_check_and_set_default_files() - checks if the files for locale is set
* if not set, the default file paths are
* computed
*
* return:
* lf(in/out):
* is_lang_init(in): true if this is called in context of lang initialization
*
* Note : This funtion is called in two contexts :
* - language initialization (no error is set in this case)
* - locale generation admin tool (error is generated)
*/
int
locale_check_and_set_default_files (LOCALE_FILE * lf, bool is_lang_init)
{
bool is_alloc_ldml_file = false;
bool is_alloc_lib_file = false;
int er_status = NO_ERROR;
assert (lf != NULL);
if (lf->locale_name == NULL || strlen (lf->locale_name) > LOC_LOCALE_STR_SIZE)
{
er_status = is_lang_init ? ER_LOC_INIT : ER_LOC_GEN;
LOG_LOCALE_ERROR ("invalid locale name in 'cubrid_locales.txt'", er_status, true);
goto error;
}
if (lf->ldml_file == NULL || *(lf->ldml_file) == '\0' || *(lf->ldml_file) == '*')
{
/* generate name for LDML file */
char ldml_short_file[LOC_LOCALE_STR_SIZE + 13];
snprintf (ldml_short_file, sizeof (ldml_short_file) - 1, "cubrid_%s.xml", lf->locale_name);
ldml_short_file[sizeof (ldml_short_file) - 1] = '\0';
if (lf->ldml_file != NULL)
{
free (lf->ldml_file);
}
lf->ldml_file = (char *) malloc (PATH_MAX + 1);
if (lf->ldml_file == NULL)
{
er_status = is_lang_init ? ER_LOC_INIT : ER_LOC_GEN;
LOG_LOCALE_ERROR ("memory allocation failed", er_status, true);
goto error;
}
is_alloc_ldml_file = true;
envvar_ldmldir_file (lf->ldml_file, PATH_MAX, ldml_short_file);
}
if (lf->lib_file == NULL || *(lf->lib_file) == '\0' || *(lf->lib_file) == '*')
{
/* generate name for locale lib file */
char lib_short_file[PATH_MAX];
snprintf (lib_short_file, sizeof (lib_short_file) - 1, "libcubrid_%s.%s", lf->locale_name, LOCLIB_FILE_EXT);
lib_short_file[sizeof (lib_short_file) - 1] = '\0';
if (lf->lib_file != NULL)
{
free (lf->lib_file);
}
lf->lib_file = (char *) malloc (PATH_MAX + 1);
if (lf->lib_file == NULL)
{
er_status = is_lang_init ? ER_LOC_INIT : ER_LOC_GEN;
LOG_LOCALE_ERROR ("memory allocation failed", er_status, true);
goto error;
}
is_alloc_lib_file = true;
envvar_libdir_file (lf->lib_file, PATH_MAX, lib_short_file);
if (is_lang_init)
{
FILE *fp;
/* check that default lib file exists, otherwise switch to the common libray locale */
fp = fopen_ex (lf->lib_file, "rb");
if (fp == NULL)
{
snprintf (lib_short_file, sizeof (lib_short_file) - 1, "libcubrid_all_locales.%s", LOCLIB_FILE_EXT);
lib_short_file[sizeof (lib_short_file) - 1] = '\0';
assert (lf->lib_file != NULL);
envvar_libdir_file (lf->lib_file, PATH_MAX, lib_short_file);
}
else
{
fclose (fp);
}
}
}
return NO_ERROR;
error:
if (is_alloc_ldml_file)
{
free (lf->ldml_file);
lf->ldml_file = NULL;
}
if (is_alloc_lib_file)
{
free (lf->lib_file);
lf->lib_file = NULL;
}
return er_status;
}