/* Copyright (C) 2015-2021, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk4uc2l.ctr */ /** @file dk4uc2l.c The dk4uc2l module. */ #include "dk4conf.h" #include #if DK4_HAVE_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef UC2L_H_INCLUDED #include #endif #if DK4_HAVE_ASSERT_H #ifndef ASSERT_H_INCLUDED #include #define ASSERT_H_INCLUDED 1 #endif #endif #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. */ } handler_object_t; /** File name suffixes to process. */ static const dkChar * const dk4uc2l_suffixes[] = { /* 0 */ dkT(".t2l"), /* 1 */ dkT(".t2l.gz"), /* 2 */ dkT(".t2l.bz2"), NULL }; /** Keywords allowed in a data line. */ static const char * const dk4uc2l_keywords[] = { /* 0 */ "b$oth", /* 1 */ "t$ext", /* 2 */ "m$ath", /* 3 */ "e$ncoding", /* 4 */ "p$ackages", NULL }; /** Font encoding names. */ static const char * const dk4uc2l_font_encodings[] = { /* 0 */ "ot1", /* 1 */ "t1", /* 2 */ "t4", /* 3 */ "t5", NULL }; /** Subdirectory names. */ static const dkChar * const dk4uc2l_kwnl[] = { /* 0 */ dkT("/dktools/charmap"), /* 1 */ dkT("/dk4app/charmap"), /* 2 */ dkT("/dk3app/charmap"), /* 3 */ dkT("/"), NULL }; /** Constant text strings for recommendations. */ static const char * const dk4uc2l_kw8[] = { /* 0 */ "% Font encodings:", /* 1 */ "% Recommended package: ", /* 2 */ " ot1", /* 3 */ " t1", /* 4 */ " t4", /* 5 */ " t5", NULL }; /** Opening and closing tag for math mode. */ static const char * const dk4uc2l_mm[] = { "\\(", "\\)" }; /** Number of elements in dk4uc2l_suffixes array. */ static const size_t sz_suffixes = DK4_SIZEOF(dk4uc2l_suffixes,DK4_PDKCHAR) - 1; /** Compare two LaTeX package structures. @param l Left pointer, always a package structure. @param r Right pointer. @param cr Comparison criteria: 0 if r is a package pointer, 1 if r is just a package name string. @return Comparison result: 1 if l>r, 0 if l==r, -1 if lpn, (const char *)r); } break; default: { pr = (const dk4_uc2l_pkg_t *)r; back = strcmp(pl->pn, pr->pn); } break; } if (-1 > back) back = -1; if ( 1 < back) back = 1; } else { back = 1; } } else { if (NULL != r) { back = -1; } } return back; } /** Compare two file information structures. @param l Left pointer, always a file information structure. @param r Right pointer. @param cr Comparison criteria: 0 if the right pointer is a file information structure pointer, 1 if the right pointer is a file name string. @return Comparison result: 0 if file names are equal, -1 if lr. */ static int dk4uc2l_file_compare(const void *l, const void *r, int cr) { const dk4_uc2l_file_t *pl; const dk4_uc2l_file_t *pr; int back = 0; if (NULL != l) { if (NULL != r) { pl = (const dk4_uc2l_file_t *)l; switch (cr) { case 1: { back = dk4str_pathcmp(pl->fn, (const dkChar *)r); } break; default: { pr = (const dk4_uc2l_file_t *)r; back = dk4str_pathcmp(pl->fn, pr->fn); } break; } if (-1 > back) { back = -1; } if ( 1 < back) { back = 1; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } return back; } /** Compare two range informations or a range information against a character. @param l Left pointer, always a range information structure. @param r Right pointer. @param cr Comparison criteria: 0 if the right pointer is a range information strucutre, 1 if the right pointer is a pointer to a dk4_c32_t. @return Comparison result: -1 if lr. */ int dk4uc2l_i_range_compare(const void *l, const void *r, int cr) { const dk4_uc2l_range_t *pl; const dk4_uc2l_range_t *pr; const dk4_c32_t *pc; int back = 0; if (NULL != l) { if (NULL != r) { pl = (const dk4_uc2l_range_t *)l; switch (cr) { case 1: { pc = (const dk4_c32_t *)r; if (pl->start > *pc) { back = 1; } else { if (pl->end < *pc) { back = -1; } } } break; default: { pr = (const dk4_uc2l_range_t *)r; if (pl->start < pr->start) { back = -1; } else { if (pl->start > pr->start) { back = 1; } } } break; } } else { back = 1; } } else { if (NULL != r) { back = -1; } } return back; } int dk4uc2l_i_suffix_index_supported(int i) { int back = 1; switch (i) { case 1: { #if !DK4_HAVE_ZLIB_H back = 0; #endif } break; case 2: { #if !DK4_HAVE_BZLIB_H back = 0; #endif } break; } return back; } int dk4uc2l_i_find_suffix_index(const dkChar *fn) { size_t sz = 0; size_t i = 0; size_t susz = 0; int back = -1; if (NULL != fn) { sz = dk4str_len(fn); for (i = 0; ((i < sz_suffixes) && (0 > back)); i++) { susz = dk4str_len(dk4uc2l_suffixes[i]); if (sz > susz) { if (0 == dk4str_pathcmp(&(fn[sz - susz]), dk4uc2l_suffixes[i])) { back = (int)i; i = sz_suffixes; } } } } return back; } void dk4uc2l_i_close_file(dk4_uc2l_file_t *fptr) { if (NULL != fptr) { dk4mem_release(fptr->fn); fptr->loaded = 0x00; dk4mem_free(fptr); } } dk4_uc2l_file_t * dk4uc2l_i_open_file(const dkChar *fn, dk4_er_t *erp) { dk4_uc2l_file_t *back = NULL; if (NULL != fn) { back = dk4mem_new(dk4_uc2l_file_t,1,erp); if (NULL != back) { back->loaded = 0x00; back->fn = dk4str_dup(fn, erp); if (NULL == back->fn) { dk4mem_free(back); back = NULL; } } #if TRACE_DEBUG else { } #endif } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } void dk4uc2l_i_close_pkg(dk4_uc2l_pkg_t *pptr) { if (NULL != pptr) { dk4mem_release(pptr->pn); pptr->used = 0x00; dk4mem_free(pptr); } } dk4_uc2l_pkg_t * dk4uc2l_i_open_pkg(const char *pn, dk4_er_t *erp) { dk4_uc2l_pkg_t *back = NULL; if (NULL != pn) { back = dk4mem_new(dk4_uc2l_pkg_t,1,erp); if (NULL != back) { back->used = 0x00; back->pn = dk4str8_dup(pn, erp); if (NULL == back->pn) { dk4mem_free(back); back = NULL; } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { } #endif } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } void dk4uc2l_i_close_range(dk4_uc2l_range_t *rptr) { dk4_er_t er; /* Error report to detect numeric overflow */ unsigned long n; /* Number of elements in range */ size_t nn; /* Size_t version of n */ size_t i; /* Traverse all elements */ if (NULL != rptr) { #if TRACE_DEBUG if (NULL != rptr->file) { if (NULL != rptr->file->fn) { } } #endif dk4error_init(&er); n = dk4ma_ulong_sub(rptr->end, rptr->start, &er); n = dk4ma_ulong_add(n, 1UL, &er); #if 0 if ((DK4_E_NONE == er.ec) && ((dk4_um_t)n <= (dk4_um_t)(SIZE_MAX))) #endif if ((DK4_E_NONE == er.ec) && (dk4ma_um_isgeq(SIZE_MAX, n))) { nn = (size_t)n; if (NULL != rptr->both) { for (i = 0; i < nn; i++) { dk4mem_release((rptr->both)[i]); } dk4mem_free(rptr->both); rptr->both = NULL; } if (NULL != rptr->text) { for (i = 0; i < nn; i++) { dk4mem_release((rptr->text)[i]); } dk4mem_free(rptr->text); rptr->text = NULL; } if (NULL != rptr->math) { for (i = 0; i < nn; i++) { dk4mem_release((rptr->math)[i]); } dk4mem_free(rptr->math); rptr->math = NULL; } if (NULL != rptr->pkgs) { for (i = 0; i < nn; i++) { dk4mem_release((rptr->pkgs)[i]); } dk4mem_free(rptr->pkgs); rptr->pkgs = NULL; } if (NULL != rptr->fenc) { dk4mem_free(rptr->fenc); rptr->fenc = NULL; } if (NULL != rptr->lno) { dk4mem_free(rptr->lno); rptr->lno = NULL; } } rptr->file = NULL; rptr->start = (dk4_c32_t)0UL; rptr->end = (dk4_c32_t)0UL; rptr->ia = 0x00; dk4mem_free(rptr); } } int dk4uc2l_i_init_range( dk4_uc2l_range_t *rptr, dk4_er_t *erp ) { dk4_er_t er; char **ppchr; dk4_uc2l_pkg_pp *pppkg; unsigned char *puc; dk4_um_t *pum; size_t sznum = 0; size_t i = 0; unsigned long num = 0UL; int back = 0; /* Avoid second initialization */ if (0x00 != rptr->ia) { back = 1; goto finished; } /* Find number of elements */ dk4error_init(&er); num = dk4ma_ulong_add( dk4ma_ulong_sub( (unsigned long)(rptr->end), (unsigned long)(rptr->start), &er ), 1UL, &er ); if (DK4_E_NONE != er.ec) { dk4error_copy(erp, &er); goto finished; } #if 0 if ((dk4_um_t)(SIZE_MAX) >= (dk4_um_t)num) #endif if (0 != dk4ma_um_isgeq(SIZE_MAX, num)) { sznum = (size_t)num; } else { dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW); goto finished; } /* both */ if (NULL == rptr->both) { rptr->both = dk4mem_new(DK4_PCHAR,sznum,erp); if (NULL != rptr->both) { ppchr = rptr->both; for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; } } else { goto finished; } } /* text */ if (NULL == rptr->text) { rptr->text = dk4mem_new(DK4_PCHAR,sznum,erp); if (NULL != rptr->text) { ppchr = rptr->text; for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; } } else { goto finished; } } /* math */ if (NULL == rptr->math) { rptr->math = dk4mem_new(DK4_PCHAR,sznum,erp); if (NULL != rptr->math) { ppchr = rptr->math; for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; } } else { goto finished; } } /* pkgs */ if (NULL == rptr->pkgs) { rptr->pkgs = dk4mem_new(dk4_uc2l_pkg_pp,sznum,erp); if (NULL != rptr->pkgs) { pppkg = rptr->pkgs; for (i = 0; i < sznum; i++) { *(pppkg++) = NULL; } } else{ goto finished; } } /* fenc */ if (NULL == rptr->fenc) { rptr->fenc = dk4mem_new(unsigned char,sznum,erp); if (NULL != rptr->fenc) { puc = rptr->fenc; for (i = 0; i < sznum; i++) { *(puc++) = 0xFF; } } else { goto finished; } } /* lno */ if (NULL == rptr->lno) { rptr->lno = dk4mem_new(dk4_um_t,sznum,erp); if (NULL != rptr->lno) { pum = rptr->lno; for (i = 0; i < sznum; i++) { *(pum++) = (dk4_um_t)0UL; } } else { goto finished; } } /* Success */ back = 1; /* Return */ finished: return back; } dk4_uc2l_range_t * dk4uc2l_i_open_range( dk4_c32_t c32, dk4_uc2l_file_t *fptr, dk4_er_t *erp ) { dk4_uc2l_range_t *back = NULL; if (NULL != fptr) { back = dk4mem_new(dk4_uc2l_range_t,1,erp); if (NULL != back) { back->file = fptr; back->both = NULL; back->text = NULL; back->math = NULL; back->pkgs = NULL; back->fenc = NULL; back->lno = NULL; back->start = back->end = c32; back->ia = 0x00; } #if TRACE_DEBUG else { } #endif } else { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); } return back; } void dk4uc2l_close(dk4_uc2l_t *ulptr) { dk4_uc2l_pkg_t *pptr; dk4_uc2l_file_t *fptr; dk4_uc2l_range_t *rptr; #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { dk4mem_release(ulptr->dname); if (NULL != ulptr->s_ranges) { if (NULL != ulptr->i_ranges) { dk4sto_it_reset(ulptr->i_ranges); do { rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ulptr->i_ranges); if (NULL != rptr) { dk4uc2l_i_close_range(rptr); } } while (NULL != rptr); dk4sto_it_close(ulptr->i_ranges); } dk4sto_close(ulptr->s_ranges); } ulptr->s_ranges = NULL; ulptr->i_ranges = NULL; if (NULL != ulptr->s_files) { if (NULL != ulptr->i_files) { dk4sto_it_reset(ulptr->i_files); do { fptr = (dk4_uc2l_file_t *)dk4sto_it_next(ulptr->i_files); if (NULL != fptr) { dk4uc2l_i_close_file(fptr); } } while (NULL != fptr); dk4sto_it_close(ulptr->i_files); } dk4sto_close(ulptr->s_files); } ulptr->s_files = NULL; ulptr->i_files = NULL; if (NULL != ulptr->s_pkgs) { if (NULL != ulptr->i_pkgs) { dk4sto_it_reset(ulptr->i_pkgs); do { pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs); if (NULL != pptr) { dk4uc2l_i_close_pkg(pptr); } } while (NULL != pptr); dk4sto_it_close(ulptr->i_pkgs); } dk4sto_close(ulptr->s_pkgs); } ulptr->s_pkgs = NULL; ulptr->i_pkgs = NULL; dk4mem_free(ulptr); } } dk4_uc2l_t * dk4uc2l_i_new(const dkChar *dn, dk4_er_t *erp) { dk4_uc2l_t *back = NULL; int ok = 0; back = dk4mem_new(dk4_uc2l_t,1,erp); if (NULL != back) { back->buf[0] = '\0'; back->dname = NULL; back->s_ranges = NULL; back->i_ranges = NULL; back->s_files = NULL; back->i_files = NULL; back->s_pkgs = NULL; back->i_pkgs = NULL; back->had_error = 0; back->utf8allowed = 0; back->fallowed = 0xFF; back->dname = dk4str_dup(dn, erp); if (NULL != back->dname) { back->s_ranges = dk4sto_open(erp); back->s_files = dk4sto_open(erp); back->s_pkgs = dk4sto_open(erp); if ( (NULL != back->s_ranges) && (NULL != back->s_files) && (NULL != back->s_pkgs) ) { dk4sto_set_comp(back->s_ranges, dk4uc2l_i_range_compare, 0); dk4sto_set_comp(back->s_files, dk4uc2l_file_compare, 0); dk4sto_set_comp(back->s_pkgs, dk4uc2l_pkg_compare, 0); back->i_ranges = dk4sto_it_open(back->s_ranges, erp); back->i_files = dk4sto_it_open(back->s_files, erp); back->i_pkgs = dk4sto_it_open(back->s_pkgs, erp); if ( (NULL != back->i_ranges) && (NULL != back->i_files) && (NULL != back->i_pkgs) ) { ok = 1; } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { } #endif if ((NULL != back) && (0 == ok)) { dk4uc2l_close(back); back = NULL; } 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_pass1( void *obj, char *line, dk4_um_t DK4_ARG_UNUSED(lineno) , dk4_er_t *erp ) { handler_object_t *pho; char *p1; dk4_uc2l_range_t *rptr; dk4_uc2l_range_t *r2; const char *pe = NULL; unsigned long ul = 0UL; dk4_c32_t c32; dk4_c32_t rbo; int res; int back = DK4_TSP_RES_OK; DK4_UNUSED_ARG(lineno) #if TRACE_DEBUG dk4str8_delnl(line); #endif pho = (handler_object_t *)obj; /* Find start of line. */ p1 = dk4str8_start(line, NULL); /* Ignore empty lines and comment lines */ if (NULL == p1) { goto finished; } if ('#' == *p1) { goto finished; } /* Retrieve hexadecimal number */ (void)dk4str8_next(p1, NULL); res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp); if (0 == res) { /* ERROR: Syntax, not a number */ goto finished; } c32 = (dk4_c32_t)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) { /* WARNING erp: Ignoring redefinition */ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); 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) { /* WARNING erp: Ignoring redefinition */ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); goto finished; } /* Check whether appending to existing range */ if (0UL < c32) { rbo = (dk4_c32_t)(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 = (dk4_c32_t)(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; } } /* Check whether prepending to existing range */ #if DK4_SIZEOF_LONG <= 4 if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) { #endif rbo = (dk4_c32_t)(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 = (dk4_c32_t)(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 DK4_SIZEOF_LONG <= 4 } #endif /* Create range on its own */ rptr = dk4uc2l_i_open_range(c32, pho->file, erp); if (NULL == rptr) { back = DK4_TSP_RES_FATAL; goto finished; } if (0 == dk4sto_add(pho->ulptr->s_ranges, rptr, erp)) { dk4uc2l_i_close_range(rptr); back = DK4_TSP_RES_FATAL; } finished: return back; } /** Process one file in pass 1 specified by absolute path name. @param ulptr Conversion structure to set up. @param rstrm Stream, opened for binary reading. @param puc2lf File structure. @param erp Error report, may be NULL. @param bptr Address of success variable to reset on errors. */ static void dk4uc2l_i_process_stream_pass1( dk4_uc2l_t *ulptr, dk4_stream_t *rstrm, dk4_uc2l_file_t *puc2lf, int *bptr, dk4_er_t *erp ) { char lnbuf[256]; /* Line buffer */ dk4_tsp08_t tsp08; /* Text stream processor */ handler_object_t ho; /* Handler object */ dk4_uc2l_range_t *rptr; /* Current range */ int res; /* Operation result */ int cc; /* Flag: Can continue */ char c; /* Current character to process */ /* Initialize handler object */ ho.file = puc2lf; ho.ulptr = ulptr; ho.s_ra = NULL; ho.i_ra = NULL; /* Create storage and iterator */ ho.s_ra = dk4sto_open(erp); if (NULL == ho.s_ra) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; goto finished; } dk4sto_set_comp(ho.s_ra, dk4uc2l_i_range_compare, 0); ho.i_ra = dk4sto_it_open(ho.s_ra, erp); if (NULL == ho.i_ra) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; 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, erp ); if (0 == res) { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } /* Process file 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; *bptr = 0; } break; case DK4_TSP_RES_FATAL : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; *bptr = 0; 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 : { *bptr = 0; ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; 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, erp); if (0 == dk4sto_add(ulptr->s_ranges, rptr, erp)) { dk4uc2l_i_close_range(rptr); *bptr = 0; 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); } } /** Process one file in pass 1 specified by absolute path name. @param ulptr Conversion structure to set up. @param fn Full (absolute) file name. @param sfn Short file name within given directory. @param erp Error report, may be NULL. @param bptr Address of success variable to reset on errors. */ static void dk4uc2l_i_process_one_full_file_pass1( dk4_uc2l_t *ulptr, const dkChar *fn, const dkChar *sfn, int *bptr, dk4_er_t *erp ) { dk4_stream_t *rstrm; dk4_uc2l_file_t *puc2lf; int fnsi; puc2lf = (dk4_uc2l_file_t *)dk4sto_it_find_like(ulptr->i_files, sfn, 1); if (NULL == puc2lf) { puc2lf = dk4uc2l_i_open_file(sfn, erp); if (NULL != puc2lf) { if (0 != dk4sto_add(ulptr->s_files, puc2lf, erp)) { fnsi = dk4uc2l_i_find_suffix_index(fn); if (-1 < fnsi) { if (0 != dk4uc2l_i_suffix_index_supported(fnsi)) { rstrm = dk4stream_open_file_reader(fn, erp); if (NULL != rstrm) { /* Process stream */ dk4uc2l_i_process_stream_pass1( ulptr, rstrm, puc2lf, bptr, erp ); dk4stream_close(rstrm, NULL); } else { ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; *bptr = 0; } } else { ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; *bptr = 0; /* ERROR erp: Compression type not supported */ dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED); } } else { /* Ignoring unsupported file */ } } else { dk4uc2l_i_close_file(puc2lf); } } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { } #endif } /** 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 erp Error report, may be NULL. @param bptr Address of success variable to reset on errors. */ static void dk4uc2l_i_process_one_file_pass1( dk4_uc2l_t *ulptr, const dkChar *pth, const dkChar *fn, int *bptr, dk4_er_t *erp ) { dkChar fnb[DK4_MAX_PATH]; size_t szfnb = DK4_SIZEOF(fnb,dkChar); if (NULL != pth) { if (0 != dk4str_cpy_s(fnb, szfnb, pth, erp)) { if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[3], erp)) { if (0 != dk4str_cat_s(fnb, szfnb, fn, erp)) { dk4path_correct_sep(fnb); dk4uc2l_i_process_one_full_file_pass1( ulptr, fnb, fn, bptr, erp ); } else { *bptr = 0; } } else { *bptr = 0; } } else { *bptr = 0; } } else { dk4uc2l_i_process_one_full_file_pass1(ulptr, fn, fn, bptr, erp); } } /** 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, not on syntax errors in translation files. @param ulptr Conversion structure. @param erp Error report, may be NULL. @return 1 on success, 0 on error. */ static int dk4uc2l_i_pass1(dk4_uc2l_t *ulptr, dk4_er_t *erp) { const dkChar *fn = NULL; const dkChar *pth = NULL; dk4_dir_t *pdir = NULL; int back = 0; pdir = dk4dir_open(ulptr->dname, DK4_DIR_OPEN_SORTED, erp); 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,erp); } } } while (NULL != fn); dk4dir_close(pdir); } else { /* ERROR: Failed to open directory */ ulptr->had_error |= DK4_UC2L_ERROR_FOPEN; } return back; } /** Internal function to open a new conversion structure. @param dn Directory name (must be the name of an existing directory). @param erp Error report, may be NULL. @return Valid pointer on success, NULL on error. */ static dk4_uc2l_t * dk4uc2l_i_open(const dkChar *dn, dk4_er_t *erp) { dk4_uc2l_t *back = NULL; back = dk4uc2l_i_new(dn, erp); if (NULL != back) { if (0 == dk4uc2l_i_pass1(back, erp)) { dk4uc2l_close(back); back = NULL; } #if TRACE_DEBUG else { } #endif } #if TRACE_DEBUG else { /* ERROR: Memory (already reported) */ } #endif return back; } dk4_uc2l_t * dk4uc2l_open(const dkChar *dn, dk4_er_t *erp) { dkChar fnb[DK4_MAX_PATH]; const dkChar *shdn = NULL; dk4_uc2l_t *back = NULL; const size_t szfnb = DK4_SIZEOF(fnb,dkChar); size_t i = 0; if (NULL != dn) { if (0 != dk4file_is_directory(dn, erp)) { back = dk4uc2l_i_open(dn, erp); } } else { shdn = dk4inst_get_directory(2); for (i = 0; ((i < 3) && (NULL == dn)); i++) { if (0 != dk4str_cpy_s(fnb, szfnb, shdn, 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; } } } } if (NULL != dn) { back = dk4uc2l_i_open(dn, erp); } else { /* ERROR: No directory found */ dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); } } return back; } void dk4uc2l_allow_utf8(dk4_uc2l_t *ulptr, int enabled) { #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { ulptr->utf8allowed = ((0 != enabled) ? 0x01 : 0x00); } } void dk4uc2l_clean_packages_and_fonts(dk4_uc2l_t *ulptr) { dk4_uc2l_pkg_t *pptr; #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { ulptr->fallowed = DK4_UC2L_FONT_ENCODING_ALL; dk4sto_it_reset(ulptr->i_pkgs); do { pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs); if (NULL != pptr) { pptr->used = 0x00; } } while (NULL != pptr); } } unsigned char dk4uc2l_retrieve_allowed_fe(dk4_uc2l_t *ulptr) { unsigned char back = 0x00; #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { back = ulptr->fallowed; } return back; } int dk4uc2lat_direct(dk4_c32_t c32) { int back = 0; char c; /* 8-bit character version of c32. */ if(128UL > dk4recode_c32_to_ul(c32)) { c = (char)c32; switch(c) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case ',': case '.': case ':': case ';': case '+': case '-': case '?': case '!': case '|': case '@': case '(': case ')': case '/': case '=': case ' ': { back = 1; } break; } } return back; } int dk4uc2l_i_keyword_index(const char *pkey) { return (dk4str8_abbr_index(dk4uc2l_keywords, '$', pkey, 0)); } unsigned char dk4uc2l_font_encoding_from_name(const char *pname) { unsigned char back = 0x00; switch (dk4str8_array_index(dk4uc2l_font_encodings, pname, 0)) { case 0: { back = DK4_UC2L_FONT_ENCODING_OT1; } break; case 1: { back = DK4_UC2L_FONT_ENCODING_T1; } break; case 2: { back = DK4_UC2L_FONT_ENCODING_T4; } break; case 3: { back = DK4_UC2L_FONT_ENCODING_T5; } break; } return back; } dk4_uc2l_pkg_t * dk4uc2l_i_create_pkg( dk4_sto_t *s_pkgs, const char *pname ) { dk4_uc2l_pkg_t *back = NULL; back = dk4uc2l_i_open_pkg(pname, NULL); if (NULL != back) { if (0 == dk4sto_add(s_pkgs, back, NULL)) { dk4uc2l_i_close_pkg(back); back = NULL; } } 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 *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; #if TRACE_DEBUG dk4str8_delnl(line); #endif /* Line handler object */ lho = (handler_object_t *)obj; /* Find start of line, ignore empty lines and comments */ p1 = dk4str8_start(line, NULL); if (NULL == p1) { goto finished; } if ('#' == *p1) { goto finished; } /* Retrieve character number */ p2 = dk4str8_next(p1, NULL); res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp); if (0 == res) { /* 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) { /* 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. */ 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, erp)) { lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; back = DK4_TSP_RES_FATAL; goto finished; } rptr->ia = 0x01; } else { } /* 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. */ 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) { p2 = dk4str8_next(p1, NULL); p3 = dk4str8_chr(p1, '='); if (NULL != p3) { *(p3++) = '\0'; p3 = dk4str8_start(p3, NULL); if (NULL != p3) { res = dk4uc2l_i_keyword_index(p1); switch (res) { case 0 : { if (NULL != rptr->both) { if (NULL == (rptr->both)[ind]) { (rptr->both)[ind] = dk4str8_dup(p3, erp); if (NULL == (rptr->both)[ind]) { lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { /* ERROR: Memory. Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 1 : { if (NULL != rptr->text) { if (NULL == (rptr->text)[ind]) { (rptr->text)[ind] = dk4str8_dup(p3, erp); if (NULL == (rptr->text)[ind]) { lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { /* ERROR: Memory Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 2 : { if (NULL != rptr->math) { if (NULL == (rptr->math)[ind]) { (rptr->math)[ind] = dk4str8_dup(p3, erp); if (NULL == (rptr->math)[ind]) { lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { /* ERROR: Memory. Already reported during range initialization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; case 3 : { 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 = (unsigned char)(feval & (~(fex))); } } else { /* ERROR: Illegal encoding name */ dk4error_set_simple_error_code( erp, DK4_E_SYNTAX ); 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 : { 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),erp); 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 { dk4error_set_simple_error_code( erp, DK4_E_MEMORY_ALLOCATION_FAILED ); lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } } } else { dk4error_set_simple_error_code( erp, DK4_E_MEMORY_ALLOCATION_FAILED ); lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } else { /* ERROR: Syntax, empty list */ dk4error_set_simple_error_code( erp, DK4_E_SYNTAX ); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { /* ERROR: Already defined. Bug: Should not happen. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } } else { /* ERROR: Memory. Already reported during range initalization. */ lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY; } } break; default : { /* ERROR: Illegal key name */ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; } break; } p1 = p2; } else { /* ERROR: Syntax, not a key=value */ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; p1 = NULL; } } else { /* ERROR: Syntax, not a key=value */ dk4error_set_simple_error_code(erp, DK4_E_SYNTAX); lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX; p1 = NULL; } } finished: return back; } /** Load data file. @param ulptr Conversion structure. @param fptr File structure to load. @param erp Error report, may be NULL. */ static void dk4uc2l_load_data_file( dk4_uc2l_t *ulptr, dk4_uc2l_file_t *fptr, dk4_er_t *erp ) { dkChar fnb[DK4_MAX_PATH]; char lnb[256]; handler_object_t ho; dk4_tsp08_t tsp08; dk4_stream_t *rstrm = NULL; size_t fnbsz = DK4_SIZEOF(fnb,dkChar); size_t szlnb = sizeof(lnb); int res; int cc; char c; /* Initialize handler object */ ho.ulptr = ulptr; ho.s_ra = NULL; ho.i_ra = NULL; ho.file = fptr; ho.rpc = NULL; /* 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, erp)) { /* ERROR: Directory name too long */ ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } if (0 == dk4str_cat_s(fnb, fnbsz, dk4uc2l_kwnl[3], erp)) { /* ERROR: Directory name too long */ ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } if (0 == dk4str_cat_s(fnb, fnbsz, fptr->fn, erp)) { /* ERROR: Directory name too long */ ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; goto finished; } dk4path_correct_sep(fnb); /* Open reader stream */ rstrm = dk4stream_open_file_reader(fnb, erp); if (NULL == rstrm) { /* ERROR: Failed to read file */ 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, erp ); if (0 == res) { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; /* ERROR: Memory */ goto finished; } /* Process contents */ do { cc = 0; res = dk4stream_c8_read_byte(&c, rstrm, erp); 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; } break; case DK4_TSP_RES_FATAL : { ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING; 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; } break; } /* Clean up */ finished: if (NULL != rstrm) { dk4stream_close(rstrm, NULL); } } const char * dk4uc2l_find(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_er_t *erp) { dk4_uc2l_range_t *rptr; dk4_uc2l_pkg_t **pkgpp; dk4_uc2l_file_t *fptr; const char *back = NULL; size_t ind; size_t blgt; int res; #if DK4_USE_ASSERT assert(NULL != ulptr); #endif /* Check ulptr usability */ if (NULL == ulptr) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } /* 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 files */ rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(ulptr->i_ranges, &c, 1); if (NULL != rptr) { fptr = rptr->file; if (0x00 == fptr->loaded) { dk4uc2l_load_data_file(ulptr, fptr, erp); } 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 data or ASCII data directly */ if (0 == mm) { if (0x00 != ulptr->utf8allowed) { blgt = 15; res = dk4utf8_encode( (unsigned char *)(&(ulptr->buf[0])), &blgt, c, erp ); if (0 != res) { ulptr->buf[blgt] = '\0'; back = &(ulptr->buf[0]); } } else { if (dkC32(0x00000100) > c) { ulptr->buf[0] = (char)c; ulptr->buf[1] = '\0'; back = &(ulptr->buf[0]); } } } finished: return back; } static int dk4uc2l_i_encoding( unsigned char enclist, unsigned char oneenc ) { int back = 0; if (0x00 != (enclist & ((unsigned char)oneenc))) { back = 1; } return back; } void dk4uc2l_recommendations(dk4_uc2l_t *ulptr, dk4_stream_t *wstrm, dk4_er_t *erp) { dk4_uc2l_pkg_t *pptr; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); #endif if ((NULL != ulptr) && (NULL != wstrm)) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[0], erp ); if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T1)) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[3], erp ); } if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_OT1)) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[2], erp ); } if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T4)) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[4], erp ); } if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T5)) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[5], erp ); } dk4stream_write_byte(wstrm, '\n', erp); dk4sto_it_reset(ulptr->i_pkgs); do { pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs); if (NULL != pptr) { if (0x00 != pptr->used) { dk4stream_write_char_string( wstrm, dk4uc2l_kw8[1], erp ); dk4stream_write_char_string( wstrm, pptr->pn, erp ); dk4stream_write_byte(wstrm, '\n', erp); } } } while (NULL != pptr); } } int dk4uc2l_retrieve_errors(dk4_uc2l_t *ulptr) { int back = 0; #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { back = ulptr->had_error; } return back; } void dk4uc2l_reset_errors(dk4_uc2l_t *ulptr) { #if DK4_USE_ASSERT assert(NULL != ulptr); #endif if (NULL != ulptr) { ulptr->had_error = 0; } } /* ##### untested */ static void dk4uc2l_putc32( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, dk4_c32_t c32, int *pmm, int *pback, dk4_er_t *erp ) { dk4_er_t er; const char *le = NULL; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); #endif dk4error_init(&er); le = dk4uc2l_find(ulptr, c32, 0, &er); if (NULL != le) { if (0 != *pmm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { *pback = 0; } *pmm = 0; } if (0 == dk4stream_write_char_string(wstrm, le, erp)) { *pback = 0; } } else { le = dk4uc2l_find(ulptr, c32, 1, &er); if (NULL != le) { if (0 == *pmm) { if (0 == dk4stream_write_char_string(wstrm,dk4uc2l_mm[0],erp)) { *pback = 0; } *pmm = 1; } if (0 == dk4stream_write_char_string(wstrm, le, erp)) { *pback = 0; } } else { *pback = 0; dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND); } } } /* ##### untested */ int dk4uc2l_string_c32( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c32_t *str, dk4_er_t *erp ) { int back = 0; int mm = 0; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } /* Process all characters from string */ back = 1; while (dkC32(0) != *str) { dk4uc2l_putc32(wstrm, ulptr, *(str++), &mm, &back, erp); } /* Finalize math mode if necessary */ if (0 != mm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { back = 0; } } finished: return back; } /* ##### untested */ int dk4uc2l_string_c16( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dk4_c16_t *str, dk4_er_t *erp ) { dk4_utf16_decoder_t dec; dk4_c32_t c32; int mm = 0; int back = 0; int err = 0; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif /* Check arguments */ if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } 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(wstrm, ulptr, c32, &mm, &back, erp); } break; case DK4_EDSTM_ERROR : { err = 1; dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED); back = 0; } break; } } if (0 == err) { if (0 == dk4utf16_is_empty(&dec)) { dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED); back = 0; } } if (0 != mm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { back = 0; } } finished: return back; } /* ##### untested */ int dk4uc2l_string_utf8( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_er_t *erp ) { dk4_utf8_decoder_t dec; dk4_c32_t c32; int back = 0; int mm = 0; int err = 0; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } 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(wstrm, ulptr, c32, &mm, &back, erp); } break; case DK4_EDSTM_ERROR : { err = 1; dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED); back = 0; } break; } } if (0 == err) { if (0 == dk4utf8_is_empty(&dec)) { dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED); back = 0; } } if (0 != mm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { back = 0; } } finished: return back; } /* ##### untested */ int dk4uc2l_string_ansi( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_er_t *erp ) { dk4_c32_t c32; int back = 0; int mm = 0; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } back = 1; while ('\0' != *str) { if (0 != dk4ansi_decode(&c32, (unsigned char)(*(str++)))) { dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp); } else { dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED); back = 0; } } if (0 != mm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { back = 0; } } finished: return back; } /* ##### untested */ int dk4uc2l_string_ascii( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, dk4_er_t *erp ) { dk4_c32_t c32; int back = 0; int mm = 0; #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) { dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS); goto finished; } back = 1; while ('\0' != *str) { c32 = (dk4_c32_t)((unsigned char)(*(str++))); dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp); } if (0 != mm) { if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) { back = 0; } } finished: return back; } /* ##### untested */ int dk4uc2l_string_c8( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const char *str, int ie, dk4_er_t *erp ) { #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif switch (ie) { case DK4_ENCODING_UTF8 : { return (dk4uc2l_string_utf8(wstrm, ulptr, str, erp)); } break; case DK4_ENCODING_WIN1252 : { return (dk4uc2l_string_ansi(wstrm, ulptr, str, erp)); } break; default : { return (dk4uc2l_string_ascii(wstrm, ulptr, str, erp)); } break; } } /* ##### untested */ int dk4uc2l_string_dk( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const dkChar *str, #if 1 == DK4_CHAR_SIZE int ie, #else int DK4_ARG_UNUSED(ie), #endif dk4_er_t *erp ) { #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(wstrm, ulptr, str, erp)); #else return (dk4uc2l_string_c16(wstrm, ulptr, str, erp)); #endif #else return (dk4uc2l_string_c8(wstrm, ulptr, str, ie, erp)); #endif } int dk4uc2l_string_encoded( dk4_stream_t *wstrm, dk4_uc2l_t *ulptr, const void *str, int ie, dk4_er_t *erp ) { int back = 0; #if DK4_CHAR_SIZE > 1 DK4_UNUSED_ARG(ie) #endif #if DK4_USE_ASSERT assert(NULL != wstrm); assert(NULL != ulptr); assert(NULL != str); #endif switch (ie) { case DK4_ENCODING_32 : { back = dk4uc2l_string_c32(wstrm, ulptr, str, erp); } break; case DK4_ENCODING_UTF16 : { back = dk4uc2l_string_c16(wstrm, ulptr, str, erp); } break; default : { back = dk4uc2l_string_c8(wstrm, ulptr, str, ie, erp); } break; } return back; } /* vim: set ai sw=4 ts=4 : */