1%%	options
2
3copyright owner	=	Dirk Krause
4copyright year	=	2011-xxxx
5SPDX-License-Identifier:	BSD-3-Clause
6
7
8
9%%	header
10
11/**	@file	dk3uc2l.h	32-bit character to LaTeX conversion.
12
13This module was rewritten in August 2015, so it uses the same *.t2l files
14as the dk4uc2l module.
15During this rewrite the functionality was stripped down to those functions
16used by the itadmin program.
17
18*/
19
20#include "dk3conf.h"
21#include <libdk3c/dk3types.h>
22
23#ifdef __cplusplus
24extern "C" {
25#endif
26
27/**	Open LaTeX encoder.
28	@param	d	Directory containing the tables.
29	@param	f_utf8	Flag: UTF-8 output encoding.
30	@param	app	Application structure for diagnostics, may be NULL.
31	@return	Pointer to new encoder on success, NULL on error.
32*/
33dk3_uc2lat_t *
34dk3uc2lat_open_app(dkChar const *d, int f_utf8, dk3_app_t *app);
35
36/**	Close LaTeX encoder.
37	@param	u	Encoder to close.
38*/
39void
40dk3uc2lat_close(dk3_uc2lat_t *u);
41
42/**	Retrieve LaTeX encoding for one 32-bit character.
43	@param	u	LaTeX encoder.
44	@param	c32	Character to obtain LaTeX encoding for.
45	@param	ismath	Flag: In math mode.
46	@return	Pointer to encoding on success, NULL on error.
47*/
48char const *
49dk3uc2lat_get(dk3_uc2lat_t *u, dk3_c32_t c32, int ismath);
50
51/**	Check whether a character can be written to a LaTeX file directly.
52	@param	c32	Character to check.
53	@return	1 for yes, 0 for no.
54*/
55int
56dk3uc2lat_direct(dk3_c32_t c32);
57
58/**	Write LaTeX encoding for a string to a stream.
59	@param	u	LaTeX encoder.
60	@param	st	Stream to write to.
61	@param	t	Text to write (ASCII/ISO-LATIN-1 encoded).
62	@return	1 on success, 0 on error.
63*/
64int
65dk3uc2lat_c8_plain_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t);
66
67/**	Write LaTeX encoding for a string to a stream.
68	@param	u	LaTeX encoder.
69	@param	st	Stream to write to.
70	@param	t	Text to write (UTF-8 encoded).
71	@return	1 on success, 0 on error.
72*/
73int
74dk3uc2lat_c8_utf8_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t);
75
76/**	Write LaTeX encoding for a string to a stream.
77	@param	u	LaTeX encoder.
78	@param	st	Stream to write to.
79	@param	t	Text to write (UTF-16 encoded).
80	@return	1 on success, 0 on error.
81*/
82int
83dk3uc2lat_c16_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c16_t const *t);
84
85/**	Write LaTeX encoding for a string to a stream.
86	@param	u	LaTeX encoder.
87	@param	st	Stream to write to.
88	@param	t	Text to write (32-bit characters).
89	@return	1 on success, 0 on error.
90*/
91int
92dk3uc2lat_c32_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t const *t);
93
94/**	Write LaTeX encoding for a string to a stream.
95	@param	u	LaTeX encoder.
96	@param	st	Stream to write to.
97	@param	t	Text to write (dkChar characters).
98	@param	e	Encoding (only used for 8-bit characters).
99	@return	1 on success, 0 on error.
100*/
101int
102dk3uc2lat_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dkChar const *t, int e);
103
104#if HAVE_PACKAGES
105
106/**	Prepare LaTeX encoder to retrieve package information.
107	@param	u	LaTeX encoder.
108*/
109void
110dk3uc2lat_package_reset(dk3_uc2lat_t *u);
111
112/**	Retrieve next package information from LaTeX encoder.
113	@param	u	LaTeX encoder.
114	@return	Pointer to next package information or NULL.
115*/
116dk3_uc2lat_pkg_t *
117dk3uc2lat_package_next(dk3_uc2lat_t *u);
118
119#endif
120
121/**	Reset font encoding information.
122*/
123void
124dk3uc2lat_font_encoding_reset(void);
125
126/**	Check for font encoding conflicts.
127	@return	1 on conflicts, 0 otherwise (no problems).
128*/
129int
130dk3uc2lat_font_encoding_conflict(void);
131
132/**	Report font encoding requirement conflicts.
133	@param	u	LaTeX encoder.
134*/
135void
136dk3uc2lat_font_encoding_report_conflict(dk3_uc2lat_t *u);
137
138/**	Report font encoding requirement conflicts.
139	@param	u	LaTeX encoder.
140*/
141void
142dk3uc2lat_font_encoding_report(dk3_uc2lat_t *u);
143
144/**	Write some final comments to output stream about
145	usable encdings and required packages.
146	@param	u	LaTeX encoder.
147	@param	st	Output stream.
148*/
149void
150dk3uc2lat_final_report(dk3_uc2lat_t *u, dk3_stream_t *st);
151
152#ifdef __cplusplus
153}
154#endif
155
156
157
158%%	module
159
160/**	Enable or disable support for dk3_uc2l_pkg_t.
161*/
162#define	HAVE_PACKAGES	1
163
164
165#include <libdk3c/dk3all.h>
166#include <libdk3c/dk3maih8.h>
167#include <libdk3c/dk3unused.h>
168#include <itadmin/dk3uc2l.h>
169
170
171$!trace-include
172
173
174
175/**	LaTeX commands to start and end math mode.
176*/
177static char const * const dk3uc2lat_mm[] = {
178"\\(",
179"\\)",
180"% font encodings:",
181"% package: ",
182"\n",
183};
184
185
186
187#if 0
188/**	Font encoding names.
189*/
190static char const * const dk3uc2lat_font_encodings[] = {
191"ot1",
192"!ot1",
193"t1",
194"!t1",
195"t4",
196"!t4",
197"t5",
198"!t5",
199NULL
200};
201#endif
202
203
204#if 0
205/**	Font encoding names, used in error messages.
206	Why unused ?!
207*/
208static dkChar const * const	dk3uc2l_font_encoding_names[] = {
209dkT("OT1"),
210dkT("T1"),
211dkT("T4"),
212dkT("T5"),
213NULL
214};
215#endif
216
217
218/**	Font encoding names written at end of output file.
219*/
220static const char * const	dk3uc2l_c8_font_encoding_names[] = {
221$!string-table
222 OT1
223 T1
224 T4
225 T5
226$!end
227};
228
229
230
231/**	Allowed suffixes for conversion data files.
232*/
233static dkChar const * const	dk3uc2l_suffixes[] = {
234dkT(".t2l"),
235#if DK3_HAVE_ZLIB_H	&& (DK3_CHAR_SIZE == 1)
236dkT(".t2l.gz"),
237#endif
238#if DK3_HAVE_BZLIB_H	&& (DK3_CHAR_SIZE == 1)
239dkT(".t2l.bz2"),
240#endif
241NULL
242};
243
244
245
246/**	Compression suffixes.
247*/
248static dkChar const * const	dk3uc2l_co_suf[] = {
249$!string-table	macro=dkT
250.gz
251.bz2
252$!end
253};
254
255
256
257/**	Attribute keywords.
258*/
259static const char * const	dk3uc2l_kw[] = {
260$!string-table
261b$oth
262t$ext
263m$ath
264e$ncoding
265p$ackages
266$!end
267};
268
269
270
271/**	Encoding names, used for reporting.
272*/
273static const char * const	dk3uc2l_enco[] = {
274$!string-table
275ot1
276t1
277t4
278t5
279$!end
280};
281
282
283
284/**	Release an array of string pointers.
285	@param	ap	Array base address.
286	@param	ns	Number of strings.
287*/
288static
289void
290dk3uc2lat_release_pointer_array(char const **ap, size_t ns)
291{
292  char const	**ptr;	/* Current string in array. */
293  size_t	  i;	/* Current string index in array. */
294  $? "+ dk3uc2lat_release_pointer_array %lu", (unsigned long)ns
295  ptr = ap; i = ns;
296  while(i--) {
297    dk3_release(*ptr);
298    ptr++;
299  } $? "- dk3uc2lat_release_pointer_array"
300  dk3_delete(ap);
301}
302
303
304
305/**	Destroy range structure, release memory.
306	@param	rp	Structure to destroy.
307*/
308static
309void
310dk3uc2lat_range_delete(dk3_uc2lat_range_t *rp)
311{
312  size_t	numchar;	/* Number of characters in this range. */
313  dkChar const	**ptr;		/* Release all descriptions. */
314  dk3_uc2lat_pkg_t	***pkgppp;
315  size_t	i;		/* Number of descriptions to release. */
316  $? "+ dk3uc2lat_range_delete %lx %lx", dk3enc_uc_to_ul(rp->start), dk3enc_uc_to_ul(rp->end)
317  if(rp) {
318    numchar = (size_t)(rp->end - rp->start + 1);
319    if(numchar > 0) {
320      rp->dir = NULL;
321      if(rp->f) {
322        dk3_release(rp->f);
323      } rp->f = NULL;
324      if(rp->dsc) {
325        ptr = rp->dsc;
326	i = (size_t)(rp->end - rp->start + 1);
327	while(i--) {
328	  dk3_release(*ptr);
329	  ptr++;
330	}
331      } rp->dsc = NULL;
332      if(rp->a) {
333        dk3uc2lat_release_pointer_array(rp->a, numchar);
334      } rp->a = NULL;
335      if(rp->t) {
336        dk3uc2lat_release_pointer_array(rp->t, numchar);
337      } rp->t = NULL;
338      if(rp->m) {
339        dk3uc2lat_release_pointer_array(rp->m, numchar);
340      } rp->m = NULL;
341      if(rp->p) {
342        pkgppp = rp->p;
343	i = (size_t)(rp->end - rp->start + 1);
344	while (i--) {
345	  dk3_release(*pkgppp);
346	  pkgppp++;
347	}
348        dk3_delete(rp->p);
349      } rp->p = NULL;
350      rp->start = (dk3_c32_t)0UL; rp->end = (dk3_c32_t)0UL;
351      rp->ia = 0x00;
352    }
353    dk3_delete(rp);
354  } $? "- dk3uc2lat_range_delete"
355}
356
357
358#if HAVE_PACKAGES
359
360/**	Destroy package structure, release memory.
361	@param	pp	Structure to release.
362*/
363static
364void
365dk3uc2lat_pkg_delete(dk3_uc2lat_pkg_t *pp)
366{
367  $? "+ dk3uc2lat_pkg_delete %!8s", TR_8PTR(pp)
368  if(pp) {	$? ". pkg name = \"%!8s\"", TR_8STR(pp->name)
369    dk3_release(pp->name);
370    pp->used = 0x00;
371    dk3_delete(pp);
372  } $? "- dk3uc2lat_pkg_delete"
373}
374
375#endif
376
377
378/**	Destroy UC to LaTeX directory structure, release memory.
379	@param	dp	Structure to destroy.
380*/
381static
382void
383dk3uc2lat_dir_delete(dk3_uc2lat_dir_t *dp)
384{
385  $? "+ dk3uc2lat_dir_delete %!8s", TR_8PTR(dp)
386  if(dp) {
387    if(dp->s_ran) {
388      if(dp->i_ran) {
389        dk3sto_it_close(dp->i_ran);
390      } dp->i_ran = NULL;
391      dk3sto_close(dp->s_ran);
392    } dp->s_ran = NULL;
393    dk3_release(dp->sn);
394    dp->loaded = 0x00;
395    dk3_delete(dp);
396  } $? "- dk3uc2lat_dir_delete"
397}
398
399
400
401#if HAVE_PACKAGES
402
403/**	Compare two package records.
404	  @param	l	Left record.
405	  @param	r	Right record or name.
406	  @param	cr	Comparison criteria (0=record/record, 1=record/name).
407	  @return	Comparison result.
408*/
409static
410int
411dk3uc2lat_pkg_compare(void const *l, void const *r, int cr)
412{
413  int back = 0;
414  dk3_uc2lat_pkg_t const	*pl;	/* Left pointer. */
415  dk3_uc2lat_pkg_t const	*pr;	/* Right pointer. */
416
417  pl = (dk3_uc2lat_pkg_t const *)l;
418  pr = (dk3_uc2lat_pkg_t const *)r;
419  if(l) {
420    if(r) {
421	switch(cr) {
422	  case 1: {
423	    if(pl->name) {
424	      back = dk3str_c8_cmp(pl->name, (char const *)r);
425	    } else { back = -1; }
426	  } break;
427	  default: {
428	    if(pl->name) {
429	      if(pr->name) {
430		back = dk3str_c8_cmp(pl->name, pr->name);
431	      } else { back = 1; }
432	    } else {
433	      if(pr->name) { back = -1; }
434	    }
435	  } break;
436	}
437    } else { back = 1; }
438  } else {
439    if(r) { back = -1; }
440  }
441  if(back < -1) { back = -1; }
442  if(back >  1) { back =  1; }
443  return back;
444}
445
446#endif
447
448
449
450/**	Compare two range structures by start and end character.
451	  @param	l	Left structure.
452	  @param	r	Right structure/UC character.
453	  @param	cr	Comparison criteria (0=struct/struct, 1=struct/char).
454	  @return	Comparison result.
455*/
456static
457int
458dk3uc2lat_range_compare(void const *l, void const *r, int cr)
459{
460  int back = 0;
461  dk3_uc2lat_range_t const	*pl;	/* Left pointer. */
462  dk3_uc2lat_range_t const	*pr;	/* Right pointer. */
463  dk3_c32_t		*ucptr;	/* Right pointer is a character pointer. */
464
465  pl = (dk3_uc2lat_range_t const *)l;
466  pr = (dk3_uc2lat_range_t const *)r;
467  if(l) {
468    if(r) {
469	switch(cr) {
470	  case 1: {
471	    ucptr = (dk3_c32_t *)r;
472	    if(pl->start > (*ucptr)) {
473	      back = 1;
474	    } else {
475	      if(pl->end < (*ucptr)) {
476		back = -1;
477	      }
478	    }
479	  } break;
480	  default: {
481	    if(pl->start > pr->end) {
482	      back = 1;
483	    } else {
484	      if(pl->end < pr->start) {
485		back = -1;
486	      }
487	    }
488	  } break;
489	}
490    } else { back = 1; }
491  } else {
492    if(r) { back = -1; }
493  }
494  return back;
495}
496
497
498
499/**	Compare two UC to LaTeX directory structures.
500	  @param	l	Left structure.
501	  @param	r	Right structure/name.
502	  @param	cr	Comparison criteria (0=struct/struct, 1=struct/name).
503	  @return	Comparison result.
504*/
505static
506int
507dk3uc2lat_dir_compare(void const *l, void const *r, int cr)
508{
509  int back = 0;
510  dk3_uc2lat_dir_t const	*pl;	/* Left pointer. */
511  dk3_uc2lat_dir_t const	*pr;	/* Right pointer. */
512
513  pl = (dk3_uc2lat_dir_t const *)l;
514  pr = (dk3_uc2lat_dir_t const *)r;
515  if(l) {
516    if(r) {
517	switch(cr) {
518	  case 1: {
519	    if(pl->sn) {
520	      back = dk3str_fncmp(pl->sn, (dkChar const *)r);
521	    } else { back = -1; }
522	  } break;
523	  default: {
524	    if(pl->sn) {
525	      if(pr->sn) {
526		back = dk3str_fncmp(pl->sn, pr->sn);
527	      } else { back = 1; }
528	    } else {
529	      if(pr->sn) { back = -1; }
530	    }
531	  } break;
532	}
533    } else { back = 1; }
534  } else {
535    if(r) { back = -1; }
536  }
537  return back;
538}
539
540
541
542void
543dk3uc2lat_close(dk3_uc2lat_t *u)
544{
545#if HAVE_PACKAGES
546  dk3_uc2lat_pkg_t	*ppkg;
547#endif
548  dk3_uc2lat_dir_t	*pdir;
549  dk3_uc2lat_range_t	*pran;
550  $? "+ dk3uc2lat_close"
551  if (NULL != u) {
552    u->app = NULL;
553    dk3_release(u->dir);
554    dk3_release(u->buf);
555    if (NULL != u->s_ran) {
556      if (NULL != u->i_ran) {
557        dk3sto_it_reset(u->i_ran);
558	do {
559	  pran = (dk3_uc2lat_range_t *)dk3sto_it_next(u->i_ran);
560	  if (NULL != pran) {
561	    dk3uc2lat_range_delete(pran);
562	  }
563	} while (NULL != pran);
564	dk3sto_it_close(u->i_ran);
565      }
566      dk3sto_close(u->s_ran);
567    }
568    u->s_ran = NULL; u->i_ran = NULL;
569    if (NULL != u->s_dir) {
570      if (NULL != u->i_dir) {
571        dk3sto_it_reset(u->i_dir);
572	do {
573	  pdir = (dk3_uc2lat_dir_t *)dk3sto_it_next(u->i_dir);
574	  if (NULL != pdir) {
575	    dk3uc2lat_dir_delete(pdir);
576	  }
577	} while (NULL != pdir);
578	dk3sto_it_close(u->i_dir);
579      }
580      dk3sto_close(u->s_dir);
581    }
582    u->s_dir = NULL; u->i_dir = NULL;
583#if HAVE_PACKAGES
584    if (NULL != u->s_pkg) {
585      if (NULL != u->i_pkg) {
586        dk3sto_it_reset(u->i_pkg);
587	do {
588	  ppkg = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg);
589	  if (NULL != ppkg) {
590	    dk3uc2lat_pkg_delete(ppkg);
591	  }
592	} while (NULL != ppkg);
593	dk3sto_it_close(u->i_pkg);
594      }
595      dk3sto_close(u->s_pkg);
596    }
597    u->s_pkg = NULL; u->i_pkg = NULL;
598#endif
599    u->rca = NULL;
600    u->szbuf = 0;
601    u->f_dsc = 0;
602    u->f_utf8 = 0;
603    u->fe = 0;
604    dk3_delete(u);
605  }
606  $? "- dk3uc2lat_close"
607}
608
609
610
611#if HAVE_PACKAGES
612
613/**	Create package structure, allocate memory.
614	@param	pn	Package name.
615	@param	app	Application structure for diagnostics.
616	@return	Pointer to new structure on success, NULL on error.
617*/
618static
619dk3_uc2lat_pkg_t *
620dk3uc2lat_pkg_new(char const *pn, dk3_app_t *app)
621{
622  dk3_uc2lat_pkg_t *back = NULL;
623  $? "+ dk3uc2lat_pkg_new \"%!8s\"", TR_8STR(pn)
624  back = dk3_new_app(dk3_uc2lat_pkg_t,1,app);
625  if(back) {
626    back->used = 0x00;
627    back->name = dk3str_c8_dup_app(pn,app);
628    if(!(back->name)) {
629      dk3uc2lat_pkg_delete(back);
630      back = NULL;
631    }
632  } $? "- dk3uc2lat_pkg_new %!8s", TR_8PTR(back)
633  return back;
634}
635
636#endif
637
638
639/**	Create range structure, allocate memory.
640	@param	start	Start character of range.
641	@param	end	End character of range.
642	@param	dir	Directory structure (parent of this range).
643	@param	app	Application structure for diagnostics.
644	@return	Pointer to new range structure on success, NULL on error.
645*/
646static
647dk3_uc2lat_range_t *
648dk3uc2lat_range_new(
649  dk3_c32_t start, dk3_c32_t end, dk3_uc2lat_dir_t *dir, dk3_app_t *app
650)
651{
652  dk3_uc2lat_range_t	*back = NULL;
653  char			range_text[32];		/* Buffer for number range. */
654  dkChar		dk_range_text[32];	/* Buffer for number range. */
655  $? "+ dk3uc2lat_range_new %lx %lx", dk3enc_uc_to_ul(start), dk3enc_uc_to_ul(end)
656  if(dk3app_max_log_level(app) >= DK3_LL_DEBUG) {
657    sprintf(range_text, "%lx-%lx", (long)start, (long)end);
658    (void)dk3str_c8_to_str_simple_app(dk_range_text, 32, range_text, app);
659    dk3app_log_i3(app, DK3_LL_DEBUG, 238, 239, dk_range_text);
660  }
661  if(end >= start) {
662    back = dk3_new_app(dk3_uc2lat_range_t,1,app);
663    if(back) {
664      back->dir = dir;
665      back->dsc = NULL;
666      back->a = NULL;
667      back->t = NULL;
668      back->m = NULL;
669#if HAVE_PACKAGES
670      back->p = NULL;
671#endif
672      back->f = NULL;
673      back->start = start;
674      back->end = end;
675      back->ia = 0x00;
676    }
677  } else {
678    if(app) {
679      dk3app_log_i1(app, DK3_LL_ERROR, 220);
680    }
681  } $? "- dk3uc2lat_range_new %!8s", TR_8PTR(back)
682  return back;
683}
684
685
686
687/**	Create UC to LaTeX directory structure, allocate memory.
688	@param	sn	Short directory file name.
689	@param	app	Application structure for diagnostics.
690	@return	Pointer to new directory structure on success, NULL on error.
691*/
692static
693dk3_uc2lat_dir_t *
694dk3uc2lat_dir_new(dkChar const *sn, dk3_app_t *app)
695{
696  dk3_uc2lat_dir_t *back = NULL;
697  $? "+ dk3uc2lat_dir_new \"%!ds\"", TR_STR(sn)
698  back = dk3_new_app(dk3_uc2lat_dir_t,1,app);
699  if(back) {
700    back->s_ran = NULL; back->i_ran = NULL; back->sn = NULL;
701    back->loaded = 0x00;
702    back->s_ran = dk3sto_open_app(app);
703    if(back->s_ran) {
704      dk3sto_set_comp(back->s_ran, dk3uc2lat_range_compare, 0);
705      back->i_ran = dk3sto_it_open(back->s_ran);
706      if(back->i_ran) {
707        back->sn = dk3str_dup_app(sn,app);
708      }
709    }
710    if(!((back->s_ran) && (back->i_ran) && (back->sn))) {
711      dk3uc2lat_dir_delete(back); back = NULL;
712    }
713  } $? "- dk3uc2lat_dir_new PTR:%d", TR_IPTR(back)
714  return back;
715}
716
717
718
719/**	Create new LaTeX encoder.
720	  @param	dn	Directory containing the data files.
721	  @param	f_utf8	Flag: Allowed to write UTF-8 output.
722	  @param	app	Application structure for diagnostics, may be NULL.
723	  @return	Pointer to new encoder on success, NULL on error.
724*/
725static
726dk3_uc2lat_t *
727dk3uc2lat_t_new(
728  const dkChar	*dn,
729  int		 f_utf8,
730  dk3_app_t	*app
731)
732{
733  dk3_uc2lat_t		*back	= NULL;
734  int			 ok	= 0;
735  $? "+ dk3uc2lat_t_new %!ds", dn
736  back = dk3_new_app(dk3_uc2lat_t,1,app);
737  if (NULL != back) {
738    back->app = app;
739    back->dir = NULL;
740    back->buf = NULL;
741    back->s_ran = NULL;
742    back->i_ran = NULL;
743    back->s_dir = NULL;
744    back->i_dir = NULL;
745#if HAVE_PACKAGES
746    back->s_pkg = NULL;
747    back->i_pkg = NULL;
748#endif
749    back->rca = NULL;
750    back->szbuf = 0;
751    back->f_dsc = 0;
752    back->f_utf8 = f_utf8;
753    back->fe =
754    DK3_FONT_ENCODING_OT1 + DK3_FONT_ENCODING_T1
755    + DK3_FONT_ENCODING_T4 + DK3_FONT_ENCODING_T5;
756    back->dir = dk3str_dup_app(dn, app);
757    back->buf = dk3_new_app(char,16,app);
758    if (NULL != back->buf) { back->szbuf = 16; }
759    if ((NULL != back->dir) && (NULL != back->buf)) {
760      back->s_ran = dk3sto_open_app(app);
761      if (NULL != back->s_ran) {
762        dk3sto_set_comp(back->s_ran, dk3uc2lat_range_compare, 0);
763        back->s_dir = dk3sto_open_app(app);
764        if (NULL != back->s_dir) {
765          dk3sto_set_comp(back->s_dir, dk3uc2lat_dir_compare, 0);
766#if HAVE_PACKAGES
767          back->s_pkg = dk3sto_open_app(app);
768          if (NULL != back->s_pkg) {
769            dk3sto_set_comp(back->s_pkg, dk3uc2lat_pkg_compare, 0);
770#endif
771            back->i_ran = dk3sto_it_open(back->s_ran);
772            if (NULL != back->i_ran) {
773              back->i_dir = dk3sto_it_open(back->s_dir);
774              if (NULL != back->i_dir) {
775#if HAVE_PACKAGES
776                back->i_pkg = dk3sto_it_open(back->s_pkg);
777                if (NULL != back->i_pkg) {
778#endif
779                  ok = 1;
780#if HAVE_PACKAGES
781		}
782#endif
783              }
784            }
785#if HAVE_PACKAGES
786	  }
787#endif
788        }
789      }
790    }
791    if (0 == ok) {
792      dk3uc2lat_close(back);
793      back = NULL;
794    }
795  } $? "- dk3uc2lat_t_new PTR:%d", TR_IPTR(back)
796  return back;
797}
798
799
800
801/**	Check the file name whether it contains LaTeX conversion data
802	and can be processed.
803	@param	fn	File name to check.
804	@return	1 if yes, 0 otherwise.
805*/
806static
807int
808dk3uc2lat_is_suitable_file(const dkChar *fn)
809{
810  const dkChar * const	*ptr;		/* Traverse allowed suffixes array */
811  size_t	 	 szfn	= 0;	/* File name size */
812  size_t	 	 szsu	= 0;	/* Allowed suffix size */
813  int		 	 back	= 0;
814  $? "+ dk3uc2lat_is_suitable_file %!ds", fn
815  szfn = dk3str_len(fn);
816  ptr = dk3uc2l_suffixes;
817  while ((NULL != *ptr) && (0 == back)) {
818    szsu = dk3str_len(*ptr);
819    if (szfn > szsu) {
820      if (0 == dk3str_fncmp(&(fn[szfn - szsu]), *ptr)) {
821        back = 1;
822      }
823    }
824    ptr++;
825  } $? "- dk3uc2lat_is_suitable_file %d", back
826  return back;
827}
828
829
830
831/**	Add one character to the range descriptions of a file directory.
832	@param	uptr	Conversion structure to set up.
833	@param	pdir	File directory to set up.
834	@param	chr	Character to add.
835	@param	app	Application structure for diagnostics, may be NULL.
836	@return	1 on success, 0 on error.
837*/
838static
839int
840dk3uc2l_add_char_to_dir(
841  dk3_uc2lat_t		*uptr,
842  dk3_uc2lat_dir_t	*pdir,
843  dk3_c32_t		 chr,
844  dk3_app_t		*app
845)
846{
847  dkChar		 cbuf[64];
848  dk3_uc2lat_range_t	*prange;
849  dk3_uc2lat_range_t	*pr2;
850  size_t		 szcbuf = DK3_SIZEOF(cbuf,dkChar);
851  dk3_c32_t		 tchr;
852  int			 back = 0;
853  $? "+ dk3uc2l_add_char_to_dir %lx", dk3enc_uc_to_ul(chr)
854  prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(uptr->i_ran, &chr, 1);
855  if (NULL == prange) {
856    prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(pdir->i_ran, &chr, 1);
857    if (NULL == prange) {
858      if ((dk3_c32_t)0UL < chr) {			$? ". try to append"
859        tchr = chr - 1;
860	prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(pdir->i_ran,&tchr,1);
861	if (NULL != prange) {	$? ". found %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
862	  prange->end = chr;
863	  back = 1;	$? ". changed to %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
864	  if (dkC32(0xFFFFFFFF) > chr) {
865	    tchr = chr + (dk3_c32_t)1UL;
866	    pr2 = (dk3_uc2lat_range_t *)dk3sto_it_find_like(
867	    	pdir->i_ran, &tchr, 1
868	    );
869	    if (NULL != pr2) {	$? ". found %lx-%lx", dk3enc_uc_to_ul(pr2->start), dk3enc_uc_to_ul(pr2->end)
870	      tchr = pr2->end;
871	      dk3sto_remove(pdir->s_ran, pr2);
872	      dk3uc2lat_range_delete(pr2);
873	      prange->end = tchr;
874	      $? ". changed %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
875	    }
876	  }
877	}
878      }
879      if (0 == back) {					$? ". try to prepend"
880        if (dkC32(0xFFFFFFFF) > chr) {	$? ". can"
881	  tchr = chr + (dk3_c32_t)1UL;
882	  prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(
883	  	pdir->i_ran, &tchr, 1
884	  );
885	  if (NULL != prange) {	$? ". found %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
886	    prange->start = chr;
887	    back = 1;	$? ". changed to %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
888	  }
889	}
890      }
891      if (0 == back) {					$? ". try to add"
892        prange = dk3uc2lat_range_new(chr, chr, pdir, app);
893	if (NULL != prange) {
894	  if (dk3sto_add(pdir->s_ran, prange)) {
895	    back = 1;	$? ". added %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
896	  } else {
897	    dk3uc2lat_range_delete(prange);
898	  }
899	}
900      }
901    } else {						$? "! already found"
902      /* ERROR: Already found! */
903      if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)chr, 8)) {
904        dk3app_log_i3(uptr->app, DK3_LL_ERROR, 395, 396, cbuf);
905      } else {
906        dk3app_log_i1(uptr->app, DK3_LL_ERROR, 397);
907      }
908    }
909  } else {						$? "! already found"
910    /* ERROR: Already found ! */
911    if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)chr, 8)) {
912      dk3app_log_i3(uptr->app, DK3_LL_ERROR, 395, 396, cbuf);
913    } else {
914      dk3app_log_i1(uptr->app, DK3_LL_ERROR, 397);
915    }
916  } $? "- dk3uc2l_add_char_to_dir %d", back
917  return back;
918}
919
920
921
922/**	Apply data from stream to directory information for one file.
923	@param	uptr	Conversion structure to set up.
924	@param	pdir	File directory entry to configure.
925	@param	istrm	Input stream for file (normal or compressed).
926	@param	app	Application structure for diagnostics, may be NULL.
927	@return	1 on success, 0 on error.
928*/
929static
930int
931dk3uc2l_apply_1(
932  dk3_uc2lat_t		*uptr,
933  dk3_uc2lat_dir_t	*pdir,
934  dk3_stream_t		*istrm,
935  dk3_app_t		*app
936)
937{
938  char			 buf[512];
939  char			*p1;
940  char			*p2;
941  dk3_uc2lat_range_t	*prange;
942  unsigned long		 lineno	= 0UL;
943  unsigned long		 chr;
944  int			 back	= 1;
945  $? "+ dk3uc2l_apply_1"
946  while ((1 == back) && (1 == dk3stream_c8_fgets(istrm, buf, sizeof(buf)))) {
947    dk3app_set_source_line(app, ++lineno);
948    buf[sizeof(buf) - 1] = '\0';
949    $? ". processing line %lu: %s", lineno, buf
950    p1 = dk3str_c8_start(buf, NULL);
951    if (NULL != p1) {
952      if ('#' != *p1) {
953        p2 = dk3str_c8_next(p1, NULL);
954	if (NULL != p2) {
955	  if (0 != dk3ma_ul_from_c8_hex_string(&chr, p1, NULL)) {
956	    if (0 == dk3uc2l_add_char_to_dir(uptr, pdir, (dk3_c32_t)chr, app)) {
957	      back = 0;	$? "! failed to add %lx", chr
958	    }
959	  } else {
960	    /* ERROR: Syntax error, not a hexadecimal number */
961	    dk3app_log_i1(uptr->app, DK3_LL_ERROR, 398);
962	  }
963	} else {
964	  /* ERROR: Syntax error, missing configuration */
965	  dk3app_log_i1(uptr->app, DK3_LL_ERROR, 400);
966	}
967      }
968    }
969  }
970  if (1 == back) {	$? ". copying ranges to global container"
971    dk3sto_it_reset(pdir->i_ran);
972    do {
973      prange = (dk3_uc2lat_range_t *)dk3sto_it_next(pdir->i_ran);
974      if (NULL != prange) {	$? ". range %lx-%lx", dk3enc_uc_to_ul(prange->start), dk3enc_uc_to_ul(prange->end)
975        if (0 == dk3sto_add(uptr->s_ran, prange)) {
976	  dk3uc2lat_range_delete(prange);
977	  back = 0;	$? "! failed to copy range"
978	}
979      }
980    } while (NULL != prange);
981  } else {		$? "! deleting ranges due to error"
982    dk3sto_it_reset(pdir->i_ran);
983    do {
984      prange = (dk3_uc2lat_range_t *)dk3sto_it_next(pdir->i_ran);
985      if (NULL != prange) {
986        dk3uc2lat_range_delete(prange);
987      }
988    } while (NULL != prange);
989  } $? "- dk3uc2l_apply_1 %d", back
990  return back;
991}
992
993
994
995/**	Apply directory information for a file.
996	@param	uptr	Conversion structure to set up.
997	@param	fn	File name containing conversion data.
998	@param	app	Application structure for diagnostics, may be NULL.
999	@return	1 on success, 0 on error.
1000*/
1001static
1002int
1003dk3uc2lat_pass_1(
1004  dk3_uc2lat_t *uptr, const dkChar *fn, const dkChar *sn, dk3_app_t *app
1005)
1006{
1007  dk3_uc2lat_dir_t	*pdir	= NULL;
1008  dk3_stream_t		*istrm	= NULL;
1009  FILE			*fipo	= NULL;
1010  const dkChar		*oldsrc	= NULL;
1011  const dkChar		*fsuf	= NULL;
1012#if DK3_HAVE_ZLIB_H	&& (DK3_CHAR_SIZE == 1)
1013  gzFile		 gzf	= NULL;
1014#endif
1015#if DK3_HAVE_BZLIB_H	&& (DK3_CHAR_SIZE == 1)
1016  BZFILE		*bzf	= NULL;
1017#endif
1018  unsigned long		 oldln	= 0UL;
1019#if DK3_HAVE_FNCASEINS
1020  int			 fncs	= 0;
1021#else
1022  int			 fncs	= 1;
1023#endif
1024  int			 back	= 0;
1025  $? ". dk3uc2lat_pass_1 %!ds", fn
1026  pdir = dk3uc2lat_dir_new(sn, app);
1027  if (NULL != pdir) {
1028    oldsrc = dk3app_get_source_file(app);
1029    oldln  = dk3app_get_source_line(app);
1030    dk3app_set_source_file(app, fn);
1031    dk3app_set_source_line(app, 0UL);
1032    if (0 != dk3sto_add(uptr->s_dir, pdir)) {
1033      fsuf = dk3str_get_suffix(fn);
1034      switch (dk3str_array_index(dk3uc2l_co_suf, fsuf, fncs)) {
1035        case 0: {	/* gz */
1036#if DK3_HAVE_ZLIB_H	&& (DK3_CHAR_SIZE == 1)
1037	  gzf = gzopen(fn, "r");
1038	  if (NULL != gzf) {
1039	    istrm = dk3stream_open_gz_app(gzf, DK3_STREAM_FLAG_READ, app);
1040	    if (NULL != istrm) {
1041	      back = dk3uc2l_apply_1(uptr, pdir, istrm, app);
1042	      (void)dk3stream_close(istrm);
1043	    }
1044	    gzclose(gzf);
1045	  } else {
1046	    /* ERROR: Failed to open file */
1047	    dk3app_log_i3(uptr->app, DK3_LL_ERROR, 143, 144, fn);
1048	  }
1049#else
1050	  /* ERROR: No zlib support */
1051	  dk3app_log_i1(uptr->app, DK3_LL_ERROR, 401);
1052#endif
1053	} break;
1054	case 1: {	/* bz2 */
1055#if DK3_HAVE_BZLIB_H	&& (DK3_CHAR_SIZE == 1)
1056	  bzf = BZ2_bzopen(fn, "r");
1057	  if (NULL != bzf) {
1058	    istrm = dk3stream_open_bz2_app(bzf, DK3_STREAM_FLAG_READ, app);
1059	    if (NULL != istrm) {
1060	      back = dk3uc2l_apply_1(uptr, pdir, istrm, app);
1061	      (void)dk3stream_close(istrm);
1062	    }
1063	    BZ2_bzclose(bzf);
1064	  } else {
1065	    /* ERROR: Failed to open file */
1066	    dk3app_log_i3(uptr->app, DK3_LL_ERROR, 143, 144, fn);
1067	  }
1068#else
1069	  /* ERROR: No bzip2 support */
1070	  dk3app_log_i1(uptr->app, DK3_LL_ERROR, 402);
1071#endif
1072	} break;
1073	default : {	/* normal file */
1074	  fipo = dk3sf_fopen_app(fn, dkT("r"), app);
1075	  if (NULL != fipo) {
1076	    istrm = dk3stream_open_file_app(fipo, DK3_STREAM_FLAG_READ, app);
1077	    if (NULL != istrm) {
1078	      back = dk3uc2l_apply_1(uptr, pdir, istrm, app);
1079	      (void)dk3stream_close(istrm);
1080	    }
1081	    fclose(fipo);
1082	  }
1083	} break;
1084      }
1085    } else {
1086      dk3uc2lat_dir_delete(pdir);
1087    }
1088    dk3app_set_source_file(app, oldsrc);
1089    dk3app_set_source_line(app, oldln);
1090  } $? "- dk3uc2lat_pass_1 %d", back
1091  return back;
1092}
1093
1094
1095
1096/**	Read directory information (check existing data files, retrieve ranges.
1097	@param	d	Directory containing the data files.
1098	@param	uptr	Conversion structure to initialize.
1099	@param	app	Application structure for diagnostics, may be NULL.
1100	@return	1 on success, 0 on error.
1101*/
1102static
1103int
1104dk3uc2lat_read_dir_info(dk3_uc2lat_t *uptr, dk3_app_t *app)
1105{
1106  dk3_dir_t	*dir	= NULL;
1107  const	dkChar	*fn	= NULL;
1108  const dkChar	*sn	= NULL;
1109  int		 back	= 0;
1110  int		 found	= 0;
1111  $? "+ dk3uc2lat_read_dir_info"
1112  dir = dk3dir_open_app(uptr->dir, uptr->app);
1113  if (NULL != dir) {
1114    back = 1;
1115    while (0 != dk3dir_get_next_file(dir)) {
1116      sn = dk3dir_get_shortname(dir);
1117      fn = dk3dir_get_fullname(dir);
1118      if ((NULL != sn) && (NULL != fn)) {
1119        if (0 != dk3uc2lat_is_suitable_file(fn)) {
1120	  found = 1;
1121	  if (0 == dk3uc2lat_pass_1(uptr, fn, sn, app)) {
1122	    back = 0;
1123	  }
1124	}
1125      }
1126    }
1127    dk3dir_close(dir);
1128    if (0 == found) {
1129      back = 0;
1130      /* ERROR: No suitable files found */
1131      dk3app_log_i1(uptr->app, DK3_LL_ERROR, 403);
1132    }
1133  }
1134  $? "- dk3uc2lat_read_dir_info %d", back
1135  return back;
1136}
1137
1138
1139
1140/**	Allocate memory for all ranges details for a file directory.
1141	@param	uptr	Conversion structure to set up.
1142	@param	pdir	Directory information to set up.
1143	@return	1 on success, 0 on error.
1144*/
1145static
1146int
1147dk3uc2l_allocate_memory(
1148  dk3_uc2lat_t		*uptr,
1149  dk3_uc2lat_dir_t	*pdir
1150)
1151{
1152  dk3_uc2lat_range_t	*prange;
1153  size_t		 sz;
1154  size_t		 i;
1155  int			 back	= 1;
1156  int			 allenc	= 0;
1157
1158  dk3sto_it_reset(pdir->i_ran);
1159  allenc = DK3_FONT_ENCODING_OT1
1160  	   + DK3_FONT_ENCODING_T1
1161	   + DK3_FONT_ENCODING_T4
1162	   + DK3_FONT_ENCODING_T5;
1163  do {
1164    prange = (dk3_uc2lat_range_t *)dk3sto_it_next(pdir->i_ran);
1165    if (NULL != prange) {
1166      sz = (size_t)(prange->end - prange->start) + 1;
1167      if (NULL == prange->a) {
1168        prange->a = dk3_new_app(DK3_PCCHAR,sz,uptr->app);
1169	if (NULL != prange->a) {
1170	  for (i = 0; i < sz; i++) { (prange->a)[i] = NULL; }
1171	} else {
1172	  back = 0;
1173	}
1174      }
1175      if (NULL == prange->t) {
1176        prange->t = dk3_new_app(DK3_PCCHAR,sz,uptr->app);
1177	if (NULL != prange->t) {
1178	  for (i = 0; i < sz; i++) { (prange->t)[i] = NULL; }
1179	} else {
1180	  back = 0;
1181	}
1182      }
1183      if (NULL == prange->m) {
1184        prange->m = dk3_new_app(DK3_PCCHAR,sz,uptr->app);
1185	if (NULL != prange->m) {
1186	  for (i = 0; i < sz; i++) { (prange->m)[i] = NULL; }
1187	} else {
1188	  back = 0;
1189	}
1190      }
1191#if HAVE_PACKAGES
1192      if (NULL == prange->p) {
1193        prange->p = dk3_new_app(dk3_uc2lat_pkg_pptr,sz,uptr->app);
1194	if (NULL != prange->p) {
1195	  for (i = 0; i < sz; i++) { (prange->p)[i] = NULL; }
1196	} else {
1197	  back = 0;
1198	}
1199      }
1200#endif
1201      if (NULL == prange->f) {
1202        prange->f = dk3_new_app(dk3_font_encoding_t,sz,uptr->app);
1203	if (NULL != prange->f) {
1204	  for(i = 0; i < sz; i++) {
1205	    (prange->f)[i] = (dk3_font_encoding_t)allenc;
1206	  }
1207	} else {
1208	  back = 0;
1209	}
1210      }
1211    }
1212  } while (NULL != prange);
1213  return back;
1214}
1215
1216
1217
1218static
1219void
1220dk3uc2l_apply_2(
1221  dk3_uc2lat_t		*uptr,
1222  dk3_uc2lat_dir_t	*pdir,
1223  dk3_stream_t		*istrm
1224)
1225{
1226  char			 buf[512];		/* Input line buffer */
1227#if HAVE_PACKAGES
1228  char			*parts[16];		/* Package names */
1229#endif
1230  char			*p1;			/* Hex value or next item */
1231  char			*p2;			/* Current item key */
1232  char			*p3;			/* Current item value */
1233  char			*p4;			/* Dynamic value copy */
1234  dk3_uc2lat_range_t	*prange;		/* Current range */
1235#if HAVE_PACKAGES
1236  dk3_uc2lat_pkg_t	*ppkg;			/* Current package */
1237#endif
1238  unsigned long		 lineno = 0UL;		/* Current line number */
1239  unsigned long		 chr;			/* Current character */
1240  size_t		 ind;			/* Index of chr in range */
1241#if HAVE_PACKAGES
1242  size_t		 nparts;		/* Number of packages */
1243  size_t		 i;			/* Traverse */
1244  size_t		 j;			/* Add new packages */
1245#endif
1246  int			 cc	= 1;		/* Flag: Can continue */
1247  int			 action;		/* Action to take */
1248  int			 isneg;			/* Flag: Deny encodings */
1249  int			 encod;			/* Encodings selection */
1250  $? "+ dk3uc2l_apply_2"
1251  while ((1 == cc) && (1 == dk3stream_c8_fgets(istrm, buf, sizeof(buf)))) {
1252    dk3app_set_source_line(uptr->app, ++lineno);
1253    buf[sizeof(buf) - 1] = '\0';
1254    $? ". processing line %lu: %s", lineno, buf
1255    p1 = dk3str_c8_start(buf, NULL);
1256    if (NULL != p1) {				$? ". p1=\"%!8s\"", p1
1257      if ('#' != *p1) {				$? ". normal line"
1258        p2 = dk3str_c8_next(p1, NULL);
1259	if (NULL != p2) {			$? ". attributes=\"%!8s\"", p2
1260	  if (0 != dk3ma_ul_from_c8_hex_string(&chr, p1, NULL)) {
1261	    prange =
1262	    (dk3_uc2lat_range_t *)dk3sto_it_find_like(pdir->i_ran, &chr, 1);
1263	    if (NULL != prange) {		$? ". range found"
1264	      ind = (size_t)(chr - (unsigned long)(prange->start));
1265	      while (NULL != p2) {
1266	        p1 = dk3str_c8_next(p2, NULL);
1267		p3 = dk3str_c8_chr(p2, '=');
1268		if (NULL != p3) {
1269		  *(p3++) = '\0';
1270#if 0
1271		  /* 2015-08-10 Bugfix: Must be start */
1272		  p3 = dk3str_c8_next(p3, NULL);
1273#endif
1274		  p3 = dk3str_c8_start(p3, NULL);
1275		  if (NULL != p3) {	$? ". \"%!8s\"=\"%!8s\"", p2, p3
1276		    action = dk3str_c8_array_abbr(dk3uc2l_kw, p2, '$', 0);
1277		    $? ". action = %d", action
1278		    switch (action) {
1279		      case 0: {	/* both */		$? ". both"
1280		        if (NULL != prange->a) {
1281			  p4 = dk3str_c8_dup_app(p3, uptr->app);
1282			  if (NULL != p4) {
1283			    dk3_release((prange->a)[ind]);
1284			    (prange->a)[ind] = p4;
1285			  }
1286			}
1287		      } break;
1288		      case 1: {	/* text */		$? ". text"
1289		        if (NULL != prange->t) {
1290			  p4 = dk3str_c8_dup_app(p3, uptr->app);
1291			  if (NULL != p4) {
1292			    dk3_release((prange->t)[ind]);
1293			    (prange->t)[ind] = p4;
1294			  }
1295			}
1296		      } break;
1297		      case 2: {	/* math */		$? ". math"
1298		        if (NULL != prange->m) {
1299			  p4 = dk3str_c8_dup_app(p3, uptr->app);
1300			  if (NULL != p4) {
1301			    dk3_release((prange->m)[ind]);
1302			    (prange->m)[ind] = p4;
1303			  }
1304			}
1305		      } break;
1306		      case 3: {	/* encoding */		$? ". encoding"
1307		        if (NULL != prange->f) {
1308			  isneg = 0; encod = 0;
1309			  if ('!' == *p3) {
1310			    isneg = 1; p3++;
1311			  }
1312			  while (NULL != p3) {
1313			    p4 = dk3str_c8_chr(p3, ',');
1314			    if (NULL != p4) {
1315			      *(p4++) = '\0';
1316			      p4 = dk3str_c8_start(p4, NULL);
1317			    }
1318			    switch (dk3str_c8_array_index(dk3uc2l_enco, p3, 0))
1319			    {
1320			      case 0: {	/* OT1 */
1321			        encod |= DK3_FONT_ENCODING_OT1;
1322			      } break;
1323			      case 1: {	/* T1 */
1324			        encod |= DK3_FONT_ENCODING_T1;
1325			      } break;
1326			      case 2: {	/* T4 */
1327			        encod |= DK3_FONT_ENCODING_T4;
1328			      } break;
1329			      case 3: {	/* T5 */
1330			        encod |= DK3_FONT_ENCODING_T5;
1331			      } break;
1332			      default : {
1333			        /* Syntax error, unknown encoding */
1334				dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 404);
1335			      } break;
1336			    }
1337			    p3 = p4;
1338			  }
1339			  if (0 != isneg) { encod = (~(encod)); }
1340			  (prange->f)[ind] = (dk3_font_encoding_t)encod;
1341			}
1342		      } break;
1343		      case 4: {	/* packages */		$? ". packages"
1344#if HAVE_PACKAGES
1345		        if (NULL != prange->p) {
1346			  nparts = dk3str_c8_explode(parts, 15, p3, ",");
1347			  if (0 < nparts) {
1348			    dk3_release((prange->p)[ind]);
1349			    (prange->p)[ind] =
1350			    dk3_new_app(dk3_uc2lat_pkg_ptr,(nparts+1),uptr->app);
1351			    if (NULL != (prange->p)[ind]) {
1352			      for (i = 0; i < (nparts+1); i++) {
1353			        ((prange->p)[ind])[i] = NULL;
1354			      }
1355			      j = 0;
1356			      for (i = 0; i < nparts; i++) {
1357			        ppkg = (dk3_uc2lat_pkg_t *)dk3sto_it_find_like(
1358				  uptr->i_pkg, parts[i], 1
1359				);
1360				if (NULL != ppkg) {
1361				  ((prange->p)[ind])[j++] = ppkg;
1362				} else {
1363				  ppkg = dk3uc2lat_pkg_new(parts[i], uptr->app);
1364				  if (NULL != ppkg) {
1365				    if (dk3sto_add(uptr->s_pkg, ppkg)) {
1366				      ((prange->p)[ind])[j++] = ppkg;
1367				    } else {
1368				      dk3uc2lat_pkg_delete(ppkg);
1369				    }
1370				  }
1371				}
1372			      }
1373			    }
1374			  } else {
1375			    /* ERROR: Syntax, no packages */
1376			    dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 405);
1377			  }
1378			}
1379#endif
1380		      } break;
1381		      default: {		$? "! unknown key"
1382		      } break;
1383		    }
1384		  } else {			$? "! missing attribute value"
1385		    /* ERROR: Value missing */
1386		    dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 406);
1387		  }
1388		} else {			$? "! missing attribute value"
1389		  /* ERROR: Syntax, not a key value pair */
1390		  dk3app_log_i1(uptr->app, DK3_LL_DEBUG, 406);
1391		}
1392		p2 = p1;
1393	      }
1394	    } else {				$? "! bug: range not found"
1395	      /* BUG or file changed */
1396	    }
1397	  } else {
1398	    /* ERROR: Syntax error, not a hexadecimal number */
1399	    dk3app_log_i1(uptr->app, DK3_LL_ERROR, 398);
1400	  }
1401	} else {				$? "! missing attributes"
1402	  /* ERROR: Syntax error, missing configuration */
1403	  dk3app_log_i1(uptr->app, DK3_LL_ERROR, 401);
1404	}
1405      } else {					$? ". ignore comment line"
1406      }
1407    } else {					$? ". ignore empty line"
1408    }
1409  } $? "- dk3uc2l_apply_2"
1410}
1411
1412
1413
1414static
1415void
1416dk3uc2lat_load_file(dk3_uc2lat_t *u, dk3_uc2lat_dir_t *pdir)
1417{
1418  dkChar		 fnb[DK3_MAX_PATH];
1419  dk3_stream_t		*istrm	= NULL;
1420  FILE			*fipo	= NULL;
1421  const dkChar		*oldsrc	= NULL;
1422  const dkChar		*fsuf	= NULL;
1423#if DK3_HAVE_ZLIB_H	&& (DK3_CHAR_SIZE == 1)
1424  gzFile		 gzf	= NULL;
1425#endif
1426#if DK3_HAVE_BZLIB_H	&& (DK3_CHAR_SIZE == 1)
1427  BZFILE		*bzf	= NULL;
1428#endif
1429  unsigned long		 oldln	= 0UL;
1430#if DK3_HAVE_FNCASEINS
1431  int			 fncs	= 0;
1432#else
1433  int			 fncs	= 1;
1434#endif
1435  size_t		 sz;
1436  $? "+ dk3uc2lat_load_file"
1437  sz =  dk3str_len(u->dir);
1438  sz += dk3str_len(pdir->sn);
1439  sz += 1;
1440  if (sizeof(fnb) > sz) {			$? ". file name length ok"
1441    dk3str_cpy(fnb, u->dir);
1442    dk3str_cat(fnb, dk3app_not_localized(20));
1443    dk3str_cat(fnb, pdir->sn);
1444    dk3str_correct_filename(fnb);
1445    oldsrc = dk3app_get_source_file(u->app);
1446    oldln  = dk3app_get_source_line(u->app);
1447    dk3app_set_source_file(u->app, fnb);
1448    dk3app_set_source_line(u->app, 0UL);
1449    if (0 != dk3uc2l_allocate_memory(u, pdir)) {	$? ". memory allocated"
1450      fsuf = dk3str_get_suffix(fnb);
1451      switch (dk3str_array_index(dk3uc2l_co_suf, fsuf, fncs)) {
1452        case 0: {				$? ". zlib compressed"
1453#if DK3_HAVE_ZLIB_H	&& (DK3_CHAR_SIZE == 1)
1454	  gzf = gzopen(fnb, "r");
1455	  if (NULL != gzf) {
1456	    istrm = dk3stream_open_gz_app(gzf, DK3_STREAM_FLAG_READ, u->app);
1457	    if (NULL != istrm) {
1458	      dk3uc2l_apply_2(u, pdir, istrm);
1459	      (void)dk3stream_close(istrm);
1460	    }
1461	    gzclose(gzf);
1462	  } else {
1463	    /* ERROR: Failed to open file */
1464	    dk3app_log_i3(u->app, DK3_LL_ERROR, 143, 144, fnb);
1465	  }
1466#else
1467	/* ERROR: No zlib support */
1468	dk3app_log_i1(u->app, DK3_LL_ERROR, 401);
1469#endif
1470        } break;
1471        case 1: {				$? ". bzip2 compressed"
1472#if DK3_HAVE_BZLIB_H	&& (DK3_CHAR_SIZE == 1)
1473	  bzf = BZ2_bzopen(fnb, "r");
1474	  if (NULL != bzf) {
1475	    istrm = dk3stream_open_bz2_app(bzf, DK3_STREAM_FLAG_READ, u->app);
1476	    if (NULL != istrm) {
1477	      dk3uc2l_apply_2(u, pdir, istrm);
1478	      (void)dk3stream_close(istrm);
1479	    }
1480	    BZ2_bzclose(bzf);
1481	  } else {
1482	    /* ERROR: Failed to open file */
1483	    dk3app_log_i3(u->app, DK3_LL_ERROR, 143, 144, fnb);
1484	  }
1485#else
1486	/* ERROR: No bzip2 support */
1487	dk3app_log_i1(u->app, DK3_LL_ERROR, 402);
1488#endif
1489        } break;
1490        default: {				$? ". normal file"
1491	  fipo = dk3sf_fopen_app(fnb, dkT("r"), u->app);
1492	  if (NULL != fipo) {
1493	    istrm = dk3stream_open_file_app(fipo, DK3_STREAM_FLAG_READ, u->app);
1494	    if (NULL != istrm) {
1495	      dk3uc2l_apply_2(u, pdir, istrm);
1496	      (void)dk3stream_close(istrm);
1497	    }
1498	    fclose(fipo);
1499	  }
1500        } break;
1501      }
1502    } else {				$? "! memory allocation error"
1503    }
1504    dk3app_set_source_file(u->app, oldsrc);
1505    dk3app_set_source_line(u->app, oldln);
1506  } else {				$? "! file name too long"
1507    /* ERROR: Name too long */
1508    dk3app_log_i3(u->app, DK3_LL_ERROR, 65, 66, pdir->sn);
1509  }
1510  pdir->loaded = 0x01;
1511  $? "- dk3uc2lat_load_file"
1512}
1513
1514
1515
1516/**	Open conversion structure for a given directory.
1517	@param	d	Directory containing conversion files.
1518	@param	f_desc	Flag: Load glyph descriptions (ignored).
1519	@param	f_utf8	Flag: UTF-8 output allowed.
1520	@param	app	Application structure for diagnostics, may be NULL.
1521	@return	Pointer to new structure on success, NULL on error.
1522*/
1523static
1524dk3_uc2lat_t *
1525dk3uc2lat_i_open_app(
1526  const dkChar	*d,
1527  int		 f_utf8,
1528  dk3_app_t	*app
1529)
1530{
1531  dk3_uc2lat_t		*back	= NULL;
1532  $? "+ dk3uc2lat_i_open_app %!ds", d
1533  if (0 != dk3sf_is_dir_app(d, NULL)) {
1534    back = dk3uc2lat_t_new(d, f_utf8, app);
1535    if (NULL != back) {
1536      if (0 == dk3uc2lat_read_dir_info(back, app)) {
1537        dk3uc2lat_close(back);
1538	back = NULL;
1539      }
1540    }
1541  } else {
1542    /* ERROR: Not a directory ... */
1543    dk3app_log_i3(app, DK3_LL_ERROR, 202, 203, d);
1544  }
1545  $? "- dk3uc2lat_i_open_app PTR:%d", TR_IPTR(back)
1546  return back;
1547}
1548
1549
1550
1551dk3_uc2lat_t *
1552dk3uc2lat_open_app(dkChar const *d, int f_utf8, dk3_app_t *app)
1553{
1554  dkChar		 fnb[DK3_MAX_PATH];
1555  dk3_uc2lat_t		*back	= NULL;
1556  const dkChar		*shd	= NULL;
1557  const dkChar		*dirn	= NULL;
1558  size_t		 szfnb	= DK3_SIZEOF(fnb,dkChar);
1559  size_t		 szshd	= 0;
1560  $? "+ dk3uc2lat_open_app %!ds", TR_DKSTR(d)
1561  if (NULL != d) {
1562    back = dk3uc2lat_i_open_app(d, f_utf8, app);
1563  } else {
1564    if (NULL != app) {
1565      if (dk3app_get_dir_from_pref(app,dk3app_not_localized(48),fnb,szfnb,1))
1566      {
1567        dk3str_correct_filename(fnb);
1568        back = dk3uc2lat_i_open_app(fnb, f_utf8, app);
1569      } else
1570      {
1571        shd = dk3app_get_sharedir(app);
1572	if (NULL != shd) {
1573	  szshd = dk3str_len(shd);
1574	  if (szfnb > szshd) {
1575	    dk3str_cpy_not_overlapped(fnb, shd);
1576	    dirn = dk3app_not_localized(49);
1577	    if (szfnb > (szshd + dk3str_len(dirn))) {
1578	      dk3str_cat(fnb, dirn);
1579	      dk3str_correct_filename(fnb);
1580	      back = dk3uc2lat_i_open_app(fnb, f_utf8, app);
1581	    } else {
1582	      /* ERROR: Directory name too long! */
1583	      dk3app_log_i3(app, DK3_LL_ERROR, 64, 66, dirn);
1584	    }
1585	  } else {
1586	    /* ERROR: Share directory name too long! */
1587	    dk3app_log_i3(app, DK3_LL_ERROR, 64, 66, shd);
1588	  }
1589	} else {
1590	  /* ERROR: Missing share directory */
1591	  dk3app_log_i1(app, DK3_LL_ERROR, 407);
1592	}
1593      }
1594    }
1595  } $? "- dk3uc2lat_open_app %d", TR_IPTR(back)
1596  return back;
1597}
1598
1599
1600
1601char const *
1602dk3uc2lat_get(dk3_uc2lat_t *u, dk3_c32_t c32, int ismath)
1603{
1604  dkChar		 cbuf[64];
1605  dk3_uc2lat_range_t	*prange	= NULL;
1606  dk3_uc2lat_pkg_t	**pkgpp;
1607  const char		*back	= NULL;
1608  size_t		 szcbuf = DK3_SIZEOF(cbuf,dkChar);
1609  $? "+ dk3uc2lat_get"
1610  if (NULL != u) {
1611    if (NULL != u->rca) {			$? ". range cache available"
1612      if ((u->rca)->start <= c32) {		$? ". start ok"
1613        if ((u->rca)->end >= c32) {		$? ". end ok"
1614	  prange = u->rca;			$? ". use range cache"
1615	}
1616      }
1617    }
1618    if (NULL == prange) {			$? ". find character"
1619      prange = (dk3_uc2lat_range_t *)dk3sto_it_find_like(u->i_ran, &c32, 1);
1620      if (NULL != prange) {			$? ". range found"
1621        u->rca = prange;
1622	if (NULL != prange->p) {		$? ". range->package"
1623	  pkgpp = (prange->p)[(size_t)(c32 - prange->start)];
1624	  if (NULL != pkgpp) {
1625	    while (NULL != *pkgpp) {
1626	      (*(pkgpp++))->used = 0x01;
1627	    }					$? ". packages marked as used"
1628	  }
1629	}
1630      } else {					$? "! no range found"
1631      }
1632    }
1633    if (NULL != prange) {			$? ". range found"
1634      if (NULL != prange->dir) {		$? ". range has dir entry"
1635        if (0x00 == (prange->dir)->loaded) {	$? ". must load"
1636	  dk3uc2lat_load_file(u, prange->dir);
1637	}
1638      }
1639      if (0 != ismath) {			$? ". math mode"
1640        if (NULL != prange->m) {		$? ". math"
1641	  back = (prange->m)[(size_t)(c32 - prange->start)];
1642	}
1643	if (NULL == back) {
1644	  if (NULL != prange->a) {		$? ". all"
1645	    back = (prange->a)[(size_t)(c32 - prange->start)];
1646	  }
1647	}
1648      } else {					$? ". normal mode"
1649        if (NULL != prange->t) {		$? ". text"
1650	  back = (prange->t)[(size_t)(c32 - prange->start)];
1651	}
1652	if (NULL == back) {			$? ". all"
1653	  if (NULL != prange->a) {
1654	    back = (prange->a)[(size_t)(c32 - prange->start)];
1655	  }
1656	}
1657      }
1658      if (NULL != prange->f) {
1659        u->fe &= ((prange->f)[(size_t)(c32 - prange->start)]);
1660      }
1661    } else {
1662      /* ERROR: Not found */
1663      if (0 != dk3ma_um_to_hex_string(cbuf, szcbuf, (dk3_um_t)c32, 8)) {
1664        dk3app_log_i3(u->app, DK3_LL_ERROR, 409, 410, cbuf);
1665      } else {
1666        dk3app_log_i1(u->app, DK3_LL_ERROR, 408);
1667      }
1668    }
1669  } $? "- dk3uc2lat_get PTR:%d", TR_IPTR(back)
1670  return back;
1671}
1672
1673
1674
1675#if HAVE_PACKAGES
1676
1677void
1678dk3uc2lat_package_reset(dk3_uc2lat_t *u)
1679{
1680  if (NULL != u) {
1681    dk3sto_it_reset(u->i_pkg);
1682  }
1683}
1684
1685
1686
1687dk3_uc2lat_pkg_t *
1688dk3uc2lat_package_next(dk3_uc2lat_t *u)
1689{
1690  dk3_uc2lat_pkg_t	*back	= NULL;
1691  if (NULL != u) {
1692    back = (dk3_uc2lat_pkg_t *)dk3sto_it_next(u->i_pkg);
1693  }
1694  return back;
1695}
1696
1697#endif
1698
1699
1700
1701void
1702dk3uc2lat_font_encoding_reset(void)
1703{
1704  /* UNUSED */
1705}
1706
1707
1708
1709int
1710dk3uc2lat_font_encoding_conflict(void)
1711{
1712  int		 back	= 0;
1713  /* UNUSED */
1714  return back;
1715}
1716
1717
1718
1719void
1720dk3uc2lat_font_encoding_report_conflict(dk3_uc2lat_t *u)
1721{
1722  if (0x00 == u->fe) {
1723    /* Error */
1724    dk3app_log_i1(u->app, DK3_LL_ERROR, 411);
1725  }
1726}
1727
1728
1729
1730static
1731void
1732dk3uc2lat_report_for_encoding(dk3_uc2lat_t *u, const char *eptr)
1733{
1734#if DK3_CHAR_SIZE > 1
1735  dkChar	 buffer[32];
1736  dkChar	*dkptr		=	NULL;
1737  size_t	 szbu		=	DK3_SIZEOF(buffer,dkChar);
1738  if (szbu > strlen(eptr)) {
1739    dkptr = buffer;
1740    while ('\0' != *eptr) {
1741      *(dkptr++) = (dkChar)(*(eptr++));
1742    }
1743    *dkptr = dkT('\0');
1744    dk3app_log_i3(u->app, DK3_LL_INFO, 381, 382, buffer);
1745  }
1746#else
1747  dk3app_log_i3(u->app, DK3_LL_INFO, 381, 382, eptr);
1748#endif
1749}
1750
1751
1752
1753void
1754dk3uc2lat_font_encoding_report(dk3_uc2lat_t *u)
1755{
1756  if (0 != ((u->fe) & DK3_FONT_ENCODING_OT1)) {
1757    dk3uc2lat_report_for_encoding(u,  dk3uc2l_enco[0]);
1758  }
1759  if (0 != ((u->fe) & DK3_FONT_ENCODING_T1)) {
1760    dk3uc2lat_report_for_encoding(u,  dk3uc2l_enco[1]);
1761  }
1762  if (0 != ((u->fe) & DK3_FONT_ENCODING_T4)) {
1763    dk3uc2lat_report_for_encoding(u,  dk3uc2l_enco[2]);
1764  }
1765  if (0 != ((u->fe) & DK3_FONT_ENCODING_T5)) {
1766    dk3uc2lat_report_for_encoding(u,  dk3uc2l_enco[3]);
1767  }
1768}
1769
1770
1771
1772int
1773dk3uc2lat_direct(dk3_c32_t c32)
1774{
1775  int back = 0;
1776  char c;	/* 8-bit character version of c32. */
1777  $? "+ dk3uc2lat_direct %lx", dk3enc_uc_to_ul(c32)
1778  if(128UL > dk3enc_uc_to_ul((unsigned long)c32)) {
1779    c = (char)c32;
1780    switch(c) {
1781      case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
1782      case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
1783      case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
1784      case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
1785      case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
1786      case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
1787      case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W':
1788      case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3':
1789      case '4': case '5': case '6': case '7': case '8': case '9': case ',':
1790      case '.': case ':': case ';': case '+': case '-': case '?': case '!':
1791      case '|': case '@': case '(': case ')': case '/': case '=': case ' ':
1792      case '\t':
1793      {
1794        back = 1;
1795      }
1796      break;
1797    }
1798  } $? "- dk3uc2lat_direct %d", back
1799  return back;
1800}
1801
1802
1803
1804static
1805int
1806dk3uc2lat_stputc(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t ul, int *mmptr)
1807{
1808  char		 buf[16];
1809  const char	*ptr;
1810  size_t	 sz;
1811  int		 back	= 0;
1812
1813  if (0 != dk3uc2lat_direct(ul)) {
1814    if (0 != *mmptr) {
1815      dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1816      *mmptr = 0;
1817    }
1818    if (u->f_utf8) {
1819      sz = dk3enc_uc2utf8(ul, (unsigned char *)buf, sizeof(buf));
1820      buf[sz] = '\0';
1821    } else {
1822      buf[0] = (char)ul;
1823      buf[1] = '\0';
1824    }
1825    dk3stream_c8_fputs(st, buf);
1826    back = 1;
1827  } else {
1828    ptr = dk3uc2lat_get(u, ul, 0);
1829    if (NULL != ptr) {
1830      if (0 != *mmptr) {
1831        dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1832	*mmptr = 0;
1833      }
1834      dk3stream_c8_fputs(st, ptr);
1835    } else {
1836      ptr = dk3uc2lat_get(u, ul, 1);
1837      if (NULL != ptr) {
1838        if (0 == *mmptr) {
1839	  dk3stream_c8_fputs(st, dk3uc2lat_mm[0]);
1840	  *mmptr = 1;
1841	}
1842	dk3stream_c8_fputs(st, ptr);
1843      } else {
1844        /* ERROR: Not found, already reported */
1845      }
1846    }
1847  }
1848  return back;
1849}
1850
1851
1852
1853int
1854dk3uc2lat_c8_plain_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t)
1855{
1856  int 		back = 0;
1857  int		mm = 0;		/* Flag: In math mode. */
1858  char const	*ptr;		/* Current position. */
1859  dk3_c32_t	ul;		/* Output character. */
1860  char		c;		/* Current character. */
1861  $? "+ dk3uc2lat_c8_plain_stputs \"%!8s\"", TR_8STR(t)
1862  if((u) && (st) && (t)) {
1863    ptr = t; back = 1;
1864    while(*ptr) {
1865      c = *ptr;
1866      ul = (unsigned long)c;
1867      ul &= 0x000000FFUL;
1868      if(!dk3uc2lat_stputc(u, st, ul, &mm)) { back = 0; }
1869      ptr++;
1870    }
1871    if(mm) {
1872      dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1873    }
1874  }
1875  $? "- dk3uc2lat_c8_plain_stputs %d", back
1876  return back;
1877}
1878
1879
1880
1881int
1882dk3uc2lat_c8_utf8_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, char const *t)
1883{
1884  int				back = 0;
1885  int				mm = 0;	/* Flag: Math mode. */
1886  unsigned char const		*sp;	/* String pointer, current pos. */
1887  size_t			sl;	/* Remaining bytes. */
1888  size_t			used;	/* Bytes used for current c32. */
1889  dk3_c32_t			c32;	/* Current character. */
1890  $? "+ dk3uc2lat_c8_utf8_stputs \"%!8s\"", TR_8STR(t)
1891  if((u) && (st) && (t)) {
1892    sp = (unsigned char const *)t; sl = dk3str_c8_len(t); back = 1;
1893    while(sl) {
1894      used = 0;
1895      if(dk3enc_utf82uc(&c32, sp, sl, &used)) {
1896        if(!dk3uc2lat_stputc(u, st, c32, &mm)) {
1897	  back = 0;
1898	}
1899        if(used) {
1900	  if(sl >= used) {
1901	    sl = sl - used;
1902	    sp = &(sp[used]);
1903	  } else {
1904	    sl = 0; back = 0;
1905	  }
1906	} else {
1907	  sl = 0; back = 0; /* No byte used, will appear again and again. */
1908	}
1909      } else {
1910        sl = 0; back = 0;
1911	if(u->app) {
1912	  /* ERROR: Decoding failed! */
1913	  dk3app_log_i1(u->app, DK3_LL_ERROR, 118);
1914	}
1915      }
1916    }
1917    if(mm) {
1918      dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1919    }
1920  }
1921  $? "- dk3uc2lat_c8_utf8_stputs %d", back
1922  return back;
1923}
1924
1925
1926
1927int
1928dk3uc2lat_c16_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c16_t const *t)
1929{
1930  int 			back = 0;
1931  int			mm = 0;	/* Flag: Math mode. */
1932  dk3_c16_t const	*sp;	/* Current position. */
1933  size_t		sl;	/* Number of 16-bit characters remaining. */
1934  size_t		used;	/* Number of 16-bit characters used. */
1935  dk3_c32_t		c32;	/* Current output character. */
1936  $? "+ dk3uc2lat_c16_stputs %!8s", TR_8PTR(t)
1937  if((u) && (st) && (t)) {
1938    sp = t; sl = dk3str_c16_len(t); back = 1;
1939    while(sl) {
1940      used = 0;
1941      if(dk3enc_utf162uc(&c32, sp, sl, &used)) {
1942        if(used) {
1943	  if(!dk3uc2lat_stputc(u, st, c32, &mm)) { back = 0; }
1944	  if(sl >= used) {
1945	    sl = sl - used;
1946	    sp = &(sp[used]);
1947	  } else {
1948	    sl = 0;
1949	  }
1950	} else {
1951	  back = 0; sl = 0;
1952	  if(u->app) {
1953	    /* ERROR: Decoding */
1954	    dk3app_log_i1(u->app, DK3_LL_ERROR, 119);
1955	  }
1956	}
1957      } else {
1958        sl = 0; back = 0;
1959	if(u->app) {
1960	  /* Decoding error */
1961	  dk3app_log_i1(u->app, DK3_LL_ERROR, 119);
1962	}
1963      }
1964    }
1965    if(mm) {
1966      dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1967    }
1968  }
1969  $? "- dk3uc2lat_c16_stputs %d", back
1970  return back;
1971}
1972
1973
1974
1975int
1976dk3uc2lat_c32_stputs(dk3_uc2lat_t *u, dk3_stream_t *st, dk3_c32_t const *t)
1977{
1978  int			back = 0;
1979  int			mm = 0;	/* Flag: Math mode. */
1980  dk3_c32_t const	*ptr;	/* Current position. */
1981  $? "+ dk3uc2lat_c32_stputs %!8s", TR_8PTR(t)
1982  if((u) && (st) && (t)) {
1983    back = 1;
1984    ptr = t;
1985    while(*ptr) {
1986      if(!dk3uc2lat_stputc(u, st, *(ptr++), &mm)) {
1987        back = 0;
1988      }
1989    }
1990    if(mm) {
1991      dk3stream_c8_fputs(st, dk3uc2lat_mm[1]);
1992    }
1993  }
1994  $? "- dk3uc2lat_c32_stputs %d", back
1995  return back;
1996}
1997
1998
1999
2000int
2001dk3uc2lat_stputs(
2002  dk3_uc2lat_t *u,
2003  dk3_stream_t *st,
2004  dkChar const *t,
2005#if DK3_CHAR_SIZE > 1
2006  int		DK3_ARG_UNUSED(e)
2007#else
2008  int		e
2009#endif
2010)
2011{
2012  int back = 0;
2013  $? "+ dk3uc2lat_stputs \"%!ds\"", TR_STR(t)
2014#if DK3_CHAR_SIZE > 1
2015  DK3_UNUSED_ARG(e)
2016#if DK3_CHAR_SIZE > 2
2017  back = dk3uc2lat_c32_stputs(u, st, t);
2018#else
2019  back = dk3uc2lat_c16_stputs(u, st, t);
2020#endif
2021#else
2022  switch(e) {
2023    case DK3_ENCODING_UTF8: {
2024      back = dk3uc2lat_c8_utf8_stputs(u, st, t);
2025    } break;
2026    default: {
2027      back = dk3uc2lat_c8_plain_stputs(u, st, t);
2028    } break;
2029  }
2030#endif
2031  $? "- dk3uc2lat_stputs %d", back
2032  return back;
2033}
2034
2035
2036
2037void
2038dk3uc2lat_final_report(dk3_uc2lat_t *u, dk3_stream_t *st)
2039{
2040  dk3_uc2lat_pkg_t	*pkgp;
2041  dk3stream_c8_fputs(st, dk3uc2lat_mm[2]);
2042  if (0 != ((u->fe) & DK3_FONT_ENCODING_OT1)) {
2043    dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[0]);
2044  }
2045  if (0 != ((u->fe) & DK3_FONT_ENCODING_T1)) {
2046    dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[1]);
2047  }
2048  if (0 != ((u->fe) & DK3_FONT_ENCODING_T4)) {
2049    dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[2]);
2050  }
2051  if (0 != ((u->fe) & DK3_FONT_ENCODING_T5)) {
2052    dk3stream_c8_fputs(st, dk3uc2l_c8_font_encoding_names[3]);
2053  }
2054  dk3stream_c8_fputs(st, dk3uc2lat_mm[4]);
2055  dk3uc2lat_package_reset(u);
2056  do {
2057    pkgp = dk3uc2lat_package_next(u);
2058    if (NULL != pkgp) {
2059      $!trace-code if (NULL != pkgp->name) {
2060      $!trace-code   if (0x00 != pkgp->used) {
2061			$? ". pkg used %!8s", pkgp->name
2062      $!trace-code   } else {
2063			$? ". pkg not used %!8s", pkgp->name
2064      $!trace-code   }
2065      $!trace-code }
2066      if ((0x00 != pkgp->used) && (NULL != pkgp->name)) {
2067        dk3stream_c8_fputs(st, dk3uc2lat_mm[3]);
2068	dk3stream_c8_fputs(st, pkgp->name);
2069	dk3stream_c8_fputs(st, dk3uc2lat_mm[4]);
2070      }
2071    }
2072  } while (NULL != pkgp);
2073}
2074
2075
2076
2077/* vim: set ai sw=2 : */
2078