%% options copyright owner = Dirk Krause copyright year = 2011-2014 license = bsd %% header #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 structurefor 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); /** 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); /** 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); #ifdef __cplusplus } #endif %% module #include "dk3all.h" $!trace-include /** LaTeX commands to start and end math mode. */ static char const * const dk3uc2lat_mm[] = { "\\(", "\\)", }; /** Font encoding names. */ static char const * const dk3uc2lat_font_encodings[] = { "ot1", "!ot1", "t1", "!t1", "t4", "!t4", "t5", "!t5", NULL }; /** Font encoding names, used in error messages. */ static dkChar const * const dk3uc2l_font_encoding_names[] = { dkT("OT1"), dkT("T1"), dkT("T4"), dkT("T5"), NULL }; /** 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; } /** 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; } /** 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; } /** Destroy package structure, release memory. @param pp Structure to release. */ static void dk3uc2lat_pkg_delete(dk3_uc2lat_pkg_t *pp) { $? "+ dk3uc2lat_pkg_delete %s", TR_PTR(pp) if(pp) { $? ". pkg name = \"%s\"", TR_STR(pp->name) dk3_release(pp->name); pp->used = 0x00; dk3_delete(pp); } $? "- dk3uc2lat_pkg_delete" } /** 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 \"%s\"", TR_STR(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 %s", TR_PTR(back) return back; } /** 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 %u", (unsigned)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. */ size_t i; /* Number of descriptions to release. */ $? "+ dk3uc2lat_range_delete %lx %lx", rp->start, 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; rp->start = (dk3_c32_t)0UL; rp->end = (dk3_c32_t)0UL; rp->ia = 0x00; } dk3_delete(rp); } $? "- dk3uc2lat_range_delete" } /** 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", start, 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; back->p = NULL; 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 %s", TR_PTR(back) return back; } /** 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 %s", TR_PTR(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" } /** 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 \"%s\"", 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 %s", TR_PTR(back) return back; } /** Process one of the directory input files. @param ucp Conversion structure. @param fn Full file name. @param sn Short file name. @return 1 on success, 0 on error. */ static int dk3uc2lat_read_dir_file( dk3_uc2lat_t *ucp, dkChar const *fn, dkChar const *sn ) { int back = 0; dkChar const *oldfilename = NULL; /* Previous source file name. */ unsigned long oldlineno = 0UL; /* Previous line number. */ unsigned long lineno = 0UL; /* Current line number. */ FILE *fipo = NULL; /* Input file. */ char il[1024]; /* Input line. */ dk3_uc2lat_dir_t *dp; /* Directory pointer. */ char *p1; /* Range start. */ char *p2; /* Range end. */ long l1; /* Range start. */ long l2; /* Range end. */ dk3_uc2lat_range_t ra; /* Range for tests. */ dk3_uc2lat_range_t *rp; /* Range pointer. */ $? "+ dk3uc2lat_read_dir_file \"%s\"", TR_STR(sn) /* Save old source file position. */ if(ucp->app) { oldfilename = dk3app_get_source_file(ucp->app); oldlineno = dk3app_get_source_line(ucp->app); dk3app_set_source_file(ucp->app, fn); dk3app_set_source_line(ucp->app, lineno); } /* Process file. */ dp = dk3uc2lat_dir_new(sn, ucp->app); if(dp) { if(dk3sto_add(ucp->s_dir, dp)) { fipo = dk3sf_fopen_app(fn, dk3app_not_localized(22), ucp->app); if(fipo) { back = 1; while(fgets(il, sizeof(il), fipo)) { p1 = dk3str_c8_start(il, NULL); if(p1) { if(*p1 != '#') { p2 = dk3str_c8_next(p1, NULL); if(p2) { if(sscanf(p1, "%lx", &l1) == 1) { if(sscanf(p2, "%lx", &l2) == 1) { /* Range recognized. */ ra.start = (dk3_c32_t)l1; ra.end = (dk3_c32_t)l2; rp = (dk3_uc2lat_range_t *)dk3sto_it_find_like(ucp->i_ran, (void *)(&ra), 0); if(rp) { if(ucp->app) { dk3app_log_i1(ucp->app, DK3_LL_ERROR, 221); } back = 0; } else { rp = dk3uc2lat_range_new(ra.start, ra.end, dp, ucp->app); if(rp) { if(dk3sto_add(ucp->s_ran, (void *)rp)) { if(!dk3sto_add(dp->s_ran, (void *)rp)) { back = 0; } } else { back = 0; dk3uc2lat_range_delete(rp); rp = NULL; } } } } else { if(ucp->app) { dk3app_log_i1(ucp->app, DK3_LL_ERROR, 222); } back = 0; } } else { if(ucp->app) { /* ERROR: Not a hex number. */ dk3app_log_i1(ucp->app, DK3_LL_ERROR, 222); } back = 0; } } else { if(ucp->app) { /* Syntax error! */ dk3app_log_i1(ucp->app, DK3_LL_ERROR, 223); } back = 0; } } /* Ignore comments. */ } /* Ignore empty lines. */ } fclose(fipo); } } else { dk3uc2lat_dir_delete(dp); } } /* Restore old source file position. */ if(ucp->app) { dk3app_set_source_file(ucp->app, oldfilename); dk3app_set_source_line(ucp->app, oldlineno); } $? "- dk3uc2lat_read_dir_file %d", back return back; } /** Read UC to LaTeX conversion directory. @param ucp Conversion structure. @return 1 on success, 0 on error. */ static int dk3uc2lat_read_directory(dk3_uc2lat_t *ucp) { int back = 0; int found = 0; /* Flag: At least one matching file. */ int res; /* File processing result. */ dkChar const *sn; /* Short file name. */ dkChar const *fn; /* Full file name. */ dkChar const *sf; /* File suffix. */ dk3_dir_t *dir; /* Directory traversal structure. */ $? "+ dk3uc2lat_read_directory" dir = dk3dir_open_app(ucp->dir, ucp->app); if(dir) { back = 1; while(dk3dir_get_next_file(dir)) { sn = dk3dir_get_shortname(dir); fn = dk3dir_get_fullname(dir); if((sn) && (fn)) { sf = dk3str_get_suffix(fn); if(sf) { if(dk3str_fncmp(sf, dk3app_not_localized(54)) == 0) { found = 1; dk3app_log_i3(ucp->app, DK3_LL_DEBUG, 236, 237, fn); res = dk3uc2lat_read_dir_file(ucp, fn, sn); if(!res) { back = 0; } } else { /* Not a *.dir file, ignore this file. */ } } else { /* No suffix, ignore this file. */ } } else { /* BUG */ } } dk3dir_close(dir); if(0 == found) { back = 0; /* ##### ERROR: No file found! */ } } $? "- dk3uc2lat_read_directory %d", back return back; } int dk3uc2lat_direct(dk3_c32_t c32) { int back = 0; char c; /* 8-bit character version of c32. */ $? "+ dk3uc2lat_direct %lx", 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 ' ': { back = 1; } break; } } $? "- dk3uc2lat_direct %d", back return back; } dk3_uc2lat_t * dk3uc2lat_open_app(dkChar const *d, int f_desc, int f_utf8, dk3_app_t *app) { dk3_uc2lat_t *back = NULL; dkChar const *dn; /* Directory name pointer. */ dkChar bu[DK3_MAX_PATH]; /* Buffer for directory. */ int ok = 0; /* Flag: Success. */ dkChar *p1; /* Start of preference value. */ dkChar const *p2; /* Share directory. */ $? "+ dk3uc2lat_open_app \"%s\" %d", TR_STR(d), f_desc if((d) || (app)) { back = dk3_new_app(dk3_uc2lat_t,1,app); if(back) { /* Initialize new structure. */ back->dir = NULL; back->app = app; back->buf = NULL; back->s_ran = NULL; back->i_ran = NULL; back->s_dir = NULL; back->i_dir = NULL; back->s_pkg = NULL; back->i_pkg = NULL; back->rca = NULL; back->szbuf = 0; back->f_dsc = f_desc; back->f_utf8 = f_utf8; back->fe = (dk3_font_encoding_t)0x00; /* Search for directory name. */ dn = NULL; if(d) { if(dk3str_len(d) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, d); dk3str_correct_filename(bu); if(app) { dk3app_log_i3(app, DK3_LL_DEBUG, 234, 235, bu); } if(dk3sf_is_dir_app(bu, app)) { dn = bu; } } } if((!(dn)) && (app)) { if(dk3app_get_pref(app,dk3app_not_localized(48),bu,DK3_SIZEOF(bu,dkChar))) { p1 = dk3str_start(bu, NULL); if(p1) { dk3str_chomp(p1, NULL); dk3str_correct_filename(p1); if(app) { dk3app_log_i3(app, DK3_LL_DEBUG, 234, 235, bu); } if(dk3sf_is_dir_app(p1, app)) { dn = p1; } } } } if((!(dn)) && (app)) { p2 = dk3app_get_sharedir(app); if(p2) { if((dk3str_len(p2)) < DK3_SIZEOF(bu,dkChar)) { dk3str_cpy_not_overlapped(bu, p2); p2 = dk3app_not_localized(49); if((dk3str_len(p2) + dk3str_len(bu)) < DK3_SIZEOF(bu,dkChar)) { dk3str_cat(bu, p2); dk3str_correct_filename(bu); if(app) { dk3app_log_i3(app, DK3_LL_DEBUG, 234, 235, bu); } if(dk3sf_is_dir_app(bu, app)) { dn = bu; } } } } } /* Allocate internal data structures. */ ok = 0; if(dn) { if(app) { dk3app_log_i3(app, DK3_LL_DEBUG, 232, 233, dn); } back->dir = dk3str_dup_app(dn, app); if(back->dir) { back->buf = dk3_new_app(char,16,app); if(back->buf) { back->szbuf = 16; 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->s_dir = dk3sto_open_app(app); if(back->s_dir) { dk3sto_set_comp(back->s_dir, dk3uc2lat_dir_compare, 0); back->i_dir = dk3sto_it_open(back->s_dir); if(back->i_dir) { back->s_pkg = dk3sto_open_app(app); if(back->s_pkg) { dk3sto_set_comp(back->s_pkg, dk3uc2lat_pkg_compare, 0); back->i_pkg = dk3sto_it_open(back->s_pkg); if(back->i_pkg) { ok = dk3uc2lat_read_directory(back); } } } } } } } } } /* Destroy object if initialization did not succeed. */ if(!(ok)) { dk3uc2lat_close(back); back = NULL; } } } $? "- dk3uc2lat_open_app %s", TR_PTR(back) return back; } void dk3uc2lat_close(dk3_uc2lat_t *u) { dk3_uc2lat_range_t *rp; /* Range pointer. */ dk3_uc2lat_dir_t *dp; /* Directory pointer. */ dk3_uc2lat_pkg_t *pp; /* Package pointer. */ $? "+ dk3uc2lat_close" if(u) { if(u->s_ran) { if(u->i_ran) { dk3sto_it_reset(u->i_ran); while((rp = (dk3_uc2lat_range_t *)dk3sto_it_next(u->i_ran)) != NULL) { /* DELETE RANGE */ dk3uc2lat_range_delete(rp); } dk3sto_it_close(u->i_ran); } dk3sto_close(u->s_ran); } u->s_ran = NULL; u->i_ran = NULL; if(u->s_dir) { if(u->i_dir) { dk3sto_it_reset(u->i_dir); while((dp = (dk3_uc2lat_dir_t *)dk3sto_it_next(u->i_dir)) != NULL) { /* DELETE DIR */ dk3uc2lat_dir_delete(dp); } dk3sto_it_close(u->i_dir); } dk3sto_close(u->s_dir); } u->s_dir = NULL; u->i_dir = NULL; if(u->s_pkg) { if(u->i_pkg) { dk3sto_it_reset(u->i_pkg); while((pp = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg)) != NULL) { /* DELETE PACKAGE */ dk3uc2lat_pkg_delete(pp); } dk3sto_it_close(u->i_pkg); } dk3sto_close(u->s_pkg); } u->s_pkg = NULL; u->i_pkg = NULL; dk3_release(u->buf); dk3_release(u->dir); u->szbuf = 0; u->app = NULL; dk3_delete(u); } $? "- dk3uc2lat_close" } /** Initialize a range (allocate the array of pointers). @param ra Range to initialize. @param f_desc Flag: Allocate pointer array for descriptions too. @param app Application structure for diagnostics. */ static void dk3uc2lat_initialize_range(dk3_uc2lat_range_t *ra, int f_desc, dk3_app_t *app) { size_t sz; /* Number of elements in range. */ size_t i; /* Traverse range. */ $? "+ dk3uc2lat_initialize_range %lx %lx", ra->start, ra->end sz = (size_t)(ra->end - ra->start + 1UL); ra->a = dk3_new_app(DK3_PCCHAR,sz,app); if(ra->a) { for(i = 0; i < sz; i++) { (ra->a)[i] = NULL; } } ra->t = dk3_new_app(DK3_PCCHAR,sz,app); if(ra->t) { for(i = 0; i < sz; i++) { (ra->t)[i] = NULL; } } ra->m = dk3_new_app(DK3_PCCHAR,sz,app); if(ra->m) { for(i = 0; i < sz; i++) { (ra->m)[i] = NULL; } } ra->p = dk3_new_app(dk3_uc2lat_pkg_ptr,sz,app); if(ra->p) { for(i = 0; i < sz; i++) { (ra->p)[i] = NULL; } } ra->f = dk3_new_app(dk3_font_encoding_t,sz,app); if(ra->f) { for(i = 0; i < sz; i++) { (ra->f)[i] = (dk3_font_encoding_t)0; } } if(f_desc) { ra->dsc = dk3_new_app(DK3_PCDKCHAR,sz,app); if(ra->dsc) { for(i = 0; i < sz; i++) { (ra->dsc)[i] = NULL; } } } ra->ia = 0x01; $? "- dk3uc2lat_initialize_range" } /** Save text entry to pointer. @param d Address of destination pointer. @param s Source text. @param a Application structure for diagnostics. @param c32 Character. @param m Flag: Math mode (probably used in error message). */ static void dk3uc2lat_save_text( char const **d, char const *s, dk3_app_t *a, dk3_c32_t c32, int m ) { char const *nc; /* New copy. */ $? "+ dk3cu2lat_save_text \"%s\"", TR_STR(s) nc = dk3str_c8_dup_app(s, a); if(nc) { $? ". new copy ok" if(*d) { dk3_release(*d); if(a) { /* ERROR: Redefinition for c32 in m mode! */ dk3app_log_i1(a, DK3_LL_ERROR, 224); } } *d = nc; } $? "- dk3cu2lat_save_text" } /** Load data for one directory file. @param u Conversion object. @param udir Directory to load. */ static void dk3uc2lat_load_directory_data(dk3_uc2lat_t *u, dk3_uc2lat_dir_t *udir) { dk3_uc2lat_range_t *ra; /* Current range to process. */ dkChar fnb[DK3_MAX_PATH]; /* Construct file name. */ dkChar *ptr; /* File name suffix of directory file. */ char il[256]; /* Input line. */ int ok = 0; /* Flag: Data file name ok. */ dkChar const *oldsourcename = NULL; /* Old source file name. */ unsigned long oldsourceline = 0UL; /* Old source file line. */ long l; /* Current 32-bit character. */ dk3_c32_t c32; /* Current 32-bit character. */ char *p1; /* Start of data line. */ char *p2; /* Closing square bracket. */ size_t sz; /* File name length / data position index. */ dk3_uc2lat_pkg_t *pa; /* Package. */ FILE *fipo; /* Input file. */ unsigned long lineno = 0UL; /* Current line number. */ $? "+ dk3uc2lat_load_directory_data" c32 = 0UL; /* Allocate memory to store the information. */ dk3sto_it_reset(udir->i_ran); while((ra = (dk3_uc2lat_range_t *)dk3sto_it_next(udir->i_ran)) != NULL) { if(!(ra->ia)) { dk3uc2lat_initialize_range(ra, u->f_dsc, u->app); } } /* Create file name for data file. */ $? ". create file name for data file" dk3str_cpy_not_overlapped(fnb, u->dir); $? ". dir=\"%s\"", fnb sz = dk3str_len(fnb) + dk3str_len(dk3app_not_localized(20)) + dk3str_len(udir->sn); if(sz < DK3_SIZEOF(fnb,dkChar)) { $? ". file name size ok" dk3str_cat(fnb, dk3app_not_localized(20)); $? ". name=\"%s\"", fnb dk3str_cat(fnb, udir->sn); dk3str_correct_filename(fnb); ptr = dk3str_get_suffix(fnb); if(ptr) { *ptr = dkT('\0'); $? ". without suffix \"%s\"", fnb sz = dk3str_len(fnb) + dk3str_len(dk3app_not_localized(55)); if(sz < DK3_SIZEOF(fnb,dkChar)) { $? ". size ok" dk3str_cat(fnb, dk3app_not_localized(55)); ok = 1; $? ". load file \"%s\"", fnb } else { $? "! file name size too long" } } } else { $? "! file name too long" } /* Load information from data file. */ if(ok) { $? ". file name \"%s\"", fnb if(u->app) { oldsourcename = dk3app_get_source_file(u->app); oldsourceline = dk3app_get_source_line(u->app); dk3app_set_source_file(u->app, fnb); dk3app_set_source_line(u->app, 0UL); dk3app_log_i3(u->app, DK3_LL_DEBUG, 240, 241, fnb); } fipo = dk3sf_fopen_app(fnb, dk3app_not_localized(22), u->app); if(fipo) { $? ". file opened" ra = NULL; sz = 0; while(fgets(il, sizeof(il), fipo)) { lineno++; if(u->app) { dk3app_set_source_line(u->app, lineno); } dk3str_c8_delnl(il); $? ". line \"%s\"", il p1 = dk3str_c8_start(il, NULL); if(p1) { $? ". contents \"%s\"", p1 if(*p1 != '#') { $? ". not a comment" if(*p1 == '[') { $? ". new section" ra = NULL; sz = 0; p1++; p2 = dk3str_c8_chr(p1, ']'); if(p2) { *p2 = '\0'; } else { if(u->app) { /* ERROR: Syntax, missing closing bracket. */ dk3app_log_i1(u->app, DK3_LL_ERROR, 223); } } if(sscanf(p1, "%lx", &l) == 1) { $? ". character %lx", l c32 = (dk3_c32_t)l; ra = (dk3_uc2lat_range_t *)dk3sto_it_find_like( u->i_ran, (void *)(&c32), 1 ); if(ra) { $? ". range found" sz = (size_t)(c32 - ra->start); /* Success. */ } else { $? "! no range for char" if(u->app) { /* ERROR: Range not declared in directory. */ dk3app_log_i1(u->app, DK3_LL_ERROR, 225); } } } else { $? "! not a hex number" if(u->app) { /* ERROR: Syntax, not a hex number. */ dk3app_log_i1(u->app, DK3_LL_ERROR, 222); } } } else { $? ". data line" if(ra) { if(!(ra->ia)) { $? ". must initialize range" dk3uc2lat_initialize_range(ra, u->f_dsc, u->app); } switch(*p1) { case 'l': { $? ". l line" if(ra->a) { p1++; dk3uc2lat_save_text(&((ra->a)[sz]), p1, u->app, c32, 0); } } break; case 't': { $? ". t line" if(ra->t) { p1++; dk3uc2lat_save_text(&((ra->t)[sz]), p1, u->app, c32, 1); } } break; case 'm': { $? ". m line" if(ra->m) { p1++; dk3uc2lat_save_text(&((ra->m)[sz]), p1, u->app, c32, 2); } } break; case 'p': { $? ". p line" if(ra->p) { p1++; pa = (dk3_uc2lat_pkg_t *)dk3sto_it_find_like( u->i_pkg, p1, 1 ); if(pa) { $? ". package already registered" if((ra->p)[sz]) { if(u->app) { /* Warning: Overwriting package. */ dk3app_log_i1(u->app, DK3_LL_WARNING, 226); } } (ra->p)[sz] = pa; } else { $? ". register new package" pa = dk3uc2lat_pkg_new(p1, u->app); if(pa) { $? ". new package ok" if(dk3sto_add(u->s_pkg, pa)) { $? ". add ok" if((ra->p)[sz]) { if(u->app) { /* Warning: Overwriting package. */ dk3app_log_i1(u->app, DK3_LL_WARNING, 226); } } (ra->p)[sz] = pa; } else { $? "! add" dk3uc2lat_pkg_delete(pa); pa = NULL; } } else { $? "! failed to create package info" } } } } break; case 'e': { $? ". encoding line" p1++; if(ra->f) { switch(dk3str_c8_array_index(dk3uc2lat_font_encodings,p1,0)) { case 0: { (ra->f)[sz] |= DK3_FONT_ENCODING_OT1; } break; case 1: { (ra->f)[sz] |= DK3_FONT_ENCODING_NOT_OT1; } break; case 2: { (ra->f)[sz] |= DK3_FONT_ENCODING_T1; } break; case 3: { (ra->f)[sz] |= DK3_FONT_ENCODING_NOT_T1; } break; case 4: { (ra->f)[sz] |= DK3_FONT_ENCODING_T4; } break; case 5: { (ra->f)[sz] |= DK3_FONT_ENCODING_NOT_T4; } break; case 6: { (ra->f)[sz] |= DK3_FONT_ENCODING_T5; } break; case 7: { (ra->f)[sz] |= DK3_FONT_ENCODING_NOT_T5; } break; } } } break; } } /* else: No range for character, already reported. */ } } /* else: Ignore comment lines. */ } /* else: Ignore empty lines. */ } fclose(fipo); } else { $? "! failed to open file" } if(u->app) { dk3app_set_source_file(u->app, oldsourcename); dk3app_set_source_line(u->app, oldsourceline); } } udir->loaded = 0x01; $? "- dk3uc2lat_load_directory_data" } char const * dk3uc2lat_get(dk3_uc2lat_t *u, dk3_c32_t c32, int ismath) { char const *back = NULL; size_t sz; /* Buffer length used. */ dk3_uc2lat_pkg_t *cpkg; /* Current package. */ $? "+ dk3uc2lat_get %lx math=%d", c32, ismath if(u) { if(dk3uc2lat_direct(c32)) { if(u->f_utf8) { sz = dk3enc_uc2utf8(c32, (unsigned char *)(u->buf), u->szbuf); (u->buf)[sz] = '\0'; } else { (u->buf)[0] = (char)c32; (u->buf)[1] = '\0'; } back = u->buf; } else { if(u->rca) { if(u->rca->start > c32) { u->rca = NULL; } else { if(u->rca->end < c32) { u->rca = NULL; } } } if(!(u->rca)) { u->rca = (dk3_uc2lat_range_t *)dk3sto_it_find_like( u->i_ran, (void *)(&c32), 1 ); } if(u->rca) { if(!(u->rca->ia)) { dk3uc2lat_initialize_range(u->rca, u->f_dsc, u->app); } if(!(u->rca->dir->loaded)) { dk3uc2lat_load_directory_data(u, u->rca->dir); } sz = (size_t)(c32 - u->rca->start); if((u->rca)->f) { u->fe |= (((u->rca)->f)[sz]); } if(ismath) { if(u->rca->m) { back = (u->rca->m)[sz]; } if(!(back)) { if(u->rca->a) { back = (u->rca->a)[sz]; } } } else { if(u->rca->t) { back = (u->rca->t)[sz]; } if(!(back)) { if(u->rca->a) { back = (u->rca->a)[sz]; } } } cpkg = NULL; if(u->rca->p) { $? ". range has packages array" cpkg = (u->rca->p)[sz]; if(cpkg) { $? ". package info \"%s\"", TR_STR(cpkg->name) cpkg->used = 0x01; $? ". package marked as used" } } } else { if(u->app) { /* No such range in directory files. */ dk3app_log_i1(u->app, DK3_LL_WARNING, 225); } } } } $? "- dk3uc2lat_get \"%s\"", TR_STR(back) return back; } /** Write LaTeX encoding for one 32-bit character to stream. @param u LaTeX encoder. @param st Stream to write to. @param c32 Character to write. @param mm Pointer to math mode flag variable. @return 1 on success, 0 on error. */ static int dk3uc2lat_stputc(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t c32, int *mm) { int back = 0; char const *string; /* LaTeX encoding for c32. */ string = dk3uc2lat_get(u, c32, 0); if(string) { if(*mm) { *mm = 0; dk3stream_c8_fputs(st, dk3uc2lat_mm[1]); } dk3stream_c8_fputs(st, string); back = 1; } else { string = dk3uc2lat_get(u, c32, 1); if(string) { if(*mm == 0) { *mm = 1; dk3stream_c8_fputs(st, dk3uc2lat_mm[0]); } dk3stream_c8_fputs(st, string); back = 1; } } 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 \"%s\"", TR_STR(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 \"%s\"", TR_STR(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 \"%ls\"", 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 %s", TR_PTR(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 \"%s\"", 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_package_reset(dk3_uc2lat_t *u) { $? "+ dk3_uc2lat_package_reset" if(u) { if(u->i_pkg) { dk3sto_it_reset(u->i_pkg); } } $? "- dk3_uc2lat_package_reset" } dk3_uc2lat_pkg_t * dk3uc2lat_package_next(dk3_uc2lat_t *u) { dk3_uc2lat_pkg_t *back = NULL; $? "+ dk3_uc2lat_pkg_t" if(u) { if(u->i_pkg) { back = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg); } } $? "- dk3_uc2lat_pkg_t %s", TR_PTR(back) return back; } void dk3uc2lat_font_encoding_reset(dk3_uc2lat_t *u) { if(u) { u->fe = (dk3_font_encoding_t)0; } } int dk3uc2lat_font_encoding_conflict(dk3_uc2lat_t *u) { int i; /* Index of current encoding. */ int back = 0; /* Function result. */ dk3_font_encoding_t fe; /* Encoding. */ dk3_font_encoding_t m; /* Mask for tests. */ if(u) { fe = u->fe; m = DK3_FONT_ENCODING_OT1 | DK3_FONT_ENCODING_T1 | DK3_FONT_ENCODING_T4 | DK3_FONT_ENCODING_T5; switch(fe & m) { case DK3_FONT_ENCODING_NONE: case DK3_FONT_ENCODING_OT1: case DK3_FONT_ENCODING_T1: case DK3_FONT_ENCODING_T4: case DK3_FONT_ENCODING_T5: { } break; default: { /* Multiple encodings required. */ back = 1; } break; } m = DK3_FONT_ENCODING_NOT_OT1 | DK3_FONT_ENCODING_NOT_T1 | DK3_FONT_ENCODING_NOT_T4 | DK3_FONT_ENCODING_NOT_T5; if(m == ((u->fe) & m)) { back = 1; /* All encodings denied! */ } for(i = 0; i < 4; i++) { switch(i) { case 0: { m = DK3_FONT_ENCODING_OT1 | DK3_FONT_ENCODING_NOT_OT1; } break; case 1: { m = DK3_FONT_ENCODING_T1 | DK3_FONT_ENCODING_NOT_T1; } break; case 2: { m = DK3_FONT_ENCODING_T4 | DK3_FONT_ENCODING_NOT_T4; } break; case 3: { m = DK3_FONT_ENCODING_T5 | DK3_FONT_ENCODING_NOT_T5; } break; } if(m == (fe & m)) { back = 1; /* Encoding both required and denied. */ } } } return back; } void dk3uc2lat_font_encoding_report_conflict(dk3_uc2lat_t *u) { int i; /* Index of current encoding. */ dk3_font_encoding_t fe; /* Font encoding. */ dk3_font_encoding_t m; /* Mask for tests. */ if(u) { if((u->app) && (dk3uc2lat_font_encoding_conflict(u))) { fe = u->fe; m = DK3_FONT_ENCODING_OT1 | DK3_FONT_ENCODING_T1 | DK3_FONT_ENCODING_T4 | DK3_FONT_ENCODING_T5; switch(fe & m) { case DK3_FONT_ENCODING_NONE: case DK3_FONT_ENCODING_OT1: case DK3_FONT_ENCODING_T1: case DK3_FONT_ENCODING_T4: case DK3_FONT_ENCODING_T5: { } break; default: { /* Multiple encodings required. */ dk3app_log_i1(u->app, DK3_LL_ERROR, 378); } break; } m = DK3_FONT_ENCODING_NOT_OT1 | DK3_FONT_ENCODING_NOT_T1 | DK3_FONT_ENCODING_NOT_T4 | DK3_FONT_ENCODING_NOT_T5; if(m == ((u->fe) & m)) { /* All encodings denied! */ dk3app_log_i1(u->app, DK3_LL_ERROR, 385); } for(i = 0; i < 4; i++) { switch(i) { case 0: { m = DK3_FONT_ENCODING_OT1 | DK3_FONT_ENCODING_NOT_OT1; } break; case 1: { m = DK3_FONT_ENCODING_T1 | DK3_FONT_ENCODING_NOT_T1; } break; case 2: { m = DK3_FONT_ENCODING_T4 | DK3_FONT_ENCODING_NOT_T4; } break; case 3: { m = DK3_FONT_ENCODING_T5 | DK3_FONT_ENCODING_NOT_T5; } break; } if(m == (fe & m)) { /* Encoding both required and denied. */ dk3app_log_i3( u->app, DK3_LL_ERROR, 379, 380, dk3uc2l_font_encoding_names[i] ); } } } } } void dk3uc2lat_font_encoding_report(dk3_uc2lat_t *u) { int i; /* Index of current encoding. */ dk3_font_encoding_t m; /* Mask for tests. */ if(u) { if(u->app) { if(dk3uc2lat_font_encoding_conflict(u)) { dk3uc2lat_font_encoding_report_conflict(u); } else { m = DK3_FONT_ENCODING_OT1 | DK3_FONT_ENCODING_T1 | DK3_FONT_ENCODING_T4 | DK3_FONT_ENCODING_T5; switch(m & (u->fe)) { case 0: { for(i = 0; i < 4; i++) { switch(i) { case 0: { m = DK3_FONT_ENCODING_NOT_OT1; } break; case 1: { m = DK3_FONT_ENCODING_NOT_T1; } break; case 2: { m = DK3_FONT_ENCODING_NOT_T4; } break; case 3: { m = DK3_FONT_ENCODING_NOT_T5; } break; } if(m & (u->fe)) { dk3app_log_i3( u->app, DK3_LL_INFO, 383, 384, dk3uc2l_font_encoding_names[i] ); } } } break; case DK3_FONT_ENCODING_OT1: { dk3app_log_i3( u->app, DK3_LL_INFO, 381, 382, dk3uc2l_font_encoding_names[0] ); } break; case DK3_FONT_ENCODING_T1: { dk3app_log_i3( u->app, DK3_LL_INFO, 381, 382, dk3uc2l_font_encoding_names[1] ); } break; case DK3_FONT_ENCODING_T4: { dk3app_log_i3( u->app, DK3_LL_INFO, 381, 382, dk3uc2l_font_encoding_names[2] ); } break; case DK3_FONT_ENCODING_T5: { dk3app_log_i3( u->app, DK3_LL_INFO, 381, 382, dk3uc2l_font_encoding_names[3] ); } break; } } } } } /* vim: set ai sw=2 : */