%% options copyright owner = Dirk Krause copyright year = 2011-xxxx license = bsd %% header /** @file dk3uc2l.h 32-bit character to LaTeX conversion. This module was rewritten in August 2015, so it uses the same *.t2l files as the dk4uc2l module. During this rewrite the functionality was stripped down to those functions used by the itadmin program. */ #include "dk3conf.h" #include "dk3types.h" #ifdef __cplusplus extern "C" { #endif /** Open LaTeX encoder. @param d Directory containing the tables. @param f_desc Flag: Attempt to load glyph descriptions. @param f_utf8 Flag: UTF-8 output encoding. @param app Application structure for diagnostics, may be NULL. @return Pointer to new encoder on success, NULL on error. */ dk3_uc2lat_t * dk3uc2lat_open_app(dkChar const *d, int f_desc, int f_utf8, dk3_app_t *app); /** Close LaTeX encoder. @param u Encoder to close. */ void dk3uc2lat_close(dk3_uc2lat_t *u); /** Retrieve LaTeX encoding for one 32-bit character. @param u LaTeX encoder. @param c32 Character to obtain LaTeX encoding for. @param ismath Flag: In math mode. @return Pointer to encoding on success, NULL on error. */ char const * dk3uc2lat_get(dk3_uc2lat_t *u, dk3_c32_t c32, int ismath); /** Check whether a character can be written to a LaTeX file directly. @param c32 Character to check. @return 1 for yes, 0 for no. */ int dk3uc2lat_direct(dk3_c32_t c32); /** Write LaTeX encoding for a string to a stream. @param u LaTeX encoder. @param st Stream to write to. @param t Text to write (ASCII/ISO-LATIN-1 encoded). @return 1 on success, 0 on error. */ int dk3uc2lat_c8_plain_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t); /** Write LaTeX encoding for a string to a stream. @param u LaTeX encoder. @param st Stream to write to. @param t Text to write (UTF-8 encoded). @return 1 on success, 0 on error. */ int dk3uc2lat_c8_utf8_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t); /** Write LaTeX encoding for a string to a stream. @param u LaTeX encoder. @param st Stream to write to. @param t Text to write (UTF-16 encoded). @return 1 on success, 0 on error. */ int dk3uc2lat_c16_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c16_t const *t); /** Write LaTeX encoding for a string to a stream. @param u LaTeX encoder. @param st Stream to write to. @param t Text to write (32-bit characters). @return 1 on success, 0 on error. */ int dk3uc2lat_c32_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t const *t); /** Write LaTeX encoding for a string to a stream. @param u LaTeX encoder. @param st Stream to write to. @param t Text to write (dkChar characters). @param e Encoding (only used for 8-bit characters). @return 1 on success, 0 on error. */ int dk3uc2lat_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dkChar const *t, int e); #if HAVE_PACKAGES /** Prepare LaTeX encoder to retrieve package information. @param u LaTeX encoder. */ void dk3uc2lat_package_reset(dk3_uc2lat_t *u); /** Retrieve next package information from LaTeX encoder. @param u LaTeX encoder. @return Pointer to next package information or NULL. */ dk3_uc2lat_pkg_t * dk3uc2lat_package_next(dk3_uc2lat_t *u); #endif /** Reset font encoding information. @param u LaTeX encoder. */ void dk3uc2lat_font_encoding_reset(dk3_uc2lat_t *u); /** Check for font encoding conflicts. @param u LaTeX encoder. @return 1 on conflicts, 0 otherwise (no problems). */ int dk3uc2lat_font_encoding_conflict(dk3_uc2lat_t *u); /** Report font encoding requirement conflicts. @param u LaTeX encoder. */ void dk3uc2lat_font_encoding_report_conflict(dk3_uc2lat_t *u); /** Report font encoding requirement conflicts. @param u LaTeX encoder. */ void dk3uc2lat_font_encoding_report(dk3_uc2lat_t *u); /** Write some final comments to output stream about usable encdings and required packages. @param u LaTeX encoder. @param st Output stream. */ void dk3uc2lat_final_report(dk3_uc2lat_t *u, dk3_stream_t *st); #ifdef __cplusplus } #endif %% module /** Enable or disable support for dk3_uc2l_pkg_t. */ #define HAVE_PACKAGES 1 #include "dk3all.h" #include "dk3maih8.h" $!trace-include /** LaTeX commands to start and end math mode. */ static char const * const dk3uc2lat_mm[] = { "\\(", "\\)", "% font encodings:", "% package: ", "\n", }; #if 0 /** Font encoding names. */ static char const * const dk3uc2lat_font_encodings[] = { "ot1", "!ot1", "t1", "!t1", "t4", "!t4", "t5", "!t5", NULL }; #endif /** Font encoding names, used in error messages. */ static dkChar const * const dk3uc2l_font_encoding_names[] = { dkT("OT1"), dkT("T1"), dkT("T4"), dkT("T5"), NULL }; /** Font encoding names written at end of output file. */ static const char * const dk3uc2l_c8_font_encoding_names[] = { $!string-table OT1 T1 T4 T5 $!end }; /** Allowed suffixes for conversion data files. */ static dkChar const * const dk3uc2l_suffixes[] = { dkT(".t2l"), #if DK3_HAVE_ZLIB_H && (DK3_CHAR_SIZE == 1) dkT(".t2l.gz"), #endif #if DK3_HAVE_BZLIB_H && (DK3_CHAR_SIZE == 1) dkT(".t2l.bz2"), #endif NULL }; /** Compression suffixes. */ static dkChar const * const dk3uc2l_co_suf[] = { $!string-table macro=dkT .gz .bz2 $!end }; /** Attribute keywords. */ static const char * const dk3uc2l_kw[] = { $!string-table b$oth t$ext m$ath e$ncoding p$ackages $!end }; /** Encoding names, used for reporting. */ static const char * const dk3uc2l_enco[] = { $!string-table ot1 t1 t4 t5 $!end }; /** Release an array of string pointers. @param ap Array base address. @param ns Number of strings. */ static void dk3uc2lat_release_pointer_array(char const **ap, size_t ns) { char const **ptr; /* Current string in array. */ size_t i; /* Current string index in array. */ $? "+ dk3uc2lat_release_pointer_array %lu", (unsigned long)ns ptr = ap; i = ns; while(i--) { dk3_release(*ptr); ptr++; } $? "- dk3uc2lat_release_pointer_array" dk3_delete(ap); } /** Destroy range structure, release memory. @param rp Structure to destroy. */ static void dk3uc2lat_range_delete(dk3_uc2lat_range_t *rp) { size_t numchar; /* Number of characters in this range. */ dkChar const **ptr; /* Release all descriptions. */ dk3_uc2lat_pkg_t ***pkgppp; size_t i; /* Number of descriptions to release. */ $? "+ dk3uc2lat_range_delete %lx %lx", (unsigned long)(rp->start), (unsigned long)(rp->end) if(rp) { numchar = (size_t)(rp->end - rp->start + 1); if(numchar > 0) { rp->dir = NULL; if(rp->f) { dk3_release(rp->f); } rp->f = NULL; if(rp->dsc) { ptr = rp->dsc; i = (size_t)(rp->end - rp->start + 1); while(i--) { dk3_release(*ptr); ptr++; } } rp->dsc = NULL; if(rp->a) { dk3uc2lat_release_pointer_array(rp->a, numchar); } rp->a = NULL; if(rp->t) { dk3uc2lat_release_pointer_array(rp->t, numchar); } rp->t = NULL; if(rp->m) { dk3uc2lat_release_pointer_array(rp->m, numchar); } rp->m = NULL; if(rp->p) { pkgppp = rp->p; i = (size_t)(rp->end - rp->start + 1); while (i--) { dk3_release(*pkgppp); pkgppp++; } dk3_delete(rp->p); } rp->p = NULL; rp->start = (dk3_c32_t)0UL; rp->end = (dk3_c32_t)0UL; rp->ia = 0x00; } dk3_delete(rp); } $? "- dk3uc2lat_range_delete" } #if HAVE_PACKAGES /** Destroy package structure, release memory. @param pp Structure to release. */ static void dk3uc2lat_pkg_delete(dk3_uc2lat_pkg_t *pp) { $? "+ dk3uc2lat_pkg_delete %!8s", TR_8PTR(pp) if(pp) { $? ". pkg name = \"%!8s\"", TR_8STR(pp->name) dk3_release(pp->name); pp->used = 0x00; dk3_delete(pp); } $? "- dk3uc2lat_pkg_delete" } #endif /** Destroy UC to LaTeX directory structure, release memory. @param dp Structure to destroy. */ static void dk3uc2lat_dir_delete(dk3_uc2lat_dir_t *dp) { $? "+ dk3uc2lat_dir_delete %!8s", TR_8PTR(dp) if(dp) { if(dp->s_ran) { if(dp->i_ran) { dk3sto_it_close(dp->i_ran); } dp->i_ran = NULL; dk3sto_close(dp->s_ran); } dp->s_ran = NULL; dk3_release(dp->sn); dp->loaded = 0x00; dk3_delete(dp); } $? "- dk3uc2lat_dir_delete" } #if HAVE_PACKAGES /** Compare two package records. @param l Left record. @param r Right record or name. @param cr Comparison criteria (0=record/record, 1=record/name). @return Comparison result. */ static int dk3uc2lat_pkg_compare(void const *l, void const *r, int cr) { int back = 0; dk3_uc2lat_pkg_t const *pl; /* Left pointer. */ dk3_uc2lat_pkg_t const *pr; /* Right pointer. */ pl = (dk3_uc2lat_pkg_t const *)l; pr = (dk3_uc2lat_pkg_t const *)r; if(l) { if(r) { switch(cr) { case 1: { if(pl->name) { back = dk3str_c8_cmp(pl->name, (char const *)r); } else { back = -1; } } break; default: { if(pl->name) { if(pr->name) { back = dk3str_c8_cmp(pl->name, pr->name); } else { back = 1; } } else { if(pr->name) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } if(back < -1) { back = -1; } if(back > 1) { back = 1; } return back; } #endif /** Compare two range structures by start and end character. @param l Left structure. @param r Right structure/UC character. @param cr Comparison criteria (0=struct/struct, 1=struct/char). @return Comparison result. */ static int dk3uc2lat_range_compare(void const *l, void const *r, int cr) { int back = 0; dk3_uc2lat_range_t const *pl; /* Left pointer. */ dk3_uc2lat_range_t const *pr; /* Right pointer. */ dk3_c32_t *ucptr; /* Right pointer is a character pointer. */ pl = (dk3_uc2lat_range_t const *)l; pr = (dk3_uc2lat_range_t const *)r; if(l) { if(r) { switch(cr) { case 1: { ucptr = (dk3_c32_t *)r; if(pl->start > (*ucptr)) { back = 1; } else { if(pl->end < (*ucptr)) { back = -1; } } } break; default: { if(pl->start > pr->end) { back = 1; } else { if(pl->end < pr->start) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } return back; } /** Compare two UC to LaTeX directory structures. @param l Left structure. @param r Right structure/name. @param cr Comparison criteria (0=struct/struct, 1=struct/name). @return Comparison result. */ static int dk3uc2lat_dir_compare(void const *l, void const *r, int cr) { int back = 0; dk3_uc2lat_dir_t const *pl; /* Left pointer. */ dk3_uc2lat_dir_t const *pr; /* Right pointer. */ pl = (dk3_uc2lat_dir_t const *)l; pr = (dk3_uc2lat_dir_t const *)r; if(l) { if(r) { switch(cr) { case 1: { if(pl->sn) { back = dk3str_fncmp(pl->sn, (dkChar const *)r); } else { back = -1; } } break; default: { if(pl->sn) { if(pr->sn) { back = dk3str_fncmp(pl->sn, pr->sn); } else { back = 1; } } else { if(pr->sn) { back = -1; } } } break; } } else { back = 1; } } else { if(r) { back = -1; } } return back; } void dk3uc2lat_close(dk3_uc2lat_t *u) { #if HAVE_PACKAGES dk3_uc2lat_pkg_t *ppkg; #endif dk3_uc2lat_dir_t *pdir; dk3_uc2lat_range_t *pran; $? "+ dk3uc2lat_close" if (NULL != u) { u->app = NULL; dk3_release(u->dir); dk3_release(u->buf); if (NULL != u->s_ran) { if (NULL != u->i_ran) { dk3sto_it_reset(u->i_ran); do { pran = (dk3_uc2lat_range_t *)dk3sto_it_next(u->i_ran); if (NULL != pran) { dk3uc2lat_range_delete(pran); } } while (NULL != pran); dk3sto_it_close(u->i_ran); } dk3sto_close(u->s_ran); } u->s_ran = NULL; u->i_ran = NULL; if (NULL != u->s_dir) { if (NULL != u->i_dir) { dk3sto_it_reset(u->i_dir); do { pdir = (dk3_uc2lat_dir_t *)dk3sto_it_next(u->i_dir); if (NULL != pdir) { dk3uc2lat_dir_delete(pdir); } } while (NULL != pdir); dk3sto_it_close(u->i_dir); } dk3sto_close(u->s_dir); } u->s_dir = NULL; u->i_dir = NULL; #if HAVE_PACKAGES if (NULL != u->s_pkg) { if (NULL != u->i_pkg) { dk3sto_it_reset(u->i_pkg); do { ppkg = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg); if (NULL != ppkg) { dk3uc2lat_pkg_delete(ppkg); } } while (NULL != ppkg); dk3sto_it_close(u->i_pkg); } dk3sto_close(u->s_pkg); } u->s_pkg = NULL; u->i_pkg = NULL; #endif u->rca = NULL; u->szbuf = 0; u->f_dsc = 0; u->f_utf8 = 0; u->fe = 0; dk3_delete(u); } $? "- dk3uc2lat_close" } #if HAVE_PACKAGES /** Create package structure, allocate memory. @param pn Package name. @param app Application structure for diagnostics. @return Pointer to new structure on success, NULL on error. */ static dk3_uc2lat_pkg_t * dk3uc2lat_pkg_new(char const *pn, dk3_app_t *app) { dk3_uc2lat_pkg_t *back = NULL; $? "+ dk3uc2lat_pkg_new \"%!8s\"", TR_8STR(pn) back = dk3_new_app(dk3_uc2lat_pkg_t,1,app); if(back) { back->used = 0x00; back->name = dk3str_c8_dup_app(pn,app); if(!(back->name)) { dk3uc2lat_pkg_delete(back); back = NULL; } } $? "- dk3uc2lat_pkg_new %!8s", TR_8PTR(back) return back; } #endif /** Create range structure, allocate memory. @param start Start character of range. @param end End character of range. @param dir Directory structure (parent of this range). @param app Application structure for diagnostics. @return Pointer to new range structure on success, NULL on error. */ static dk3_uc2lat_range_t * dk3uc2lat_range_new( dk3_c32_t start, dk3_c32_t end, dk3_uc2lat_dir_t *dir, dk3_app_t *app ) { dk3_uc2lat_range_t *back = NULL; char range_text[32]; /* Buffer for number range. */ dkChar dk_range_text[32]; /* Buffer for number range. */ $? "+ dk3uc2lat_range_new %lx %lx", (unsigned long)(start), (unsigned long)(end) if(dk3app_max_log_level(app) >= DK3_LL_DEBUG) { sprintf(range_text, "%lx-%lx", (long)start, (long)end); (void)dk3str_c8_to_str_simple_app(dk_range_text, 32, range_text, app); dk3app_log_i3(app, DK3_LL_DEBUG, 238, 239, dk_range_text); } if(end >= start) { back = dk3_new_app(dk3_uc2lat_range_t,1,app); if(back) { back->dir = dir; back->dsc = NULL; back->a = NULL; back->t = NULL; back->m = NULL; #if HAVE_PACKAGES back->p = NULL; #endif back->f = NULL; back->start = start; back->end = end; back->ia = 0x00; } } else { if(app) { dk3app_log_i1(app, DK3_LL_ERROR, 220); } } $? "- dk3uc2lat_range_new %!8s", TR_8PTR(back) return back; } /** Create UC to LaTeX directory structure, allocate memory. @param sn Short directory file name. @param app Application structure for diagnostics. @return Pointer to new directory structure on success, NULL on error. */ static dk3_uc2lat_dir_t * dk3uc2lat_dir_new(dkChar const *sn, dk3_app_t *app) { dk3_uc2lat_dir_t *back = NULL; $? "+ dk3uc2lat_dir_new \"%!ds\"", TR_STR(sn) back = dk3_new_app(dk3_uc2lat_dir_t,1,app); if(back) { back->s_ran = NULL; back->i_ran = NULL; back->sn = NULL; back->loaded = 0x00; back->s_ran = dk3sto_open_app(app); if(back->s_ran) { dk3sto_set_comp(back->s_ran, dk3uc2lat_range_compare, 0); back->i_ran = dk3sto_it_open(back->s_ran); if(back->i_ran) { back->sn = dk3str_dup_app(sn,app); } } if(!((back->s_ran) && (back->i_ran) && (back->sn))) { dk3uc2lat_dir_delete(back); back = NULL; } } $? "- dk3uc2lat_dir_new PTR:%d", TR_IPTR(back) return back; } /** Create new LaTeX encoder. @param dn Directory containing the data files. @param f_utf8 Flag: Allowed to write UTF-8 output. @param app Application structure for diagnostics, may be NULL. @return Pointer to new encoder on success, NULL on error. */ static dk3_uc2lat_t * dk3uc2lat_t_new( const dkChar *dn, int f_utf8, dk3_app_t *app ) { dk3_uc2lat_t *back = NULL; int ok = 0; $? "+ dk3uc2lat_t_new %!ds", dn back = dk3_new_app(dk3_uc2lat_t,1,app); if (NULL != back) { back->app = app; back->dir = NULL; back->buf = NULL; back->s_ran = NULL; back->i_ran = NULL; back->s_dir = NULL; back->i_dir = NULL; #if HAVE_PACKAGES back->s_pkg = NULL; back->i_pkg = NULL; #endif back->rca = NULL; back->szbuf = 0; back->f_dsc = 0; back->f_utf8 = f_utf8; back->fe = DK3_FONT_ENCODING_OT1 + DK3_FONT_ENCODING_T1 + DK3_FONT_ENCODING_T4 + DK3_FONT_ENCODING_T5; back->dir = dk3str_dup_app(dn, app); back->buf = dk3_new_app(char,16,app); if (NULL != back->buf) { back->szbuf = 16; } if ((NULL != back->dir) && (NULL != back->buf)) { back->s_ran = dk3sto_open_app(app); if (NULL != back->s_ran) { dk3sto_set_comp(back->s_ran, dk3uc2lat_range_compare, 0); back->s_dir = dk3sto_open_app(app); if (NULL != back->s_dir) { dk3sto_set_comp(back->s_dir, dk3uc2lat_dir_compare, 0); #if HAVE_PACKAGES back->s_pkg = dk3sto_open_app(app); if (NULL != back->s_pkg) { dk3sto_set_comp(back->s_pkg, dk3uc2lat_pkg_compare, 0); #endif back->i_ran = dk3sto_it_open(back->s_ran); if (NULL != back->i_ran) { back->i_dir = dk3sto_it_open(back->s_dir); if (NULL != back->i_dir) { #if HAVE_PACKAGES back->i_pkg = dk3sto_it_open(back->s_pkg); if (NULL != back->i_pkg) { #endif ok = 1; #if HAVE_PACKAGES } #endif } } #if HAVE_PACKAGES } #endif } } } if (0 == ok) { dk3uc2lat_close(back); back = NULL; } } $? "- dk3uc2lat_t_new PTR:%d", TR_IPTR(back) return back; } /** Check the file name whether it contains LaTeX conversion data and can be processed. @param fn File name to check. @return 1 if yes, 0 otherwise. */ static int dk3uc2lat_is_suitable_file(const dkChar *fn) { const dkChar * const *ptr; /* Traverse allowed suffixes array */ size_t szfn = 0; /* File name size */ size_t szsu = 0; /* Allowed suffix size */ int back = 0; $? "+ dk3uc2lat_is_suitable_file %!ds", fn szfn = dk3str_len(fn); ptr = dk3uc2l_suffixes; while ((NULL != *ptr) && (0 == back)) { szsu = dk3str_len(*ptr); if (szfn > szsu) { if (0 == dk3str_fncmp(&(fn[szfn - szsu]), *ptr)) { back = 1; } } ptr++; } $? "- dk3uc2lat_is_suitable_file %d", back return back; } /** Add one character to the range descriptions of a file directory. @param uptr Conversion structure to set up. @param pdir File directory to set up. @param chr Character to add. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3uc2l_add_char_to_dir( dk3_uc2lat_t *uptr, dk3_uc2lat_dir_t *pdir, dk3_c32_t chr, dk3_app_t *app ) { dkChar cbuf[64]; dk3_uc2lat_range_t *prange; dk3_uc2lat_range_t *pr2; size_t szcbuf = DK3_SIZEOF(cbuf,dkChar); dk3_c32_t tchr; int back = 0; $? "+ dk3uc2l_add_char_to_dir %lx", (unsigned long)chr prange = dk3sto_it_find_like(uptr->i_ran, &chr, 1); if (NULL == prange) { prange = dk3sto_it_find_like(pdir->i_ran, &chr, 1); if (NULL == prange) { if ((dk3_c32_t)0UL < chr) { $? ". try to append" tchr = chr - 1; prange = dk3sto_it_find_like(pdir->i_ran, &tchr, 1); if (NULL != prange) { $? ". found %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) prange->end = chr; back = 1; $? ". changed to %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) if (0xFFFFFFFFUL > (unsigned long)chr) { tchr = chr + (dk3_c32_t)1UL; pr2 = dk3sto_it_find_like(pdir->i_ran, &tchr, 1); if (NULL != pr2) { $? ". found %lx-%lx", (unsigned long)(pr2->start), (unsigned long)(pr2->end) tchr = pr2->end; dk3sto_remove(pdir->s_ran, pr2); dk3uc2lat_range_delete(pr2); prange->end = tchr; $? ". changed %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) } } } } if (0 == back) { $? ". try to prepend" if (0xFFFFFFFFUL > (unsigned long)chr) { $? ". can" tchr = chr + (dk3_c32_t)1UL; prange = dk3sto_it_find_like(pdir->i_ran, &tchr, 1); if (NULL != prange) { $? ". found %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) prange->start = chr; back = 1; $? ". changed to %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) } } } if (0 == back) { $? ". try to add" prange = dk3uc2lat_range_new(chr, chr, pdir, app); if (NULL != prange) { if (dk3sto_add(pdir->s_ran, prange)) { back = 1; $? ". added %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) } else { dk3uc2lat_range_delete(prange); } } } } else { $? "! already found" /* ERROR: Already found! */ if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)chr, 8)) { dk3app_log_i3(uptr->app, DK3_LL_ERROR, 395, 396, cbuf); } else { dk3app_log_i1(uptr->app, DK3_LL_ERROR, 397); } } } else { $? "! already found" /* ERROR: Already found ! */ if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)chr, 8)) { dk3app_log_i3(uptr->app, DK3_LL_ERROR, 395, 396, cbuf); } else { dk3app_log_i1(uptr->app, DK3_LL_ERROR, 397); } } $? "- dk3uc2l_add_char_to_dir %d", back return back; } /** Apply data from stream to directory information for one file. @param uptr Conversion structure to set up. @param pdir File directory entry to configure. @param istrm Input stream for file (normal or compressed). @param fn Full path name. @param sn Short file name. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3uc2l_apply_1( dk3_uc2lat_t *uptr, dk3_uc2lat_dir_t *pdir, dk3_stream_t *istrm, const dkChar *fn, const dkChar *sn, dk3_app_t *app ) { char buf[512]; char *p1; char *p2; dk3_uc2lat_range_t *prange; unsigned long lineno = 0UL; unsigned long chr; int back = 1; $? "+ dk3uc2l_apply_1" while ((1 == back) && (1 == dk3stream_c8_fgets(istrm, buf, sizeof(buf)))) { dk3app_set_source_line(app, ++lineno); buf[sizeof(buf) - 1] = '\0'; $? ". processing line %lu: %s", lineno, buf p1 = dk3str_c8_start(buf, NULL); if (NULL != p1) { if ('#' != *p1) { p2 = dk3str_c8_next(p1, NULL); if (NULL != p2) { if (0 != dk3ma_ul_from_c8_hex_string(&chr, p1, NULL)) { if (0 == dk3uc2l_add_char_to_dir(uptr, pdir, chr, app)) { back = 0; $? "! failed to add %lx", chr } } else { /* ERROR: Syntax error, not a hexadecimal number */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 398); } } else { /* ERROR: Syntax error, missing configuration */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 400); } } } } if (1 == back) { $? ". copying ranges to global container" dk3sto_it_reset(pdir->i_ran); do { prange = dk3sto_it_next(pdir->i_ran); if (NULL != prange) { $? ". range %lx-%lx", (unsigned long)(prange->start), (unsigned long)(prange->end) if (0 == dk3sto_add(uptr->s_ran, prange)) { dk3uc2lat_range_delete(prange); back = 0; $? "! failed to copy range" } } } while (NULL != prange); } else { $? "! deleting ranges due to error" dk3sto_it_reset(pdir->i_ran); do { prange = dk3sto_it_next(pdir->i_ran); if (NULL != prange) { dk3uc2lat_range_delete(prange); } } while (NULL != prange); } $? "- dk3uc2l_apply_1 %d", back return back; } /** Apply directory information for a file. @param uptr Conversion structure to set up. @param fn File name containing conversion data. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3uc2lat_pass_1( dk3_uc2lat_t *uptr, const dkChar *fn, const dkChar *sn, dk3_app_t *app ) { dk3_uc2lat_dir_t *pdir = NULL; dk3_stream_t *istrm = NULL; FILE *fipo = NULL; const dkChar *oldsrc = NULL; const dkChar *fsuf = NULL; #if DK3_HAVE_ZLIB_H && (DK3_CHAR_SIZE == 1) gzFile gzf = NULL; #endif #if DK3_HAVE_BZLIB_H && (DK3_CHAR_SIZE == 1) BZFILE *bzf = NULL; #endif unsigned long oldln = 0UL; #if DK3_HAVE_FNCASEINS int fncs = 0; #else int fncs = 1; #endif int back = 0; $? ". dk3uc2lat_pass_1 %!ds", fn pdir = dk3uc2lat_dir_new(sn, app); if (NULL != pdir) { oldsrc = dk3app_get_source_file(app); oldln = dk3app_get_source_line(app); dk3app_set_source_file(app, fn); dk3app_set_source_line(app, 0UL); if (0 != dk3sto_add(uptr->s_dir, pdir)) { fsuf = dk3str_get_suffix(fn); switch (dk3str_array_index(dk3uc2l_co_suf, fsuf, fncs)) { case 0: { /* gz */ #if DK3_HAVE_ZLIB_H && (DK3_CHAR_SIZE == 1) gzf = gzopen(fn, "r"); if (NULL != gzf) { istrm = dk3stream_open_gz_app(gzf, DK3_STREAM_FLAG_READ, app); if (NULL != istrm) { back = dk3uc2l_apply_1(uptr, pdir, istrm, fn, sn, app); (void)dk3stream_close(istrm); } gzclose(gzf); } else { /* ERROR: Failed to open file */ dk3app_log_i3(uptr->app, DK3_LL_ERROR, 143, 144, fn); } #else /* ERROR: No zlib support */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 401); #endif } break; case 1: { /* bz2 */ #if DK3_HAVE_BZLIB_H && (DK3_CHAR_SIZE == 1) bzf = BZ2_bzopen(fn, "r"); if (NULL != bzf) { istrm = dk3stream_open_bz2_app(bzf, DK3_STREAM_FLAG_READ, app); if (NULL != istrm) { back = dk3uc2l_apply_1(uptr, pdir, istrm, fn, sn, app); (void)dk3stream_close(istrm); } BZ2_bzclose(bzf); } else { /* ERROR: Failed to open file */ dk3app_log_i3(uptr->app, DK3_LL_ERROR, 143, 144, fn); } #else /* ERROR: No bzip2 support */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 402); #endif } break; default : { /* normal file */ fipo = dk3sf_fopen_app(fn, dkT("r"), app); if (NULL != fipo) { istrm = dk3stream_open_file_app(fipo, DK3_STREAM_FLAG_READ, app); if (NULL != istrm) { back = dk3uc2l_apply_1(uptr, pdir, istrm, fn, sn, app); (void)dk3stream_close(istrm); } fclose(fipo); } } break; } } else { dk3uc2lat_dir_delete(pdir); } dk3app_set_source_file(app, oldsrc); dk3app_set_source_line(app, oldln); } $? "- dk3uc2lat_pass_1 %d", back return back; } /** Read directory information (check existing data files, retrieve ranges. @param d Directory containing the data files. @param uptr Conversion structure to initialize. @param app Application structure for diagnostics, may be NULL. @return 1 on success, 0 on error. */ static int dk3uc2lat_read_dir_info(dk3_uc2lat_t *uptr, dk3_app_t *app) { dk3_dir_t *dir = NULL; const dkChar *fn = NULL; const dkChar *sn = NULL; int back = 0; int found = 0; $? "+ dk3uc2lat_read_dir_info" dir = dk3dir_open_app(uptr->dir, uptr->app); if (NULL != dir) { back = 1; while (0 != dk3dir_get_next_file(dir)) { sn = dk3dir_get_shortname(dir); fn = dk3dir_get_fullname(dir); if ((NULL != sn) && (NULL != fn)) { if (0 != dk3uc2lat_is_suitable_file(fn)) { found = 1; if (0 == dk3uc2lat_pass_1(uptr, fn, sn, app)) { back = 0; } } } } dk3dir_close(dir); if (0 == found) { back = 0; /* ERROR: No suitable files found */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 403); } } $? "- dk3uc2lat_read_dir_info %d", back return back; } /** Allocate memory for all ranges details for a file directory. @param uptr Conversion structure to set up. @param pdir Directory information to set up. @return 1 on success, 0 on error. */ static int dk3uc2l_allocate_memory( dk3_uc2lat_t *uptr, dk3_uc2lat_dir_t *pdir ) { dk3_uc2lat_range_t *prange; size_t sz; size_t i; int back = 1; int allenc = 0; dk3sto_it_reset(pdir->i_ran); allenc = DK3_FONT_ENCODING_OT1 + DK3_FONT_ENCODING_T1 + DK3_FONT_ENCODING_T4 + DK3_FONT_ENCODING_T5; do { prange = (dk3_uc2lat_range_t *)dk3sto_it_next(pdir->i_ran); if (NULL != prange) { sz = (size_t)(prange->end - prange->start) + 1; if (NULL == prange->a) { prange->a = dk3_new_app(DK3_PCCHAR,sz,uptr->app); if (NULL != prange->a) { for (i = 0; i < sz; i++) { (prange->a)[i] = NULL; } } else { back = 0; } } if (NULL == prange->t) { prange->t = dk3_new_app(DK3_PCCHAR,sz,uptr->app); if (NULL != prange->t) { for (i = 0; i < sz; i++) { (prange->t)[i] = NULL; } } else { back = 0; } } if (NULL == prange->m) { prange->m = dk3_new_app(DK3_PCCHAR,sz,uptr->app); if (NULL != prange->m) { for (i = 0; i < sz; i++) { (prange->m)[i] = NULL; } } else { back = 0; } } #if HAVE_PACKAGES if (NULL == prange->p) { prange->p = dk3_new_app(dk3_uc2lat_pkg_pptr,sz,uptr->app); if (NULL != prange->p) { for (i = 0; i < sz; i++) { (prange->p)[i] = NULL; } } else { back = 0; } } #endif if (NULL == prange->f) { prange->f = dk3_new_app(dk3_font_encoding_t,sz,uptr->app); if (NULL != prange->f) { for(i = 0; i < sz; i++) { (prange->f)[i] = allenc; } } else { back = 0; } } } } while (NULL != prange); return back; } static void dk3uc2l_apply_2( dk3_uc2lat_t *uptr, dk3_uc2lat_dir_t *pdir, dk3_stream_t *istrm, const dkChar *filename ) { char buf[512]; /* Input line buffer */ #if HAVE_PACKAGES char *parts[16]; /* Package names */ #endif char *p1; /* Hex value or next item */ char *p2; /* Current item key */ char *p3; /* Current item value */ char *p4; /* Dynamic value copy */ dk3_uc2lat_range_t *prange; /* Current range */ #if HAVE_PACKAGES dk3_uc2lat_pkg_t *ppkg; /* Current package */ #endif unsigned long lineno = 0UL; /* Current line number */ unsigned long chr; /* Current character */ size_t ind; /* Index of chr in range */ #if HAVE_PACKAGES size_t nparts; /* Number of packages */ size_t i; /* Traverse */ size_t j; /* Add new packages */ #endif int cc = 1; /* Flag: Can continue */ int action; /* Action to take */ int isneg; /* Flag: Deny encodings */ int encod; /* Encodings selection */ $? "+ dk3uc2l_apply_2" while ((1 == cc) && (1 == dk3stream_c8_fgets(istrm, buf, sizeof(buf)))) { dk3app_set_source_line(uptr->app, ++lineno); buf[sizeof(buf) - 1] = '\0'; $? ". processing line %lu: %s", lineno, buf p1 = dk3str_c8_start(buf, NULL); if (NULL != p1) { $? ". p1=\"%!8s\"", p1 if ('#' != *p1) { $? ". normal line" p2 = dk3str_c8_next(p1, NULL); if (NULL != p2) { $? ". attributes=\"%!8s\"", p2 if (0 != dk3ma_ul_from_c8_hex_string(&chr, p1, NULL)) { prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(pdir->i_ran, &chr, 1); if (NULL != prange) { $? ". range found" ind = (size_t)(chr - prange->start); while (NULL != p2) { p1 = dk3str_c8_next(p2, NULL); p3 = dk3str_c8_chr(p2, '='); if (NULL != p3) { *(p3++) = '\0'; #if 0 /* 2015-08-10 Bugfix: Must be start */ p3 = dk3str_c8_next(p3, NULL); #endif p3 = dk3str_c8_start(p3, NULL); if (NULL != p3) { $? ". \"%!8s\"=\"%!8s\"", p2, p3 action = dk3str_c8_array_abbr(dk3uc2l_kw, p2, '$', 0); $? ". action = %d", action switch (action) { case 0: { /* both */ $? ". both" if (NULL != prange->a) { p4 = dk3str_c8_dup_app(p3, uptr->app); if (NULL != p4) { dk3_release((prange->a)[ind]); (prange->a)[ind] = p4; } } } break; case 1: { /* text */ $? ". text" if (NULL != prange->t) { p4 = dk3str_c8_dup_app(p3, uptr->app); if (NULL != p4) { dk3_release((prange->t)[ind]); (prange->t)[ind] = p4; } } } break; case 2: { /* math */ $? ". math" if (NULL != prange->m) { p4 = dk3str_c8_dup_app(p3, uptr->app); if (NULL != p4) { dk3_release((prange->m)[ind]); (prange->m)[ind] = p4; } } } break; case 3: { /* encoding */ $? ". encoding" if (NULL != prange->f) { isneg = 0; encod = 0; if ('!' == *p3) { isneg = 1; p3++; } while (NULL != p3) { p4 = dk3str_c8_chr(p3, ','); if (NULL != p4) { *(p4++) = '\0'; p4 = dk3str_c8_start(p4, NULL); } switch (dk3str_c8_array_index(dk3uc2l_enco, p3, 0)) { case 0: { /* OT1 */ encod |= DK3_FONT_ENCODING_OT1; } break; case 1: { /* T1 */ encod |= DK3_FONT_ENCODING_T1; } break; case 2: { /* T4 */ encod |= DK3_FONT_ENCODING_T4; } break; case 3: { /* T5 */ encod |= DK3_FONT_ENCODING_T5; } break; default : { /* Syntax error, unknown encoding */ dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 404); } break; } p3 = p4; } if (0 != isneg) { encod = (~(encod)); } (prange->f)[ind] = encod; } } break; case 4: { /* packages */ $? ". packages" #if HAVE_PACKAGES if (NULL != prange->p) { nparts = dk3str_c8_explode(parts, 15, p3, ","); if (0 < nparts) { dk3_release((prange->p)[ind]); (prange->p)[ind] = dk3_new_app(dk3_uc2lat_pkg_ptr,(nparts+1),uptr->app); if (NULL != (prange->p)[ind]) { for (i = 0; i < (nparts+1); i++) { ((prange->p)[ind])[i] = NULL; } j = 0; for (i = 0; i < nparts; i++) { ppkg = (dk3_uc2lat_pkg_t *)dk3sto_it_find_like( uptr->i_pkg, parts[i], 1 ); if (NULL != ppkg) { ((prange->p)[ind])[j++] = ppkg; } else { ppkg = dk3uc2lat_pkg_new(parts[i], uptr->app); if (NULL != ppkg) { if (dk3sto_add(uptr->s_pkg, ppkg)) { ((prange->p)[ind])[j++] = ppkg; } else { dk3uc2lat_pkg_delete(ppkg); } } } } } } else { /* ERROR: Syntax, no packages */ dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 405); } } #endif } break; default: { $? "! unknown key" } break; } } else { $? "! missing attribute value" /* ERROR: Value missing */ dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 406); } } else { $? "! missing attribute value" /* ERROR: Syntax, not a key value pair */ dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 406); } p2 = p1; } } else { $? "! bug: range not found" /* BUG or file changed */ } } else { /* ERROR: Syntax error, not a hexadecimal number */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 398); } } else { $? "! missing attributes" /* ERROR: Syntax error, missing configuration */ dk3app_log_i1(uptr->app, DK3_LL_ERROR, 401); } } else { $? ". ignore comment line" } } else { $? ". ignore empty line" } } $? "- dk3uc2l_apply_2" } static void dk3uc2lat_load_file(dk3_uc2lat_t *u, dk3_uc2lat_dir_t *pdir) { dkChar fnb[DK3_MAX_PATH]; dk3_stream_t *istrm = NULL; FILE *fipo = NULL; const dkChar *oldsrc = NULL; const dkChar *fsuf = NULL; #if DK3_HAVE_ZLIB_H && (DK3_CHAR_SIZE == 1) gzFile gzf = NULL; #endif #if DK3_HAVE_BZLIB_H && (DK3_CHAR_SIZE == 1) BZFILE *bzf = NULL; #endif unsigned long oldln = 0UL; #if DK3_HAVE_FNCASEINS int fncs = 0; #else int fncs = 1; #endif size_t sz; $? "+ dk3uc2lat_load_file" sz = dk3str_len(u->dir); sz += dk3str_len(pdir->sn); sz += 1; if (sizeof(fnb) > sz) { $? ". file name length ok" dk3str_cpy(fnb, u->dir); dk3str_cat(fnb, dk3app_not_localized(20)); dk3str_cat(fnb, pdir->sn); dk3str_correct_filename(fnb); oldsrc = dk3app_get_source_file(u->app); oldln = dk3app_get_source_line(u->app); dk3app_set_source_file(u->app, fnb); dk3app_set_source_line(u->app, 0UL); if (0 != dk3uc2l_allocate_memory(u, pdir)) { $? ". memory allocated" fsuf = dk3str_get_suffix(fnb); switch (dk3str_array_index(dk3uc2l_co_suf, fsuf, fncs)) { case 0: { $? ". zlib compressed" #if DK3_HAVE_ZLIB_H && (DK3_CHAR_SIZE == 1) gzf = gzopen(fnb, "r"); if (NULL != gzf) { istrm = dk3stream_open_gz_app(gzf, DK3_STREAM_FLAG_READ, u->app); if (NULL != istrm) { dk3uc2l_apply_2(u, pdir, istrm, fnb); (void)dk3stream_close(istrm); } gzclose(gzf); } else { /* ERROR: Failed to open file */ dk3app_log_i3(u->app, DK3_LL_ERROR, 143, 144, fnb); } #else /* ERROR: No zlib support */ dk3app_log_i1(u->app, DK3_LL_ERROR, 401); #endif } break; case 1: { $? ". bzip2 compressed" #if DK3_HAVE_BZLIB_H && (DK3_CHAR_SIZE == 1) bzf = BZ2_bzopen(fnb, "r"); if (NULL != bzf) { istrm = dk3stream_open_bz2_app(bzf, DK3_STREAM_FLAG_READ, u->app); if (NULL != istrm) { dk3uc2l_apply_2(u, pdir, istrm, fnb); (void)dk3stream_close(istrm); } BZ2_bzclose(bzf); } else { /* ERROR: Failed to open file */ dk3app_log_i3(u->app, DK3_LL_ERROR, 143, 144, fnb); } #else /* ERROR: No bzip2 support */ dk3app_log_i1(u->app, DK3_LL_ERROR, 402); #endif } break; default: { $? ". normal file" fipo = dk3sf_fopen_app(fnb, dkT("r"), u->app); if (NULL != fipo) { istrm = dk3stream_open_file_app(fipo, DK3_STREAM_FLAG_READ, u->app); if (NULL != istrm) { dk3uc2l_apply_2(u, pdir, istrm, fnb); (void)dk3stream_close(istrm); } fclose(fipo); } } break; } } else { $? "! memory allocation error" } dk3app_set_source_file(u->app, oldsrc); dk3app_set_source_line(u->app, oldln); } else { $? "! file name too long" /* ERROR: Name too long */ dk3app_log_i3(u->app, DK3_LL_ERROR, 65, 66, pdir->sn); } pdir->loaded = 0x01; $? "- dk3uc2lat_load_file" } /** Open conversion structure for a given directory. @param d Directory containing conversion files. @param f_desc Flag: Load glyph descriptions (ignored). @param f_utf8 Flag: UTF-8 output allowed. @param app Application structure for diagnostics, may be NULL. @return Pointer to new structure on success, NULL on error. */ static dk3_uc2lat_t * dk3uc2lat_i_open_app(const dkChar *d, int f_desc, int f_utf8, dk3_app_t *app) { dk3_uc2lat_t *back = NULL; $? "+ dk3uc2lat_i_open_app %!ds", d if (0 != dk3sf_is_dir_app(d, NULL)) { back = dk3uc2lat_t_new(d, f_utf8, app); if (NULL != back) { if (0 == dk3uc2lat_read_dir_info(back, app)) { dk3uc2lat_close(back); back = NULL; } } } else { /* ERROR: Not a directory ... */ dk3app_log_i3(app, DK3_LL_ERROR, 202, 203, d); } $? "- dk3uc2lat_i_open_app PTR:%d", TR_IPTR(back) return back; } dk3_uc2lat_t * dk3uc2lat_open_app(dkChar const *d, int f_desc, int f_utf8, dk3_app_t *app) { dkChar fnb[DK3_MAX_PATH]; dk3_uc2lat_t *back = NULL; const dkChar *shd = NULL; const dkChar *dirn = NULL; size_t szfnb = DK3_SIZEOF(fnb,dkChar); size_t szshd = 0; $? "+ dk3uc2lat_open_app %!ds", TR_DKSTR(d) if (NULL != d) { back = dk3uc2lat_i_open_app(d, f_desc, f_utf8, app); } else { if (NULL != app) { if (dk3app_get_dir_from_pref(app,dk3app_not_localized(48),fnb,szfnb,1)) { dk3str_correct_filename(fnb); back = dk3uc2lat_i_open_app(fnb, f_desc, f_utf8, app); } else { shd = dk3app_get_sharedir(app); if (NULL != shd) { szshd = dk3str_len(shd); if (szfnb > szshd) { dk3str_cpy_not_overlapped(fnb, shd); dirn = dk3app_not_localized(49); if (szfnb > (szshd + dk3str_len(dirn))) { dk3str_cat(fnb, dirn); dk3str_correct_filename(fnb); back = dk3uc2lat_i_open_app(fnb, f_desc, f_utf8, app); } else { /* ERROR: Directory name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 64, 66, dirn); } } else { /* ERROR: Share directory name too long! */ dk3app_log_i3(app, DK3_LL_ERROR, 64, 66, shd); } } else { /* ERROR: Missing share directory */ dk3app_log_i1(app, DK3_LL_ERROR, 407); } } } } $? "- dk3uc2lat_open_app %d", TR_IPTR(back) return back; } char const * dk3uc2lat_get(dk3_uc2lat_t *u, dk3_c32_t c32, int ismath) { dkChar cbuf[64]; dk3_uc2lat_range_t *prange = NULL; dk3_uc2lat_pkg_t **pkgpp; const char *back = NULL; size_t szcbuf = DK3_SIZEOF(cbuf,dkChar); $? "+ dk3uc2lat_get" if (NULL != u) { if (NULL != u->rca) { $? ". range cache available" if ((u->rca)->start <= c32) { $? ". start ok" if ((u->rca)->end >= c32) { $? ". end ok" prange = u->rca; $? ". use range cache" } } } if (NULL == prange) { $? ". find character" prange = dk3sto_it_find_like(u->i_ran, &c32, 1); if (NULL != prange) { $? ". range found" u->rca = prange; if (NULL != prange->p) { $? ". range->package" pkgpp = (prange->p)[(size_t)(c32 - prange->start)]; if (NULL != pkgpp) { while (NULL != *pkgpp) { (*(pkgpp++))->used = 0x01; } $? ". packages marked as used" } } } else { $? "! no range found" } } if (NULL != prange) { $? ". range found" if (NULL != prange->dir) { $? ". range has dir entry" if (0x00 == (prange->dir)->loaded) { $? ". must load" dk3uc2lat_load_file(u, prange->dir); } } if (0 != ismath) { $? ". math mode" if (NULL != prange->m) { $? ". math" back = (prange->m)[(size_t)(c32 - prange->start)]; } if (NULL == back) { if (NULL != prange->a) { $? ". all" back = (prange->a)[(size_t)(c32 - prange->start)]; } } } else { $? ". normal mode" if (NULL != prange->t) { $? ". text" back = (prange->t)[(size_t)(c32 - prange->start)]; } if (NULL == back) { $? ". all" if (NULL != prange->a) { back = (prange->a)[(size_t)(c32 - prange->start)]; } } } if (NULL != prange->f) { u->fe &= ((prange->f)[(size_t)(c32 - prange->start)]); } } else { /* ERROR: Not found */ if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)c32, 8)) { dk3app_log_i3(u->app, DK3_LL_ERROR, 409, 410, cbuf); } else { dk3app_log_i1(u->app, DK3_LL_ERROR, 408); } } } $? "- dk3uc2lat_get PTR:%d", TR_IPTR(back) return back; } #if HAVE_PACKAGES void dk3uc2lat_package_reset(dk3_uc2lat_t *u) { if (NULL != u) { dk3sto_it_reset(u->i_pkg); } } dk3_uc2lat_pkg_t * dk3uc2lat_package_next(dk3_uc2lat_t *u) { dk3_uc2lat_pkg_t *back = NULL; if (NULL != u) { back = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg); } return back; } #endif void dk3uc2lat_font_encoding_reset(dk3_uc2lat_t *u) { /* UNUSED */ } int dk3uc2lat_font_encoding_conflict(dk3_uc2lat_t *u) { int back = 0; /* UNUSED */ return back; } void dk3uc2lat_font_encoding_report_conflict(dk3_uc2lat_t *u) { if (0x00 == u->fe) { /* Error */ dk3app_log_i1(u->app, DK3_LL_ERROR, 411); } } static void dk3uc2lat_report_for_encoding(dk3_uc2lat_t *u, const char *eptr) { #if DK3_CHAR_SIZE > 1 dkChar buffer[32]; dkChar *dkptr = NULL; size_t szbu = DK3_SIZEOF(buffer,dkChar); if (szbu > strlen(eptr)) { dkptr = buffer; while ('\0' != *eptr) { *(dkptr++) = (dkChar)(*(eptr++)); } *dkptr = dkT('\0'); dk3app_log_i3(u->app, DK3_LL_INFO, 381, 382, buffer); } #else dk3app_log_i3(u->app, DK3_LL_INFO, 381, 382, eptr); #endif } void dk3uc2lat_font_encoding_report(dk3_uc2lat_t *u) { if (0 != ((u->fe) & DK3_FONT_ENCODING_OT1)) { dk3uc2lat_report_for_encoding(u, dk3uc2l_enco[0]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T1)) { dk3uc2lat_report_for_encoding(u, dk3uc2l_enco[1]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T4)) { dk3uc2lat_report_for_encoding(u, dk3uc2l_enco[2]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T5)) { dk3uc2lat_report_for_encoding(u, dk3uc2l_enco[3]); } } int dk3uc2lat_direct(dk3_c32_t c32) { int back = 0; char c; /* 8-bit character version of c32. */ $? "+ dk3uc2lat_direct %lx", (unsigned long)c32 if((unsigned long)c32 < 128UL) { 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 ' ': case '\t': { back = 1; } break; } } $? "- dk3uc2lat_direct %d", back return back; } static int dk3uc2lat_stputc(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t ul, int *mmptr) { char buf[16]; const char *ptr; size_t sz; int back = 0; if (0 != dk3uc2lat_direct(ul)) { if (0 != *mmptr) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); *mmptr = 0; } if (u->f_utf8) { sz = dk3enc_uc2utf8(ul, (unsigned char *)buf, sizeof(buf)); buf[sz] = '\0'; } else { buf[0] = (char)ul; buf[1] = '\0'; } dk3stream_c8_fputs(st, buf); back = 1; } else { ptr = dk3uc2lat_get(u, ul, 0); if (NULL != ptr) { if (0 != *mmptr) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); *mmptr = 0; } dk3stream_c8_fputs(st, ptr); } else { ptr = dk3uc2lat_get(u, ul, 1); if (NULL != ptr) { if (0 == *mmptr) { dk3stream_c8_fputs(st, dk3uc2lat_mm[0]); *mmptr = 1; } dk3stream_c8_fputs(st, ptr); } else { /* ERROR: Not found, already reported */ } } } return back; } int dk3uc2lat_c8_plain_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t) { int back = 0; int mm = 0; /* Flag: In math mode. */ char const *ptr; /* Current position. */ dk3_c32_t ul; /* Output character. */ char c; /* Current character. */ $? "+ dk3uc2lat_c8_plain_stputs \"%!8s\"", TR_8STR(t) if((u) && (st) && (t)) { ptr = t; back = 1; while(*ptr) { c = *ptr; ul = (unsigned long)c; ul &= 0x000000FFUL; if(!dk3uc2lat_stputc(u, st, ul, &mm)) { back = 0; } ptr++; } if(mm) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); } } $? "- dk3uc2lat_c8_plain_stputs %d", back return back; } int dk3uc2lat_c8_utf8_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t) { int back = 0; int mm = 0; /* Flag: Math mode. */ unsigned char const *sp; /* String pointer, current pos. */ size_t sl; /* Remaining bytes. */ size_t used; /* Bytes used for current c32. */ dk3_c32_t c32; /* Current character. */ $? "+ dk3uc2lat_c8_utf8_stputs \"%!8s\"", TR_8STR(t) if((u) && (st) && (t)) { sp = (unsigned char const *)t; sl = dk3str_c8_len(t); back = 1; while(sl) { used = 0; if(dk3enc_utf82uc(&c32, sp, sl, &used)) { if(!dk3uc2lat_stputc(u, st, c32, &mm)) { back = 0; } if(used) { if(sl >= used) { sl = sl - used; sp = &(sp[used]); } else { sl = 0; back = 0; } } else { sl = 0; back = 0; /* No byte used, will appear again and again. */ } } else { sl = 0; back = 0; if(u->app) { /* ERROR: Decoding failed! */ dk3app_log_i1(u->app, DK3_LL_ERROR, 118); } } } if(mm) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); } } $? "- dk3uc2lat_c8_utf8_stputs %d", back return back; } int dk3uc2lat_c16_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c16_t const *t) { int back = 0; int mm = 0; /* Flag: Math mode. */ dk3_c16_t const *sp; /* Current position. */ size_t sl; /* Number of 16-bit characters remaining. */ size_t used; /* Number of 16-bit characters used. */ dk3_c32_t c32; /* Current output character. */ $? "+ dk3uc2lat_c16_stputs %!8s", TR_8PTR(t) if((u) && (st) && (t)) { sp = t; sl = dk3str_c16_len(t); back = 1; while(sl) { used = 0; if(dk3enc_utf162uc(&c32, sp, sl, &used)) { if(used) { if(!dk3uc2lat_stputc(u, st, c32, &mm)) { back = 0; } if(sl >= used) { sl = sl - used; sp = &(sp[used]); } else { sl = 0; } } else { back = 0; sl = 0; if(u->app) { /* ERROR: Decoding */ dk3app_log_i1(u->app, DK3_LL_ERROR, 119); } } } else { sl = 0; back = 0; if(u->app) { /* Decoding error */ dk3app_log_i1(u->app, DK3_LL_ERROR, 119); } } } if(mm) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); } } $? "- dk3uc2lat_c16_stputs %d", back return back; } int dk3uc2lat_c32_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t const *t) { int back = 0; int mm = 0; /* Flag: Math mode. */ dk3_c32_t const *ptr; /* Current position. */ $? "+ dk3uc2lat_c32_stputs %!8s", TR_8PTR(t) if((u) && (st) && (t)) { back = 1; ptr = t; while(*ptr) { if(!dk3uc2lat_stputc(u, st, *(ptr++), &mm)) { back = 0; } } if(mm) { dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); } } $? "- dk3uc2lat_c32_stputs %d", back return back; } int dk3uc2lat_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dkChar const *t, int e) { int back = 0; $? "+ dk3uc2lat_stputs \"%!ds\"", TR_STR(t) #if DK3_CHAR_SIZE > 1 #if DK3_CHAR_SIZE > 2 back = dk3uc2lat_c32_stputs(u, st, t); #else back = dk3uc2lat_c16_stputs(u, st, t); #endif #else switch(e) { case DK3_ENCODING_UTF8: { back = dk3uc2lat_c8_utf8_stputs(u, st, t); } break; default: { back = dk3uc2lat_c8_plain_stputs(u, st, t); } break; } #endif $? "- dk3uc2lat_stputs %d", back return back; } void dk3uc2lat_final_report(dk3_uc2lat_t *u, dk3_stream_t *st) { dk3_uc2lat_pkg_t *pkgp; dk3stream_c8_fputs(st, dk3uc2lat_mm[2]); if (0 != ((u->fe) & DK3_FONT_ENCODING_OT1)) { dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[0]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T1)) { dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[1]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T4)) { dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[2]); } if (0 != ((u->fe) & DK3_FONT_ENCODING_T5)) { dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[3]); } dk3stream_c8_fputs(st, dk3uc2lat_mm[4]); dk3uc2lat_package_reset(u); do { pkgp = dk3uc2lat_package_next(u); if (NULL != pkgp) { $!trace-code if (NULL != pkgp->name) { $!trace-code if (0x00 != pkgp->used) { $? ". pkg used %!8s", pkgp->name $!trace-code } else { $? ". pkg not used %!8s", pkgp->name $!trace-code } $!trace-code } if ((0x00 != pkgp->used) && (NULL != pkgp->name)) { dk3stream_c8_fputs(st, dk3uc2lat_mm[3]); dk3stream_c8_fputs(st, pkgp->name); dk3stream_c8_fputs(st, dk3uc2lat_mm[4]); } } } while (NULL != pkgp); } /* vim: set ai sw=2 : */