%% options copyright owner = Dirk Krause copyright year = 2015-xxxx SPDX-License-Identifier: BSD-3-Clause %% header /** @file dk4uc2la.h Text to LaTeX conversion. LaTeX sequences to represent a 32 bit character are found in lookup tables in the ${datarootdir}/dktools/charmap directory. The functions in this module read those lookup tables needed, cache the contents and provide LaTeX sequences. After finishing output you can write recommendations (i.e. LaTeX packages to include, font encoding to use) as comments to the file. The functions in this module supported immediate error reporting using the dk4_app_t data type. The functions in the dk4uc2l module support restricted and delayed error reporting using the dk4_er_t module. Functions from the dk4uc2la and dk4uc2l module can be used combined. A typical scenario is to use the dk4uc2l_open_app_ex1() function with la set to 1 to open a conversion structure. This will read all the data files and store all contained LaTeX encodings in memory when opening the structure. Errors - i.e. failed memory allocations or syntax error in data files - are reported immediately. Later the dk4uc2l_find() function can be used. As problematic errors like failed memory allocations are already reported, a NULL return value can only indicate a missing encoding. */ #ifndef DK4CONF_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4conf.h" #else #include #endif #endif #ifndef DK4UC2L_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4uc2l.h" #else #include #endif #endif #ifndef DK4APP_H_INCLUDED #if DK4_BUILDING_DKTOOLS4 #include "dk4app.h" #else #include #endif #endif #ifdef __cplusplus extern "C" { #endif /** Open conversion structure, dynamically allocate memory. Extended version 1. @param dn Directory name containing the data files. @param app Application structure for diagnostics, may be NULL. @param la Flag: Immediately load all data files. @return Pointer to conversion structure on success, NULL on error. Use dk4uc2l_close() to close the conversion structure when done with it. */ dk4_uc2l_t * dk4uc2l_open_app_ex1(const dkChar *dn, dk4_app_t *app, int la); /** Open conversion structure, dynamically allocate memory. @param dn Directory name containing the data files. @param app Application structure for diagnostics, may be NULL. @return Pointer to conversion structure on success, NULL on error. Use dk4uc2l_close() to close the conversion structure when done with it. */ dk4_uc2l_t * dk4uc2l_open_app(const dkChar *dn, dk4_app_t *app); /** Open conversion structure, dynamically allocate memory. Extended version 1. The directory containing the data files is obtained from the application (if not NULL), ${datarootdir}/dktools/charmap is used by default. @param app Application structure for diagnostics, may be NULL. @param la Flag: Immediately load all data files. @return Pointer to conversion structure on success, NULL on error. Use dk4uc2l_close() to close the conversion structure when done with it. */ dk4_uc2l_t * dk4uc2l_open_from_app_ex1(dk4_app_t *app, int la); /** Open conversion structure, dynamically allocate memory. The directory containing the data files is obtained from the application (if not NULL), ${datarootdir}/dktools/charmap is used by default. @param app Application structure for diagnostics, may be NULL. @return Pointer to conversion structure on success, NULL on error. Use dk4uc2l_close() to close the conversion structure when done with it. */ dk4_uc2l_t * dk4uc2l_open_from_app(dk4_app_t *app); /** Find LaTeX encoding for one 32 bit character. Error messages are written using app only for internal errors (like "not enough memory" or syntax errors in data files). No error message is written if no LaTeX encoding was found, writing such error messages is left up to the calling code (as you probably want to restrict the number of such messages). @param ulptr Conversion structure. @param c Character to search encoding for. @param mm Flag: Math mode (1) or text mode (0). @param app Application structure for diagnostics, may be NULL. @return Pointer to encoding string on success, NULL on failure (error or not found). */ const char * dk4uc2l_find_app(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_app_t *app); /** Write string of 32 bit characters. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_c32_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c32_t *str, dk4_app_t *app ); /** Write string of 16 bit characters. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_c16_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c16_t *str, dk4_app_t *app ); /** Write UTF-8 encoded string. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_utf8_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ); /** Write ANSI encoded string. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_ansi_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ); /** Write ASCII encoded string. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_ascii_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ); /** Write char string. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param ie Input encoding. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_c8_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, int ie, dk4_app_t *app ); /** Write dkChar string. @param wstrm Stream to write to. @param ulptr Conversion structure. @param str String to write. @param ie Input encoding. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ int dk4uc2l_string_dk_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dkChar *str, int ie, dk4_app_t *app ); #ifdef __cplusplus } #endif %% module #include "dk4conf.h" #include #if DK4_HAVE_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #include "dk4const.h" #include "dk4uc2la.h" #include "dk4mem.h" #include "dk4mema.h" #include "dk4str8.h" #include "dk4strd.h" #include "dk4utf8.h" #include "dk4utf16.h" #include "dk4ansi.h" #include "dk4maasz.h" #include "dk4filed.h" #include "dk4mpl.h" #include "dk4strm.h" #include "dk4strmr.h" #include "dk4dir.h" #include "dk4dira.h" #include "dk4pathd.h" #include "dk4tsp08.h" #include "dk4enc.h" #include "dk4mai8hul.h" #include "dk4maodh.h" #include "dk4maodd.h" #include "dk4unused.h" #include "dk4rec26.h" #include "uc2l.h" #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif $!trace-include /** Convert to unsigned long. */ #define UL(x) ((unsigned long)(x)) /** Object to use and modify from line handler. */ typedef struct { dk4_uc2l_t *ulptr; /**< Conversion structure. */ dk4_sto_t *s_ra; /**< Local range storage. */ dk4_sto_it_t *i_ra; /**< Local range iterator. */ dk4_uc2l_file_t *file; /**< File structure. */ dk4_uc2l_range_t *rpc; /**< Range pointer cache, pass 2. */ dk4_app_t *app; /**< Application structure. */ const dkChar * const *msgs; /**< Localized message texts. */ size_t szmsgs; /**< Number of elements in msgs. */ int e_d; /**< Reported decoding errors. */ int e_e; /**< Reported encoding errors. */ int e_p; /**< Reported processing errors. */ } handler_object_t; /** Fixed keywords used by the module, not localized. */ static const dkChar * const dk4uc2l_kwnl[] = { $!string-table macro=dkT # # 0 Preference: Directory containing map data. # dir.charmap # # 1 2 3 Subdirectories to search for. # /dktools/charmap /dk4app/charmap /dk3app/charmap # # 4 5 6 File name suffixes # .t2l .t2l.gz .t2l.bz2 # # 7 Path separator # / # # 8 String table file name. # dk4uc2l.str $!end }; /** Localized texts. */ static const dkChar * const dk4uc2l_kw_def[] = { $!string-table macro=dkT # # 0 Error: Syntax # Syntax error!\n\tHexadecimal number required at start of line! # # 1 Error: Syntax # Syntax error!\n\tHexadecimal value outside allowed 32 bit range! # # 2 3 4 Error: Syntax error! Redefintion of character! # Syntax error!\n\tIgnoring redefinition of 0x ! Syntax error!\n\tIgnoring redefinition of character! # # 5 Error: Failed to set up text processing! # Failed to set up text processing! # # 6 7 Error: Failed to open file for reading: ... # Failed to open file for reading:\n\t" "! # # 8 Error: Syntax error!\n\tIllegal font encoding name! # Syntax error!\n\tIllegal font encoding name! # # 9 Error: Syntax error!\n\t1 to 15 packages names are allowed! # Syntax error!\n\t1 to 15 packages names are allowed! # # 10 Error: Syntax error!\n\tIllegal attribute name! # Syntax error!\n\tIllegal attribute name! # # 11 Error: Syntax error!\n\tAttribute specified without value! # Syntax error!\n\tAttribute specified without value! # # 12 13 14 Error: Conversion to UTF-8 failed for a character! # Conversion to UTF-8 failed for 0x ! Conversion to UTF-8 failed for a character! # # 15 Error: No directory for character mapping information found! # No directory for character mapping information found! # # 16 ... 21 Error messages. # Decoding failed!\n\tByte: Encoding failed!\n\tByte: Processing failed!\n\tByte: ,\n\tCharacter: ,\n\tPosition in line: . # # 22 ... 27 Error messages. # Decoding failed! Encoding failed! Processing failed! Further decoding failures! Further encoding failures! Further processing failures! # # 28 29 30 # Syntax error!\n\tIgnoring redefinition of 0x \n\tpreviously defined in " "! # # 31 32 ERROR: No LaTeX encoding found for ...! # No LaTeX encoding found for U+ ! # # # $!end }; /** Opening and closing tag for math mode. */ static const char * const dk4uc2l_mm[] = { "\\(", "\\)" }; /** Handler to process a line during pass 1. @param obj Object to use and modify during processing. @param line Current text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort. */ static int dk4uc2l_handler_pass1( void *obj, char *line, dk4_um_t lineno, dk4_er_t *erp ) { dkChar numbuf[16*sizeof(dk4_um_t)]; handler_object_t *pho; char *p1; dk4_uc2l_range_t *rptr; dk4_uc2l_range_t *r2; const char *pe = NULL; size_t sznb = DK4_SIZEOF(numbuf,dkChar); size_t padsz = 8; unsigned long ul = 0UL; dk4_c32_t c32; dk4_c32_t rbo; int res; int back = DK4_TSP_RES_OK; #if TRACE_DEBUG dk4str8_delnl(line); #endif $? "+ dk4uc2l_handler_pass1 \"%!8s\"", TR_8STR(line) pho = (handler_object_t *)obj; dk4app_set_log_source_line(pho->app, lineno); /* Find start of line, ignore empty lines and comments */ p1 = dk4str8_start(line, NULL); if (NULL == p1) { goto finished; } if ('#' == *p1) { goto finished; } /* Retrieve hexadecimal number at start */ (void)dk4str8_next(p1, NULL); res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp); if (0 == res) { /* ERROR: Syntax, not a number */ dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 0); goto finished; } c32 = (dk4_c32_t)ul; $? ". c32=%lu 0x%lx", ul, ul /* Check for number in global storage */ rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like( pho->ulptr->i_ranges, &c32, 1 ); if (NULL != rptr) { $? "! found in global storage" /* ERROR: Ignoring redefinition */ if ((dk4_c32_t)0xFFUL < c32) { if ((dk4_c32_t)0xFFFFUL < c32) { if ((dk4_c32_t)0xFFFFFFUL < c32) { padsz = 8; } else { padsz = 6; } } else { padsz = 4; } } else { padsz = 2; } if (0 != dk4ma_write_hex_unsigned(numbuf, sznb, c32, padsz, NULL)) { dk4app_log_5( pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 28, 29, 30, numbuf, rptr->file->fn ); } else { dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 4); } goto finished; } /* Check for number in storage for file */ rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &c32, 1); if (NULL != rptr) { $? "! found in file storage" /* ERROR: Ignoring redefinition */ if ((dk4_c32_t)0xFFUL < c32) { if ((dk4_c32_t)0xFFFFUL < c32) { if ((dk4_c32_t)0xFFFFFFUL < c32) { padsz = 8; } else { padsz = 6; } } else { padsz = 4; } } else { padsz = 2; } if (0 != dk4ma_write_hex_unsigned(numbuf, sznb, c32, padsz, NULL)) { dk4app_log_3( pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 2, 3, numbuf ); } else { dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 4); } goto finished; } /* Check whether appending to an existing range */ if (0UL < c32) { rbo = c32 - 1UL; rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1); if (NULL != rptr) { rptr->end = c32; #if DK4_SIZEOF_LONG <= 4 if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) { #endif rbo = c32 + 1UL; r2 = (dk4_uc2l_range_t *)dk4sto_it_find_like( pho->i_ra, &rbo, 1 ); if (NULL != r2) { dk4sto_remove(pho->s_ra, r2, NULL); rptr->end = r2->end; dk4uc2l_i_close_range(r2); } #if DK4_SIZEOF_LONG <= 4 } #endif goto finished; } #if TRACE_DEBUG else { $? ". no range for %lu 0x%lx", (ul-1UL), (ul-1UL) } #endif } /* Check whether prepending to an existing range */ #if DK4_SIZEOF_LONG <= 4 if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) { #endif rbo = c32 + 1UL; rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1); if (NULL != rptr) { rptr->start = c32; if ((dk4_c32_t)0UL < c32) { rbo = c32 - 1UL; r2 = (dk4_uc2l_range_t *)dk4sto_it_find_like( pho->i_ra, &rbo, 1 ); if (NULL != r2) { dk4sto_remove(pho->s_ra, r2, NULL); rptr->start = r2->start; dk4uc2l_i_close_range(r2); } } goto finished; } #if TRACE_DEBUG else { $? ". no range for %lu %lx", (ul+1UL), (ul+1UL) } #endif #if DK4_SIZEOF_LONG <= 4 } #endif /* Create new range for one character on its own */ rptr = dk4uc2l_i_open_range(c32, pho->file, erp); if (NULL == rptr) { back = DK4_TSP_RES_FATAL; /* ERROR: Memory */ dk4app_log_base1(pho->app, DK4_LL_ERROR, 90); goto finished; } if (0 == dk4sto_add(pho->s_ra, rptr, erp)) { dk4uc2l_i_close_range(rptr); /* ERROR: Memory */ dk4app_log_base1(pho->app, DK4_LL_ERROR, 90); back = DK4_TSP_RES_FATAL; } finished: $? "- dk4uc2l_handler_pass1 %d", back return back; } /** Report an error with position in source line. @param i1 Index of first message part in array. @param i2 Index of alternative first message part. @param bno Byte processed. @param lno Current line number. @param cno Current character number. @param cil Current character number in line. @param dmsg Localized error message texts. @param szdmsg Number of elements in dmsg array. */ static void dk4uc2l_report_with_pos( dk4_app_t *app, size_t i1, size_t i2, dk4_um_t bno, dk4_um_t lno, dk4_um_t cno, dk4_um_t cil, const dkChar * const *dmsg, size_t szdmsg ) { dkChar b1[8*(1+sizeof(dk4_um_t))]; dkChar b2[DK4_SIZEOF(b1,dkChar)]; dkChar b3[DK4_SIZEOF(b1,dkChar)]; size_t szbuf = DK4_SIZEOF(b1,dkChar); dk4_um_t oldlogline = (dk4_um_t)0UL; int allbuffersok = 0; oldlogline = dk4app_get_log_source_line(app); dk4app_set_log_source_line(app, lno); if (0 != dk4ma_write_decimal_unsigned(b3, szbuf, cil, 0, NULL)) { if (0 != dk4ma_write_decimal_unsigned(b2, szbuf, cno, 0, NULL)) { if (0 != dk4ma_write_decimal_unsigned(b1, szbuf, bno, 0, NULL)) { allbuffersok = 1; } } } if (0 != allbuffersok) { dk4app_log_7( app, dmsg, szdmsg, DK4_LL_ERROR, i1, 19, 20, 21, b1, b2, b3 ); } else { dk4app_log_1( app, dmsg, szdmsg, DK4_LL_ERROR, i2 ); } dk4app_set_log_source_line(app, oldlogline); } /** Report errors from text stream processing. @param app Application structure, may be NULL. @param obj Object modified by line handler. @param er_en Error report for decoding and encoding errors. @param er_pr Error report for processing errors. @param dmsg Localized error message texts. @param szmsg Number of elements in dmsg array. */ static void dk4uc2l_report_errors( dk4_app_t *app, handler_object_t *obj, dk4_er_t *er_en, dk4_er_t *er_pr, const dkChar * const *dmsg, size_t szdmsg ) { if (NULL != er_en) { switch (er_en->ec) { case DK4_E_DECODING_FAILED: { switch (obj->e_d) { case 0: case 1: { dk4uc2l_report_with_pos( app, 16, 22, er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, er_en->dt.fpos.charno, er_en->dt.fpos.charinline, dmsg, szdmsg ); } break; case 2: { dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 25); } break; } if (3 > obj->e_d) { obj->e_d += 1; } } break; case DK4_E_ENCODING_FAILED: { switch (obj->e_e) { case 0: case 1: { dk4uc2l_report_with_pos( app, 17, 23, er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, er_en->dt.fpos.charno, er_en->dt.fpos.charinline, dmsg, szdmsg ); } break; case 2: { dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 26); } break; } if (3 > obj->e_e) { obj->e_e += 1; } } break; } } if (NULL != er_pr) { if (DK4_E_NONE != er_pr->ec) { switch (obj->e_p) { case 0: case 1: { dk4uc2l_report_with_pos( app, 18, 24, er_pr->dt.fpos.byteno, er_pr->dt.fpos.lineno, er_pr->dt.fpos.charno, er_pr->dt.fpos.charinline, dmsg, szdmsg ); } break; case 2: { dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 27); } break; } if (3 > obj->e_p) { obj->e_p += 1; } } } } /** Process one stream from file in pass 1. @param ulptr Conversion structure to set up. @param rstrm Stream to read data from. @param puc2lf File structure. @param bptr Address of success variable to reset on error. @param app Application structure for diagnostics. @param dmsg Localized messages texts. @param szdmsg Size of dmsg array (number of string pointers). */ static void dk4uc2l_i_process_stream_pass1( dk4_uc2l_t *ulptr, dk4_stream_t *rstrm, dk4_uc2l_file_t *puc2lf, int *bptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { char lnbuf[256]; dk4_tsp08_t tsp08; handler_object_t ho; dk4_er_t er_en; dk4_er_t er_pr; dk4_uc2l_range_t *rptr; int res; int cc; char c; $? "+ dk4uc2l_i_process_stream_pass1" /* Initialize handler object */ ho.file = puc2lf; ho.ulptr = ulptr; ho.s_ra = NULL; ho.i_ra = NULL; ho.app = app; ho.msgs = dmsg; ho.szmsgs = szdmsg; ho.e_d = 0; ho.e_e = 0; ho.e_p = 0; dk4error_init(&er_en); dk4error_init(&er_pr); /* Allocate storage and iterator */ ho.s_ra = dk4sto_open(NULL); if (NULL == ho.s_ra) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } dk4sto_set_comp(ho.s_ra, dk4uc2l_i_range_compare, 0); ho.i_ra = dk4sto_it_open(ho.s_ra, NULL); if (NULL == ho.i_ra) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } /* Initialize text stream processor */ res = dk4tsp08_setup_line( &tsp08, (void *)(&ho), dk4uc2l_handler_pass1, lnbuf, sizeof(lnbuf), DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, NULL ); if (0 == res) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; /* ERROR: Failed to initialize text stream processor */ dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 5); goto finished; } /* Process input data */ do { cc = 0; res = dk4stream_c8_read_byte(&c, rstrm, NULL); if (0 != res) { cc = 1; res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c); switch (res) { case DK4_TSP_RES_ERROR : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; *bptr = 0; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); dk4error_init(&er_en); dk4error_init(&er_pr); } break; case DK4_TSP_RES_FATAL : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; *bptr = 0; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); dk4error_init(&er_en); dk4error_init(&er_pr); goto finished; } break; } } } while (0 < cc); /* Finalize text stream processor */ res = dk4tsp08_finish(&tsp08); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; *bptr = 0; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); goto finished; } break; } /* Transfer ranges to global storage */ do { dk4sto_it_reset(ho.i_ra); rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra); if (NULL != rptr) { dk4sto_remove(ho.s_ra, rptr, NULL); if (0 == dk4sto_add(ulptr->s_ranges, rptr, NULL)) { dk4uc2l_i_close_range(rptr); *bptr = 0; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } } } while (NULL != rptr); /* Release resources */ finished: if (NULL != ho.s_ra) { if (NULL != ho.i_ra) { dk4sto_it_reset(ho.i_ra); do { rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra); if (NULL != rptr) { dk4uc2l_i_close_range(rptr); } } while (NULL != rptr); dk4sto_it_close(ho.i_ra); } dk4sto_close(ho.s_ra); } $? "- dk4uc2l_i_process_stream_pass1" } /** Process one file in pass 1 specified by absolute path name. @param ulptr Conversion structure to set up. @param fn Absolute file name. @param sfn Short (relative) file name within given directory. @param bptr Address of success variable to reset on error. @param app Application structure for diagnostics. @param dmsg Localized messages texts. @param szdmsg Size of dmsg array (number of string pointers). */ static void dk4uc2l_i_process_one_full_file_pass1( dk4_uc2l_t *ulptr, const dkChar *fn, const dkChar *sfn, int *bptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { const dkChar *oldsourcefile; dk4_stream_t *rstrm; dk4_uc2l_file_t *puc2lf; dk4_um_t oldsourceline; int fnsi; $? "+ dk4uc2l_i_process_one_full_file_pass1 \"%!ds\"", TR_STR(fn) oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, fn); dk4app_set_log_source_line(app, (dk4_um_t)0UL); puc2lf = (dk4_uc2l_file_t *)dk4sto_it_find_like(ulptr->i_files, sfn, 1); if (NULL == puc2lf) { puc2lf = dk4uc2l_i_open_file(sfn, NULL); if (NULL != puc2lf) { if (0 != dk4sto_add(ulptr->s_files, puc2lf, NULL)) { fnsi = dk4uc2l_i_find_suffix_index(fn); if (-1 < fnsi) { if (0 != dk4uc2l_i_suffix_index_supported(fnsi)) { rstrm = dk4stream_open_file_reader(fn, NULL); if (NULL != rstrm) { dk4uc2l_i_process_stream_pass1( ulptr, rstrm, puc2lf, bptr, app, dmsg, szdmsg ); dk4stream_close(rstrm, NULL); } else { $? "! failed to open file for reading" ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; /* ERROR: Failed to read file */ dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn); *bptr = 0; } } else { $? "! unsupported compression type" /* ERROR: Unsupported compression mechanism */ dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn); ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; *bptr = 0; } } else { $? "! unsupported file type" /* Warning: Unsupported file type */ dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn); } } else { $? "! failed to store" dk4uc2l_i_close_file(puc2lf); /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } } else { $? "! allocation failed" /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } } else { $? "! bug, already processed" /* BUG file already processed */ } dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); $? "- dk4uc2l_i_process_one_full_file_pass1" } /** Process one file in pass 1. @param ulptr Conversion structure to set up. @param pth Directory path name, may be NULL. @param fn Short file name within given directory. @param bptr Address of success variable to reset on error. @param app Application structure for diagnostics. @param dmsg Localized messages texts. @param szdmsg Size of dmsg array (number of string pointers). */ static void dk4uc2l_i_process_one_file_pass1( dk4_uc2l_t *ulptr, const dkChar *pth, const dkChar *fn, int *bptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { dkChar fnb[DK4_MAX_PATH]; size_t szfnb = DK4_SIZEOF(fnb,dkChar); $? "+ dk4uc2l_i_process_one_file_pass1 \"%!ds\" \"%!ds\"", TR_STR(pth), TR_STR(fn) if (NULL != pth) { if (0 != dk4str_cpy_s(fnb, szfnb, pth, NULL)) { if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[7], NULL)) { if (0 != dk4str_cat_s(fnb, szfnb, fn, NULL)) { dk4path_correct_sep(fnb); dk4uc2l_i_process_one_full_file_pass1( ulptr, fnb, fn, bptr, app, dmsg, szdmsg ); } else { *bptr = 0; /* ERROR pth and/or fn too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { *bptr = 0; /* ERROR: pth too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { *bptr = 0; /* ERROR: pth too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { dk4uc2l_i_process_one_full_file_pass1(ulptr,fn,fn,bptr,app,dmsg,szdmsg); } $? "- dk4uc2l_i_process_one_file_pass1" } /** First pass to gather information which Unicode position is configured in which data file. This function is run while creating a new conversion structure to fill the range structures so we can later find a file for a Unicode position. If this function fails, the conversion structure is considered unusable. The function fails only on memory allocation failures. Syntax errors in translation files are reported as errors through app, but the function indicates success. @param ulptr Conversion structure. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk4uc2l_i_pass1( dk4_uc2l_t *ulptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { const dkChar *fn = NULL; const dkChar *pth = NULL; dk4_dir_t *pdir = NULL; int back = 0; $? "+ dk4uc2l_i_pass1" pdir = dk4dir_open_app(ulptr->dname, 0, app); if (NULL != pdir) { pth = dk4dir_get_path(pdir); back = 1; do { fn = dk4dir_next_file(pdir); if (NULL != fn) { if (-1 < dk4uc2l_i_find_suffix_index(fn)) { dk4uc2l_i_process_one_file_pass1( ulptr, pth, fn, &back, app, dmsg, szdmsg ); } } } while (NULL != fn); dk4dir_close(pdir); } else { $? "! failed to open dir" /* ERROR: Failed to open directory (already reported) */ ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; } $? "- dk4uc2l_i_pass1 %d", back return back; } /** Handler to process a line during pass 1. @param obj Object to use and modify during processing. @param line Current text line to process. @param lineno Current line number. @param erp Error report, may be NULL. @return DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort. */ static int dk4uc2l_handler_pass2( void *obj, char *line, dk4_um_t lineno, dk4_er_t * DK4_ARG_UNUSED(erp) ) { dk4_er_t er; char *pkgn[16]; handler_object_t *lho = NULL; const char *pe = NULL; char *p1 = NULL; char *p2 = NULL; char *p3 = NULL; char *p4 = NULL; dk4_uc2l_range_t *rptr = NULL; dk4_uc2l_pkg_t *pptr = NULL; size_t ind = 0; size_t numpkg = 0; size_t i = 0; unsigned long ul = 0UL; dk4_c32_t c32 = (dk4_c32_t)0UL; int back = DK4_TSP_RES_OK; int res = 0; int adding = 0; unsigned char fex = 0; unsigned char feval = 0; DK4_UNUSED_ARG(erp) $? "+ dk4uc2l_handler_pass2" #if TRACE_DEBUG dk4str8_delnl(line); $? ". line=\"%!8s\"", line #endif /* Line handler object */ lho = (handler_object_t *)obj; dk4app_set_log_source_line(lho->app, lineno); /* Find start of line, ignore empty lines and comments */ p1 = dk4str8_start(line, NULL); if (NULL == p1) { $? ". ignore empty line" goto finished; } if ('#' == *p1) { $? ". ignore comment" goto finished; } /* Retrieve character number */ p2 = dk4str8_next(p1, NULL); res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, NULL); if (0 == res) { $? "! failed to retrieve character number" /* WARNING: Syntax, no number. Already reported in pass 1. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; goto finished; } c32 = (dk4_c32_t)ul; /* Find and check range structure, attempt cached range pointer first */ if (NULL != lho->rpc) { if ((lho->rpc->start <= c32) && (c32 <= lho->rpc->end)) { rptr = lho->rpc; } } if (NULL == rptr) { rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(lho->ulptr->i_ranges,&c32,1); } if (NULL == rptr) { $? "! rptr" /* ERROR: No range found. Already reported in pass 1. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; back = DK4_TSP_RES_FATAL; goto finished; } if (0 != dk4str_cmp(lho->file->fn, rptr->file->fn)) { /* ERROR: Not owned by current file. Already reported in pass 1. */ $? "! redefinition" lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; goto finished; } /* Initialize range structure (allocate memory) if not yet done */ if (0x00 == rptr->ia) { if (0 == dk4uc2l_i_init_range(rptr, NULL)) { /* ERROR: Memory */ dk4app_log_base1(lho->app, DK4_LL_ERROR, 90); $? "! memory" lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; back = DK4_TSP_RES_FATAL; goto finished; } rptr->ia = 0x01; } /* Find index */ ind = (size_t)(c32 - rptr->start); /* Check whether character already defined */ if (NULL != rptr->lno) { if ((dk4_um_t)0UL != (rptr->lno)[ind]) { /* ERROR: Redefinition. Already reported in pass 1. */ $? "! redefinition" lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; goto finished; } else { (rptr->lno)[ind] = lineno; } } /* Traverse all strings in line */ p1 = p2; while (NULL != p1) { $? ". p1=\"%!8s\"", p1 p2 = dk4str8_next(p1, NULL); p3 = dk4str8_chr(p1, '='); if (NULL != p3) { *(p3++) = '\0'; p3 = dk4str8_start(p3, NULL); if (NULL != p3) { $? ". p1=\"%!8s\" p3=\"%!8s\"", p1, p3 res = dk4uc2l_i_keyword_index(p1); switch (res) { case 0 : { $? ". both=..." if (NULL != rptr->both) { if (NULL == (rptr->both)[ind]) { (rptr->both)[ind] = dk4str8_dup(p3, NULL); if (NULL == (rptr->both)[ind]) { /* ERROR: Memory */ dk4app_log_base1(lho->app, DK4_LL_ERROR, 90); $? "! memory" lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { $? "! bug" /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { $? "! rptr->both" /* ERROR: Memory. Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 1 : { $? ". text=..." if (NULL != rptr->text) { if (NULL == (rptr->text)[ind]) { (rptr->text)[ind] = dk4str8_dup(p3, NULL); if (NULL == (rptr->text)[ind]) { /* ERROR: Memory */ dk4app_log_base1(lho->app, DK4_LL_ERROR, 90); $? "! memory" lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { $? "! bug" /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { $? "! rptr->text" /* ERROR: Memory Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 2 : { $? ". math=..." if (NULL != rptr->math) { if (NULL == (rptr->math)[ind]) { (rptr->math)[ind] = dk4str8_dup(p3, NULL); if (NULL == (rptr->math)[ind]) { /* ERROR: Memory */ dk4app_log_base1(lho->app, DK4_LL_ERROR, 90); $? "! memory" lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { $? "! bug" /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { $? "! rptr->math" /* ERROR: Memory. Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 3 : { $? ". encoding=..." if (NULL != rptr->fenc) { adding = 1; feval = 0x00; if ('!' == *p3) { adding = 0; p3++; feval = DK4_UC2L_FONT_ENCODING_ALL; } while (NULL != p3) { p4 = dk4str8_chr(p3, ','); if (NULL != p4) { *(p4++) = '\0'; } fex = dk4uc2l_font_encoding_from_name(p3); if (0x00 != fex) { if (0 != adding) { feval |= fex; } else { feval &= (~(fex)); } } else { $? "! illegal encoding \"%!8s\"", p3 /* ERROR: Illegal encoding name */ dk4app_log_1( lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 8 ); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } p3 = p4; } (rptr->fenc)[ind] = feval; } else { /* ERROR: Memory. Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 4 : { $? ". packages=..." if (NULL != rptr->pkgs) { if (NULL == (rptr->pkgs)[ind]) { dk4error_init(&er); numpkg = dk4str8_tokenize( pkgn, 16, p3, ",", &er ); if (0 < numpkg) { (rptr->pkgs)[ind] = dk4mem_new(dk4_uc2l_pkg_p,(numpkg+1),NULL); if (NULL != (rptr->pkgs)[ind]) { for (i = 0; i <= numpkg; i++) { ((rptr->pkgs)[ind])[i] = NULL; } for (i = 0; i < numpkg; i++) { pptr = (dk4_uc2l_pkg_t *)dk4sto_it_find_like( lho->ulptr->i_pkgs, pkgn[i], 1 ); if (NULL != pptr) { ((rptr->pkgs)[ind])[i] = pptr; } else { pptr = dk4uc2l_i_create_pkg( lho->ulptr->s_pkgs, pkgn[i] ); if (NULL != pptr) { ((rptr->pkgs)[ind])[i] = pptr; } else { $? "! memory" /* ERROR: Memory */ dk4app_log_base1( lho->app,DK4_LL_ERROR,90 ); lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } } } else { $? "! memory" /* ERROR: Memory */ dk4app_log_base1( lho->app, DK4_LL_ERROR, 90 ); lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { $? "! empty list" dk4app_log_1( lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 9 ); } } else { $? "! bug" /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { $? "! memory" /* ERROR: Memory. Already reported during range initalization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; default : { $? "! illegal key \"%!8s\"", p1 /* ERROR: Illegal key name */ dk4app_log_1( lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 10 ); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } break; } p1 = p2; } else { $? "! not key=value" /* ERROR: Syntax, not a key=value */ dk4app_log_1(lho->app,lho->msgs,lho->szmsgs,DK4_LL_ERROR,11); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; p1 = NULL; } } else { $? "! not key=value" /* ERROR: Syntax, not a key=value */ dk4app_log_1(lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 11); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; p1 = NULL; } } finished: $? "- dk4uc2l_handler_pass2 %d", back return back; } /** Load one data file. @param ulptr Conversion structure. @param fptr File to load. @param app Application structure for diagnostics. @param dmsg Localized message texts. @param szdmsg Number of elements in dmsg array. */ static void dk4uc2l_load_data_file( dk4_uc2l_t *ulptr, dk4_uc2l_file_t *fptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { dkChar fnb[DK4_MAX_PATH]; char lnb[256]; handler_object_t ho; dk4_er_t er_en; dk4_er_t er_pr; dk4_tsp08_t tsp08; dk4_stream_t *rstrm = NULL; const dkChar *oldsourcefile = NULL; dk4_um_t oldsourceline = (dk4_um_t)0UL; size_t fnbsz = DK4_SIZEOF(fnb,dkChar); size_t szlnb = sizeof(lnb); int res; int cc; char c; $? "+ dk4uc2l_load_data_file \"%!ds\"", fptr->fn /* Save old source file and line, set new source file */ oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, fptr->fn); dk4app_set_log_source_line(app, (dk4_um_t)0UL); /* Initialize handler object */ ho.ulptr = ulptr; ho.s_ra = NULL; ho.i_ra = NULL; ho.file = fptr; ho.rpc = NULL; ho.app = app; ho.msgs = dmsg; ho.szmsgs = szdmsg; ho.e_d = 0; ho.e_e = 0; ho.e_p = 0; dk4error_init(&er_en); dk4error_init(&er_pr); /* Save source file name and line number */ /* Each file should be loaded only once */ if (0x00 != fptr->loaded) { goto finished; } fptr->loaded = 0x01; /* Construct full path name */ if (0 == dk4str_cpy_s(fnb, fnbsz, ulptr->dname, NULL)) { /* ERROR: Directory name too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname); ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } if (0 == dk4str_cat_s(fnb, fnbsz, dk4uc2l_kwnl[7], NULL)) { /* ERROR: Directory name too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname); ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } if (0 == dk4str_cat_s(fnb, fnbsz, fptr->fn, NULL)) { /* ERROR: Directory name too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname); ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } dk4path_correct_sep(fnb); dk4app_set_log_source_file(app, fnb); /* Open reader stream */ rstrm = dk4stream_open_file_reader(fnb, NULL); if (NULL == rstrm) { /* ERROR: Failed to read file */ dk4app_log_3(app, dmsg, szdmsg, DK4_LL_ERROR, 6, 7, fnb); ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; goto finished; } /* Initialize text processing */ res = dk4tsp08_setup_line( &tsp08, (void *)(&ho), dk4uc2l_handler_pass2, lnb, szlnb, DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, NULL ); if (0 == res) { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); goto finished; } /* Process contents */ do { cc = 0; res = dk4stream_c8_read_byte(&c, rstrm, NULL); if (0 < res) { cc = 1; res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c); switch (res) { case DK4_TSP_RES_ERROR : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); dk4error_init(&er_en); dk4error_init(&er_pr); } break; case DK4_TSP_RES_FATAL : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); dk4error_init(&er_en); dk4error_init(&er_pr); goto finished; } break; } } } while (0 < cc); /* Finish text processing */ res = dk4tsp08_finish(&tsp08); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; dk4tsp08_get_errors(&er_en, &er_pr, &tsp08); dk4uc2l_report_errors( app, &ho, &er_en, &er_pr, dmsg, szdmsg ); } break; } /* Clean up */ finished: if (NULL != rstrm) { dk4stream_close(rstrm, NULL); } /* Restore source file name and line number */ dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); $? "- dk4uc2l_load_data_file" } /** Second pass to load all data files immediately. @param ulptr Conversion structure. @param app Application structure for diagnostics, may be NULL. @param dmsg Localized message texts. @param szdmsg Number of elements in dmsg array. @return 1 on success, 0 on error. */ static int dk4uc2l_i_pass2( dk4_uc2l_t *ulptr, dk4_app_t *app, const dkChar * const *dmsg, size_t szdmsg ) { dk4_sto_it_t *i_files = NULL; dk4_uc2l_file_t *fptr; int back = 0; /* Create iterator through files */ i_files = dk4sto_it_open(ulptr->s_files, NULL); if (NULL == i_files) { goto finished; } back = 1; dk4sto_it_reset(i_files); do { fptr = (dk4_uc2l_file_t *)dk4sto_it_next(i_files); if (NULL != fptr) { dk4uc2l_load_data_file( ulptr, fptr, app, dmsg, szdmsg ); } } while (NULL != fptr); /* Clean up */ finished: if (NULL != i_files) { dk4sto_it_close(i_files); } return back; } /** Open Unicode to LaTeX conversion structure with application support. @param dn Directory name containing the translation files. @param app Application structure for diagnostics. @param la Flag: Load all data files immediately. @param dmsg Localized messages array. @param szdmsg Localized messages array size. @return Valid pointer on success (use dk4uc2l_close() to release resources after use), NULL on error. */ static dk4_uc2l_t * dk4uc2l_i_open_app( const dkChar *dn, dk4_app_t *app, int la, const dkChar * const *dmsg, size_t szdmsg ) { dk4_er_t er; dk4_uc2l_t *back = NULL; $? "+ dk4uc2l_i_open_app \"%!ds\"", TR_STR(dn) dk4error_init(&er); back = dk4uc2l_i_new(dn, &er); if (NULL != back) { if (0 == dk4uc2l_i_pass1(back, app, dmsg, szdmsg)) { dk4uc2l_close(back); back = NULL; } else { if (0 != la) { if (0 == dk4uc2l_i_pass2(back, app, dmsg, szdmsg)) { dk4uc2l_close(back); back = NULL; } } } } else { /* ERROR: Memory */ dk4app_log_base1(app, DK4_LL_ERROR, 90); } $? "- dk4uc2l_i_open_app %d", TR_IPTR(back) return back; } dk4_uc2l_t * dk4uc2l_open_app_ex1(const dkChar *dn, dk4_app_t *app, int la) { dkChar fnb[DK4_MAX_PATH]; const dkChar * const *dmsg = NULL; dk4_uc2l_t *back = NULL; size_t i; size_t szdmsg = 0; const size_t szfnb = DK4_SIZEOF(fnb,dkChar); int toolo = 0; $? "+ dk4uc2l_open_app \"%!ds\"", TR_STR(dn) if (NULL != app) { szdmsg = dk4app_string_table_size(dk4uc2l_kw_def); dmsg = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def); /* Retrieve fallback from preferences */ if (NULL == dn) { if (0 != dk4app_pref_get(fnb, szfnb, app, dk4uc2l_kwnl[0], 0)) { dk4path_correct_sep(fnb); if (0 != dk4file_is_directory(fnb, NULL)) { dn = fnb; } else { /* ERROR: Not a directory */ dk4app_log_base3(app, DK4_LL_ERROR, 152, 153, fnb); } } } /* Retrieve builtin fallbacks */ if (NULL == dn) { for (i = 1; ((i < 4) && (NULL == dn)); i++) { if (0 != dk4str_cpy_s(fnb, szfnb, app->dir_share, NULL)) { if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[i], NULL)) { dk4path_correct_sep(fnb); if (0 != dk4file_is_directory(fnb, NULL)) { dn = fnb; } } else { toolo = 1; } } else { toolo = 1; } } } if (NULL != dn) { if (0 != dk4file_is_directory(dn, NULL)) { back = dk4uc2l_i_open_app(dn, app, la, dmsg, szdmsg); } else { /* ERROR: Not a directory */ dk4app_log_base3(app, DK4_LL_ERROR, 152, 153, dn); } } else { if (0 != toolo) { /* ERROR: Shared directory name too long! */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, app->dir_share); } else { /* ERROR: No directory found */ dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 15); } } } else { back = dk4uc2l_open(dn, NULL); } $? "- dk4uc2l_open_app %d", TR_IPTR(back) return back; } dk4_uc2l_t * dk4uc2l_open_app(const dkChar *dn, dk4_app_t *app) { return (dk4uc2l_open_app_ex1(dn, app, 0)); } dk4_uc2l_t * dk4uc2l_open_from_app(dk4_app_t *app) { return (dk4uc2l_open_app(NULL, app)); } dk4_uc2l_t * dk4uc2l_open_from_app_ex1(dk4_app_t *app, int la) { return (dk4uc2l_open_app_ex1(NULL, app, la)); } static const char * dk4uc2l_i_find_app(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_app_t *app) { dk4_uc2l_range_t *rptr; dk4_uc2l_pkg_t **pkgpp; dk4_uc2l_file_t *fptr; const char *back = NULL; const dkChar * const *dmsg; size_t ind; size_t szdmsg; size_t blgt; int res; $? "+ dk4uc2l_i_find_app 0x%lx", (unsigned long)c #if DK4_USE_ASSERT assert(NULL != ulptr); #endif /* Attempt direct output */ if (0 != dk4uc2lat_direct(c)) { ulptr->buf[0] = (char)c; ulptr->buf[1] = '\0'; back = &(ulptr->buf[0]); goto finished; } /* Attempt data loaded from file */ rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(ulptr->i_ranges, &c, 1); if (NULL != rptr) { fptr = rptr->file; if (0x00 == fptr->loaded) { szdmsg = dk4app_string_table_size(dk4uc2l_kw_def); dmsg = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def); dk4uc2l_load_data_file(ulptr, fptr, app, dmsg, szdmsg); } ind = (size_t)(c - rptr->start); if (0 != mm) { if (NULL != rptr->math) { back = (rptr->math)[ind]; } } else { if (NULL != rptr->text) { back = (rptr->text)[ind]; } } if (NULL == back) { if (NULL != rptr->both) { back = (rptr->both)[ind]; } } if (NULL != back) { if (NULL != rptr->pkgs) { pkgpp = (rptr->pkgs)[ind]; if (NULL != pkgpp) { while (NULL != *pkgpp) { (*(pkgpp++))->used = 0x01; } } } if (NULL != rptr->fenc) { ulptr->fallowed &= (rptr->fenc)[ind]; } goto finished; } } /* Attempt to use UTF-8 encoded or ASCII data directly */ if (0 == mm) { if (0x00 != ulptr->utf8allowed) { blgt = 15; res = dk4utf8_encode( (unsigned char *)(&(ulptr->buf[0])), &blgt, c, NULL ); if (0 != res) { ulptr->buf[blgt] = '\0'; back = &(ulptr->buf[0]); } else { /* ##### ERROR: UTF-8 encoding failed */ } } else { if (dkC32(0x00000100) > c) { ulptr->buf[0] = (char)c; ulptr->buf[1] = '\0'; back = &(ulptr->buf[0]); } } } finished: if (NULL != back) { /* ERROR: No LaTeX encoding found for ... The calling application should attempt to recover from this error or report it. */ } $? "- dk4uc2l_i_find_app %d", TR_IPTR(back) return back; } const char * dk4uc2l_find_app(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_app_t *app) { const char *back = NULL; $? "+ dk4uc2l_find_app 0x%lx", (unsigned long)c #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { if (NULL != app) { back = dk4uc2l_i_find_app(ulptr, c, mm, app); } else { back = dk4uc2l_find(ulptr, c, mm, NULL); } } $? "- dk4uc2l_find_app %d", TR_IPTR(back) return back; } /* ##### untested */ static void dk4uc2l_putc32_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, dk4_c32_t c32, int *pmm, int *pback, dk4_app_t *app ) { dkChar nb[16*sizeof(dk4_um_t)]; dk4_er_t er; const dkChar * const *dmsg; const char *le = NULL; size_t padsz = 8; size_t szdmsg = 0; size_t sznb = DK4_SIZEOF(nb,dkChar); $? "+ dk4uc2l_putc32_app 0x%08lx", UL(c32) le = dk4uc2l_find(ulptr, c32, 0, NULL); if (NULL != le) { if (0 != *pmm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { *pback = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } *pmm = 0; } dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, le, &er)) { *pback = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } else { dk4error_init(&er); le = dk4uc2l_find(ulptr, c32, 1, &er); if (NULL != le) { if (0 == *pmm) { if (0 == dk4stream_write_char_string(wstrm,dk4uc2l_mm[0],&er)) { *pback = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } *pmm = 1; } dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, le, &er)) { *pback = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } else { *pback = 0; /* ERROR: Not found */ szdmsg = dk4app_string_table_size(dk4uc2l_kw_def); dmsg = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def); if ((dk4_c32_t)0xFFUL < c32) { if ((dk4_c32_t)0xFFFFUL < c32) { if ((dk4_c32_t)0xFFFFFFUL < c32) { padsz = 8; } else { padsz = 6; } } else { padsz = 4; } } else { padsz = 2; } if (0 != dk4ma_write_hex_unsigned(nb, sznb, c32, padsz, NULL)) { dk4app_log_3(app, dmsg, szdmsg, DK4_LL_ERROR, 31, 32, nb); } #if TRACE_DEBUG else { $? "! Bug, should not happen" } #endif } } $? "- dk4uc2l_putc32_app" } /* ##### untested */ int dk4uc2l_string_c32_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c32_t *str, dk4_app_t *app ) { dk4_er_t er; int back = 0; int mm = 0; $? "+ dk4uc2l_string_c32_app" #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { goto finished; } /* Process string */ back = 1; while (dkC32(0) != *str) { dk4uc2l_putc32_app(wstrm, ulptr, *(str++), &mm, &back, app); } /* Finalize math mode if necessary */ if (0 != mm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { back = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } finished: $? "- dk4uc2l_string_c32_app %d", back return back; } /* ##### untested */ int dk4uc2l_string_c16_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c16_t *str, dk4_app_t *app ) { dk4_utf16_decoder_t dec; dk4_er_t er; dk4_c32_t c32; int mm = 0; int back = 0; int err = 0; $? "+ dk4uc2l_string_c16_app" #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { goto finished; } /* Process string */ back = 1; dk4utf16_init(&dec); while ((dkC16(0) != *str) && (0 == err)) { switch (dk4utf16_add(&dec, *(str++))) { case DK4_EDSTM_FINISHED : { c32 = dk4utf16_get(&dec); dk4utf16_init(&dec); dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app); } break; case DK4_EDSTM_ERROR : { err = 1; back = 0; /* ##### ERROR: Decoding failed */ } break; } } if (0 == err) { if (0 == dk4utf16_is_empty(&dec)) { back = 0; /* ##### ERROR: Decoding failed */ } } /* Finalize math mode if necessary */ if (0 != mm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { back = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } finished: $? "- dk4uc2l_string_c16_app %d", back return back; } /* ##### untested */ int dk4uc2l_string_utf8_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ) { dk4_utf8_decoder_t dec; dk4_er_t er; dk4_c32_t c32; int back = 0; int mm = 0; int err = 0; $? "+ dk4uc2l_string_utf8_app" #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { goto finished; } /* Process string */ back = 1; dk4utf8_init(&dec); while(('\0' != *str) && (0 == err)) { switch (dk4utf8_add(&dec, (unsigned char)(*(str++)))) { case DK4_EDSTM_FINISHED : { c32 = dk4utf8_get(&dec); dk4utf8_init(&dec); dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app); } break; case DK4_EDSTM_ERROR : { err = 1; back = 0; /* ##### ERROR: Decoding failed */ } break; } } if (0 == err) { if (0 == dk4utf8_is_empty(&dec)) { back = 0; /* ##### ERROR: Decoding failed */ } } /* Finalize math mode if necessary */ if (0 != mm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { back = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } finished: $? "- dk4uc2l_string_utf8_app %d", back return back; } /* ##### untested */ int dk4uc2l_string_ansi_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ) { dk4_er_t er; dk4_c32_t c32; int back = 0; int mm = 0; $? "+ dk4uc2l_string_ansi_app" #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { goto finished; } /* Process string */ back = 1; while ('\0' != *str) { if (0 != dk4ansi_decode(&c32, (unsigned char)(*(str++)))) { dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app); } else { back = 0; /* ##### ERROR: Decoding failed */ } } /* Finalize math mode if necessary */ if (0 != mm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { back = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } finished: $? "- dk4uc2l_string_ansi_app %d", back return back; } /* ##### untested */ int dk4uc2l_string_ascii_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_app_t *app ) { dk4_er_t er; dk4_c32_t c32; int back = 0; int mm = 0; $? "+ dk4uc2l_string_ascii_app" #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { goto finished; } /* Process string */ back = 1; while ('\0' != *str) { c32 = (dk4_c32_t)((unsigned char)(*(str++))); dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app); } /* Finalize math mode if necessary */ if (0 != mm) { dk4error_init(&er); if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) { back = 0; /* ERROR: Write failed */ dk4app_log_base1(app, DK4_LL_ERROR, 128); } } finished: $? "- dk4uc2l_string_ascii_app %d", back return back; } int dk4uc2l_string_c8_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, int ie, dk4_app_t *app ) { #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif switch (ie) { case DK4_ENCODING_UTF8 : { return (dk4uc2l_string_utf8_app(wstrm, ulptr, str, app)); } break; case DK4_ENCODING_WIN1252 : { return (dk4uc2l_string_ansi_app(wstrm, ulptr, str, app)); } break; default : { return (dk4uc2l_string_ascii_app(wstrm, ulptr, str, app)); } break; } } /* ##### untested */ int dk4uc2l_string_dk_app( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dkChar *str, #if DK4_CHAR_SIZE > 1 int DK4_ARG_UNUSED(ie), #else int ie, #endif dk4_app_t *app ) { #if DK4_CHAR_SIZE > 1 DK4_UNUSED_ARG(ie) #endif #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 return (dk4uc2l_string_c32_app(wstrm, ulptr, str, app)); #else return (dk4uc2l_string_c16_app(wstrm, ulptr, str, app)); #endif #else return (dk4uc2l_string_c8_app(wstrm, ulptr, str, ie, app)); #endif } /* vim: set ai sw=4 ts=4 : */