1 /*
2 Copyright (C) 2015-2021, Dirk Krause
3 SPDX-License-Identifier: BSD-3-Clause
4 */
5 
6 /*
7 	WARNING: This file was generated by the dkct program (see
8 	http://dktools.sourceforge.net/ for details).
9 	Changes you make here will be lost if dkct is run again!
10 	You should modify the original source and run dkct on it.
11 	Original source: dk4uc2l.ctr
12 */
13 
14 /**	@file dk4uc2l.c The dk4uc2l module.
15 */
16 
17 
18 
19 #include "dk4conf.h"
20 
21 #include <stdio.h>
22 
23 #if DK4_HAVE_STRING_H
24 #ifndef STRING_H_INCLUDED
25 #include <string.h>
26 #define	STRING_H_INCLUDED 1
27 #endif
28 #endif
29 
30 #include <libdk4base/dk4const.h>
31 #include <libdk4lat/dk4uc2l.h>
32 #include <libdk4c/dk4inst.h>
33 #include <libdk4base/dk4mem.h>
34 #include <libdk4app/dk4mema.h>
35 #include <libdk4base/dk4str8.h>
36 #include <libdk4base/dk4strd.h>
37 #include <libdk4c/dk4utf16.h>
38 #include <libdk4c/dk4utf8.h>
39 #include <libdk4c/dk4ansi.h>
40 #include <libdk4ma/dk4maasz.h>
41 #include <libdk4ma/dk4maaul.h>
42 #include <libdk4ma/dk4maadu.h>
43 #include <libdk4c/dk4filed.h>
44 #include <libdk4base/dk4mpl.h>
45 #include <libdk4c/dk4strm.h>
46 #include <libdk4c/dk4strmr.h>
47 #include <libdk4c/dk4dir.h>
48 #include <libdk4app/dk4dira.h>
49 #include <libdk4c/dk4pathd.h>
50 #include <libdk4c/dk4tsp08.h>
51 #include <libdk4c/dk4enc.h>
52 #include <libdk4maio8h/dk4mai8hul.h>
53 #include <libdk4maiodh/dk4maodh.h>
54 #include <libdk4maiodd/dk4maodd.h>
55 #include <libdk4base/dk4unused.h>
56 #include <libdk4c/dk4rec26.h>
57 #include <libdk4c/dk4strmo08.h>
58 
59 #ifndef	UC2L_H_INCLUDED
60 #include <libdk4lat/uc2l.h>
61 #endif
62 
63 #if DK4_HAVE_ASSERT_H
64 #ifndef	ASSERT_H_INCLUDED
65 #include <assert.h>
66 #define	ASSERT_H_INCLUDED 1
67 #endif
68 #endif
69 
70 
71 
72 
73 
74 
75 #define	UL(x)	((unsigned long)(x))
76 
77 
78 /**	Object to use and modify from line handler.
79 */
80 typedef struct {
81 	dk4_uc2l_t			*ulptr;		/**< Conversion structure. */
82 	dk4_sto_t			*s_ra;		/**< Local range storage. */
83 	dk4_sto_it_t		*i_ra;		/**< Local range iterator. */
84 	dk4_uc2l_file_t		*file;		/**< File structure. */
85 	dk4_uc2l_range_t	*rpc;		/**< Range pointer cache, pass 2. */
86 } handler_object_t;
87 
88 
89 
90 /**	File name suffixes to process.
91 */
92 static const dkChar * const dk4uc2l_suffixes[] = {
93 /* 0 */
94 dkT(".t2l"),
95 
96 /* 1 */
97 dkT(".t2l.gz"),
98 
99 /* 2 */
100 dkT(".t2l.bz2"),
101 
102 NULL
103 
104 };
105 
106 
107 
108 /**	Keywords allowed in a data line.
109 */
110 static const char * const	dk4uc2l_keywords[] = {
111 /* 0 */
112 "b$oth",
113 
114 /* 1 */
115 "t$ext",
116 
117 /* 2 */
118 "m$ath",
119 
120 /* 3 */
121 "e$ncoding",
122 
123 /* 4 */
124 "p$ackages",
125 
126 NULL
127 
128 };
129 
130 
131 
132 /**	Font encoding names.
133 */
134 static const char * const	dk4uc2l_font_encodings[] = {
135 /* 0 */
136 "ot1",
137 
138 /* 1 */
139 "t1",
140 
141 /* 2 */
142 "t4",
143 
144 /* 3 */
145 "t5",
146 
147 NULL
148 
149 };
150 
151 
152 
153 /**	Subdirectory names.
154 */
155 static const dkChar * const	dk4uc2l_kwnl[] = {
156 /* 0 */
157 dkT("/dktools/charmap"),
158 
159 /* 1 */
160 dkT("/dk4app/charmap"),
161 
162 /* 2 */
163 dkT("/dk3app/charmap"),
164 
165 /* 3 */
166 dkT("/"),
167 
168 NULL
169 
170 };
171 
172 
173 
174 /**	Constant text strings for recommendations.
175 */
176 static const char * const	dk4uc2l_kw8[] = {
177 /* 0 */
178 "% Font encodings:",
179 
180 /* 1 */
181 "% Recommended package: ",
182 
183 /* 2 */
184 " ot1",
185 
186 /* 3 */
187 " t1",
188 
189 /* 4 */
190 " t4",
191 
192 /* 5 */
193 " t5",
194 
195 NULL
196 
197 };
198 
199 
200 
201 /**	Opening and closing tag for math mode.
202 */
203 static const char * const	dk4uc2l_mm[] = {
204 "\\(", "\\)"
205 };
206 
207 
208 /**	Number of elements in dk4uc2l_suffixes array.
209 */
210 static const size_t		sz_suffixes =
211 DK4_SIZEOF(dk4uc2l_suffixes,DK4_PDKCHAR) - 1;
212 
213 
214 
215 /**	Compare two LaTeX package structures.
216 	@param	l	Left pointer, always a package structure.
217 	@param	r	Right pointer.
218 	@param	cr	Comparison criteria: 0 if r is a package pointer,
219 			1 if r is just a package name string.
220 	@return	Comparison result: 1 if l>r, 0 if l==r, -1 if l<r.
221 */
222 static
223 int
dk4uc2l_pkg_compare(const void * l,const void * r,int cr)224 dk4uc2l_pkg_compare(const void *l, const void *r, int cr)
225 {
226 
227 	const dk4_uc2l_pkg_t	*pl;
228 	const dk4_uc2l_pkg_t	*pr;
229 	int		 back = 0;
230 
231 	if (NULL != l) {
232 		if (NULL != r) {
233 			pl = (const dk4_uc2l_pkg_t *)l;
234 			switch (cr) {
235 				case 1: {
236 	  				back = strcmp(pl->pn, (const char *)r);
237 				} break;
238 				default: {
239 	  				pr = (const dk4_uc2l_pkg_t *)r;
240 	  				back = strcmp(pl->pn, pr->pn);
241 				} break;
242 			}
243 			if (-1 > back) back = -1;
244 			if ( 1 < back) back =  1;
245 		}
246 		else {
247 			back = 1;
248 		}
249 	}
250 	else {
251 		if (NULL != r) { back = -1; }
252 	}
253 	return back;
254 }
255 
256 
257 
258 /**	Compare two file information structures.
259 	@param	l	Left pointer, always a file information structure.
260 	@param	r	Right pointer.
261 	@param	cr	Comparison criteria:
262 			0 if the right pointer is a file information structure
263 			pointer,
264 			1 if the right pointer is a file name string.
265 	@return	Comparison result: 0 if file names are equal, -1 if l<r,
266 	1 if l>r.
267 */
268 static
269 int
dk4uc2l_file_compare(const void * l,const void * r,int cr)270 dk4uc2l_file_compare(const void *l, const void *r, int cr)
271 {
272 	const	dk4_uc2l_file_t	*pl;
273 	const	dk4_uc2l_file_t	*pr;
274 	int		 back = 0;
275 	if (NULL != l) {
276 		if (NULL != r) {
277 			pl = (const dk4_uc2l_file_t *)l;
278 			switch (cr) {
279 				case 1: {
280 	  				back = dk4str_pathcmp(pl->fn, (const dkChar *)r);
281 				} break;
282 				default: {
283 	  				pr = (const dk4_uc2l_file_t *)r;
284 	  				back = dk4str_pathcmp(pl->fn, pr->fn);
285 				} break;
286 			}
287 			if (-1 > back) { back = -1; }
288 			if ( 1 < back) { back =  1; }
289 		}
290 		else {
291 			back = 1;
292 		}
293 	}
294 	else {
295 		if (NULL != r) {
296 			back = -1;
297 		}
298 	}
299 	return back;
300 }
301 
302 
303 
304 /**	Compare two range informations or a range information against a
305 	character.
306 	@param	l	Left pointer, always a range information structure.
307 	@param	r	Right pointer.
308 	@param	cr	Comparison criteria:
309 			0 if the right pointer is a range information strucutre,
310 			1 if the right pointer is a pointer to a dk4_c32_t.
311 	@return	Comparison result: -1 if l<r, 0 if l=r, 1 if l>r.
312 */
313 int
dk4uc2l_i_range_compare(const void * l,const void * r,int cr)314 dk4uc2l_i_range_compare(const void *l, const void *r, int cr)
315 {
316 	const dk4_uc2l_range_t	*pl;
317 	const dk4_uc2l_range_t	*pr;
318 	const dk4_c32_t		*pc;
319 	int		 back = 0;
320 	if (NULL != l) {
321 		if (NULL != r) {
322 			pl = (const dk4_uc2l_range_t *)l;
323 			switch (cr) {
324 				case 1: {
325 	  				pc = (const dk4_c32_t *)r;
326 	  				if (pl->start > *pc) {
327 						back = 1;
328 					}
329 					else {
330 						if (pl->end < *pc) {
331 							back = -1;
332 						}
333 	  				}
334 				} break;
335 				default: {
336 					pr = (const dk4_uc2l_range_t *)r;
337 					if (pl->start < pr->start) {
338 						back = -1;
339 					}
340 					else {
341 						if (pl->start > pr->start) {
342 							back = 1;
343 						}
344 					}
345 				} break;
346 			}
347 		}
348 		else {
349 			back = 1;
350 		}
351 	}
352 	else {
353 		if (NULL != r) {
354 			back = -1;
355 		}
356 	}
357 	return back;
358 }
359 
360 
361 
362 int
dk4uc2l_i_suffix_index_supported(int i)363 dk4uc2l_i_suffix_index_supported(int i)
364 {
365 	int			 back	= 1;
366 	switch (i) {
367 		case 1: {
368 #if !DK4_HAVE_ZLIB_H
369 			back = 0;
370 #endif
371 		} break;
372 		case 2: {
373 #if !DK4_HAVE_BZLIB_H
374 			back = 0;
375 #endif
376 		} break;
377 	}
378 	return back;
379 }
380 
381 
382 
383 int
dk4uc2l_i_find_suffix_index(const dkChar * fn)384 dk4uc2l_i_find_suffix_index(const dkChar *fn)
385 {
386 	size_t		 sz		=  0;
387 	size_t		 i		=  0;
388 	size_t		 susz	=  0;
389 	int			 back	= -1;
390 
391 	if (NULL != fn) {
392 		sz = dk4str_len(fn);
393 		for (i = 0; ((i < sz_suffixes) && (0 > back)); i++) {
394 			susz = dk4str_len(dk4uc2l_suffixes[i]);
395 			if (sz > susz) {
396 				if (0 == dk4str_pathcmp(&(fn[sz - susz]), dk4uc2l_suffixes[i])) {
397 					back = (int)i; i = sz_suffixes;
398 				}
399 			}
400 		}
401 	}
402 	return back;
403 }
404 
405 
406 
407 void
dk4uc2l_i_close_file(dk4_uc2l_file_t * fptr)408 dk4uc2l_i_close_file(dk4_uc2l_file_t *fptr)
409 {
410 
411 	if (NULL != fptr) {
412 
413 		dk4mem_release(fptr->fn);
414 		fptr->loaded = 0x00;
415 		dk4mem_free(fptr);
416 	}
417 
418 }
419 
420 
421 
422 dk4_uc2l_file_t *
dk4uc2l_i_open_file(const dkChar * fn,dk4_er_t * erp)423 dk4uc2l_i_open_file(const dkChar *fn, dk4_er_t *erp)
424 {
425 	dk4_uc2l_file_t		*back	= NULL;
426 
427 	if (NULL != fn) {
428 		back = dk4mem_new(dk4_uc2l_file_t,1,erp);
429 		if (NULL != back) {
430 			back->loaded = 0x00;
431 			back->fn = dk4str_dup(fn, erp);
432 			if (NULL == back->fn) {
433 				dk4mem_free(back);
434 				back = NULL;
435 			}
436 		}
437 #if TRACE_DEBUG
438 		else {
439 		}
440 #endif
441 	}
442 	else {
443 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
444 	}
445 
446 	return back;
447 }
448 
449 
450 
451 void
dk4uc2l_i_close_pkg(dk4_uc2l_pkg_t * pptr)452 dk4uc2l_i_close_pkg(dk4_uc2l_pkg_t *pptr)
453 {
454 
455 	if (NULL != pptr) {
456 
457 		dk4mem_release(pptr->pn);
458 		pptr->used = 0x00;
459 		dk4mem_free(pptr);
460 	}
461 
462 }
463 
464 
465 
466 dk4_uc2l_pkg_t *
dk4uc2l_i_open_pkg(const char * pn,dk4_er_t * erp)467 dk4uc2l_i_open_pkg(const char *pn, dk4_er_t *erp)
468 {
469 	dk4_uc2l_pkg_t	*back	= NULL;
470 
471 	if (NULL != pn) {
472 		back = dk4mem_new(dk4_uc2l_pkg_t,1,erp);
473 		if (NULL != back) {
474 			back->used = 0x00;
475 			back->pn = dk4str8_dup(pn, erp);
476 			if (NULL == back->pn) {
477 				dk4mem_free(back);
478 				back = NULL;
479 			}
480 #if TRACE_DEBUG
481 			else {
482 			}
483 #endif
484 		}
485 #if TRACE_DEBUG
486 		else {
487 		}
488 #endif
489 	}
490 	else {
491 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
492 	}
493 
494 	return back;
495 }
496 
497 
498 
499 
500 void
dk4uc2l_i_close_range(dk4_uc2l_range_t * rptr)501 dk4uc2l_i_close_range(dk4_uc2l_range_t *rptr)
502 {
503 	dk4_er_t		er;		/* Error report to detect numeric overflow */
504 	unsigned long	n;		/* Number of elements in range */
505 	size_t			nn;		/* Size_t version of n */
506 	size_t			i;		/* Traverse all elements */
507 
508 	if (NULL != rptr) {
509 
510 #if TRACE_DEBUG
511 		if (NULL != rptr->file) {
512 			if (NULL != rptr->file->fn) {
513 
514 			}
515 		}
516 #endif
517 		dk4error_init(&er);
518 		n = dk4ma_ulong_sub(rptr->end, rptr->start, &er);
519 		n = dk4ma_ulong_add(n, 1UL, &er);
520 #if 0
521 		if ((DK4_E_NONE == er.ec) && ((dk4_um_t)n <= (dk4_um_t)(SIZE_MAX)))
522 #endif
523 		if ((DK4_E_NONE == er.ec) && (dk4ma_um_isgeq(SIZE_MAX, n))) {
524 			nn = (size_t)n;
525 			if (NULL != rptr->both) {
526 				for (i = 0; i < nn; i++) {
527 					dk4mem_release((rptr->both)[i]);
528 				}
529 				dk4mem_free(rptr->both); rptr->both = NULL;
530 			}
531 			if (NULL != rptr->text) {
532 				for (i = 0; i < nn; i++) {
533 					dk4mem_release((rptr->text)[i]);
534 				}
535 				dk4mem_free(rptr->text); rptr->text = NULL;
536 			}
537 			if (NULL != rptr->math) {
538 				for (i = 0; i < nn; i++) {
539 					dk4mem_release((rptr->math)[i]);
540 				}
541 				dk4mem_free(rptr->math); rptr->math = NULL;
542 			}
543 			if (NULL != rptr->pkgs) {
544 				for (i = 0; i < nn; i++) {
545 					dk4mem_release((rptr->pkgs)[i]);
546 				}
547 				dk4mem_free(rptr->pkgs); rptr->pkgs = NULL;
548 			}
549 			if (NULL != rptr->fenc) {
550 				dk4mem_free(rptr->fenc); rptr->fenc = NULL;
551 			}
552 			if (NULL != rptr->lno) {
553 				dk4mem_free(rptr->lno); rptr->lno = NULL;
554 			}
555 		}
556 		rptr->file = NULL;
557 		rptr->start = (dk4_c32_t)0UL;
558 		rptr->end = (dk4_c32_t)0UL;
559 		rptr->ia = 0x00;
560 		dk4mem_free(rptr);
561 	}
562 
563 }
564 
565 
566 
567 int
dk4uc2l_i_init_range(dk4_uc2l_range_t * rptr,dk4_er_t * erp)568 dk4uc2l_i_init_range(
569 	dk4_uc2l_range_t	*rptr,
570 	dk4_er_t			*erp
571 )
572 {
573 	dk4_er_t			  er;
574 	char				**ppchr;
575 	dk4_uc2l_pkg_pp		 *pppkg;
576 	unsigned char		 *puc;
577 	dk4_um_t			 *pum;
578 	size_t				  sznum	= 0;
579 	size_t				  i		= 0;
580 	unsigned long		  num	= 0UL;
581 	int					  back	= 0;
582 
583 
584 	/*	Avoid second initialization
585 	*/
586 	if (0x00 != rptr->ia) {
587 		back = 1;
588 		goto finished;
589 	}
590 
591 	/*	Find number of elements
592 	*/
593 	dk4error_init(&er);
594 	num = dk4ma_ulong_add(
595 		dk4ma_ulong_sub(
596 			(unsigned long)(rptr->end), (unsigned long)(rptr->start), &er
597 		), 1UL, &er
598 	);
599 	if (DK4_E_NONE != er.ec) {
600 		dk4error_copy(erp, &er);
601 		goto finished;
602 	}
603 #if 0
604 	if ((dk4_um_t)(SIZE_MAX) >= (dk4_um_t)num)
605 #endif
606 	if (0 != dk4ma_um_isgeq(SIZE_MAX, num)) {
607 		sznum = (size_t)num;
608 	}
609 	else {
610 		dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
611 		goto finished;
612 	}
613 
614 	/*	both
615 	*/
616 	if (NULL == rptr->both) {
617 		rptr->both = dk4mem_new(DK4_PCHAR,sznum,erp);
618 		if (NULL != rptr->both) {
619 			ppchr = rptr->both;
620 			for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; }
621 		}
622 		else {
623 			goto finished;
624 		}
625 	}
626 
627 	/*	text
628 	*/
629 	if (NULL == rptr->text) {
630 		rptr->text = dk4mem_new(DK4_PCHAR,sznum,erp);
631 		if (NULL != rptr->text) {
632 			ppchr = rptr->text;
633 			for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; }
634 		}
635 		else {
636 			goto finished;
637 		}
638 	}
639 
640 	/*	math
641 	*/
642 	if (NULL == rptr->math) {
643 		rptr->math = dk4mem_new(DK4_PCHAR,sznum,erp);
644 		if (NULL != rptr->math) {
645 			ppchr = rptr->math;
646 			for (i = 0; i < sznum; i++) { *(ppchr++) = NULL; }
647 		}
648 		else {
649 			goto finished;
650 		}
651 	}
652 
653 	/*	pkgs
654 	*/
655 	if (NULL == rptr->pkgs) {
656 		rptr->pkgs = dk4mem_new(dk4_uc2l_pkg_pp,sznum,erp);
657 		if (NULL != rptr->pkgs) {
658 			pppkg = rptr->pkgs;
659 			for (i = 0; i < sznum; i++) { *(pppkg++) = NULL; }
660 		}
661 		else{
662 			goto finished;
663 		}
664 	}
665 
666 	/*	fenc
667 	*/
668 	if (NULL == rptr->fenc) {
669 		rptr->fenc = dk4mem_new(unsigned char,sznum,erp);
670 		if (NULL != rptr->fenc) {
671 			puc = rptr->fenc;
672 			for (i = 0; i < sznum; i++) { *(puc++) = 0xFF; }
673 		}
674 		else {
675 			goto finished;
676 		}
677 	}
678 
679 	/*	lno
680 	*/
681 	if (NULL == rptr->lno) {
682 		rptr->lno = dk4mem_new(dk4_um_t,sznum,erp);
683 		if (NULL != rptr->lno) {
684 			pum = rptr->lno;
685 			for (i = 0; i < sznum; i++) { *(pum++) = (dk4_um_t)0UL; }
686 		}
687 		else {
688 			goto finished;
689 		}
690 	}
691 
692 	/*	Success
693 	*/
694 	back = 1;
695 
696 	/*	Return
697 	*/
698 	finished:
699 
700 	return back;
701 }
702 
703 
704 
705 dk4_uc2l_range_t *
dk4uc2l_i_open_range(dk4_c32_t c32,dk4_uc2l_file_t * fptr,dk4_er_t * erp)706 dk4uc2l_i_open_range(
707 	dk4_c32_t		 c32,
708 	dk4_uc2l_file_t	*fptr,
709 	dk4_er_t		*erp
710 )
711 {
712 	dk4_uc2l_range_t		*back	= NULL;
713 
714 	if (NULL != fptr) {
715 		back = dk4mem_new(dk4_uc2l_range_t,1,erp);
716 		if (NULL != back) {
717 			back->file = fptr;
718 			back->both = NULL;
719 			back->text = NULL;
720 			back->math = NULL;
721 			back->pkgs = NULL;
722 			back->fenc = NULL;
723 			back->lno  = NULL;
724 			back->start = back->end = c32;
725 			back->ia = 0x00;
726 		}
727 #if TRACE_DEBUG
728 		else {
729 		}
730 #endif
731 	}
732 	else {
733 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
734 	}
735 
736 	return back;
737 }
738 
739 
740 
741 void
dk4uc2l_close(dk4_uc2l_t * ulptr)742 dk4uc2l_close(dk4_uc2l_t *ulptr)
743 {
744 	dk4_uc2l_pkg_t		*pptr;
745 	dk4_uc2l_file_t		*fptr;
746 	dk4_uc2l_range_t	*rptr;
747 
748 #if	DK4_USE_ASSERT
749 	assert(NULL != ulptr);
750 #endif
751 	if (NULL != ulptr) {
752 		dk4mem_release(ulptr->dname);
753 		if (NULL != ulptr->s_ranges) {
754 			if (NULL != ulptr->i_ranges) {
755 				dk4sto_it_reset(ulptr->i_ranges);
756 				do {
757 					rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ulptr->i_ranges);
758 					if (NULL != rptr) {
759 						dk4uc2l_i_close_range(rptr);
760 					}
761 				} while (NULL != rptr);
762 				dk4sto_it_close(ulptr->i_ranges);
763 			}
764 			dk4sto_close(ulptr->s_ranges);
765 		}
766 		ulptr->s_ranges = NULL;
767 		ulptr->i_ranges = NULL;
768 		if (NULL != ulptr->s_files) {
769 			if (NULL != ulptr->i_files) {
770 				dk4sto_it_reset(ulptr->i_files);
771 				do {
772 					fptr = (dk4_uc2l_file_t *)dk4sto_it_next(ulptr->i_files);
773 					if (NULL != fptr) {
774 						dk4uc2l_i_close_file(fptr);
775 					}
776 				} while (NULL != fptr);
777 				dk4sto_it_close(ulptr->i_files);
778 			}
779 			dk4sto_close(ulptr->s_files);
780 		}
781 		ulptr->s_files = NULL;
782 		ulptr->i_files = NULL;
783 		if (NULL != ulptr->s_pkgs) {
784 			if (NULL != ulptr->i_pkgs) {
785 				dk4sto_it_reset(ulptr->i_pkgs);
786 				do {
787 					pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs);
788 					if (NULL != pptr) {
789 						dk4uc2l_i_close_pkg(pptr);
790 					}
791 				} while (NULL != pptr);
792 				dk4sto_it_close(ulptr->i_pkgs);
793 			}
794 			dk4sto_close(ulptr->s_pkgs);
795 		}
796 		ulptr->s_pkgs = NULL;
797 		ulptr->i_pkgs = NULL;
798 		dk4mem_free(ulptr);
799 	}
800 
801 }
802 
803 
804 
805 dk4_uc2l_t *
dk4uc2l_i_new(const dkChar * dn,dk4_er_t * erp)806 dk4uc2l_i_new(const dkChar *dn, dk4_er_t *erp)
807 {
808 	dk4_uc2l_t	*back	= NULL;
809 	int			 ok		= 0;
810 
811 	back = dk4mem_new(dk4_uc2l_t,1,erp);
812 	if (NULL != back) {
813 		back->buf[0] = '\0';
814 		back->dname = NULL;
815 		back->s_ranges = NULL;
816 		back->i_ranges = NULL;
817 		back->s_files = NULL;
818 		back->i_files = NULL;
819 		back->s_pkgs = NULL;
820 		back->i_pkgs = NULL;
821 		back->had_error = 0;
822 		back->utf8allowed = 0;
823 		back->fallowed = 0xFF;
824 		back->dname = dk4str_dup(dn, erp);
825 		if (NULL != back->dname) {
826 			back->s_ranges = dk4sto_open(erp);
827 			back->s_files  = dk4sto_open(erp);
828 			back->s_pkgs = dk4sto_open(erp);
829 			if (
830 				(NULL != back->s_ranges)
831 				&& (NULL != back->s_files)
832 				&& (NULL != back->s_pkgs)
833 			) {
834 				dk4sto_set_comp(back->s_ranges, dk4uc2l_i_range_compare, 0);
835 				dk4sto_set_comp(back->s_files, dk4uc2l_file_compare, 0);
836 				dk4sto_set_comp(back->s_pkgs, dk4uc2l_pkg_compare, 0);
837 				back->i_ranges = dk4sto_it_open(back->s_ranges, erp);
838 				back->i_files = dk4sto_it_open(back->s_files, erp);
839 				back->i_pkgs = dk4sto_it_open(back->s_pkgs, erp);
840 				if (
841 					(NULL != back->i_ranges)
842 					&& (NULL != back->i_files)
843 					&& (NULL != back->i_pkgs)
844 				) {
845 					ok = 1;
846 				}
847 #if TRACE_DEBUG
848 				else {
849 				}
850 #endif
851 			}
852 #if TRACE_DEBUG
853 			else {
854 			}
855 #endif
856 		}
857 #if TRACE_DEBUG
858 		else {
859 		}
860 #endif
861 	}
862 #if TRACE_DEBUG
863 	else {
864 	}
865 #endif
866 	if ((NULL != back) && (0 == ok)) {
867 		dk4uc2l_close(back);
868 		back = NULL;
869 	}
870 
871 	return back;
872 }
873 
874 
875 
876 /**	Handler to process a line during pass 1.
877 	@param	obj		Object to use and modify during processing.
878 	@param	line	Current text line to process.
879 	@param	lineno	Current line number.
880 	@param	erp		Error report, may be NULL.
881 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable
882 	errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort.
883 */
884 static
885 int
dk4uc2l_handler_pass1(void * obj,char * line,dk4_um_t DK4_ARG_UNUSED (lineno),dk4_er_t * erp)886 dk4uc2l_handler_pass1(
887 	void		*obj,
888 	char		*line,
889 	dk4_um_t	 DK4_ARG_UNUSED(lineno) ,
890 	dk4_er_t	*erp
891 )
892 {
893 	handler_object_t	*pho;
894 	char				*p1;
895 	dk4_uc2l_range_t	*rptr;
896 	dk4_uc2l_range_t	*r2;
897 	const char			*pe		= NULL;
898 	unsigned long		 ul		= 0UL;
899 	dk4_c32_t			 c32;
900 	dk4_c32_t			 rbo;
901 	int					 res;
902 	int					 back	= DK4_TSP_RES_OK;
903 
904 	DK4_UNUSED_ARG(lineno)
905 #if TRACE_DEBUG
906 	dk4str8_delnl(line);
907 #endif
908 
909 	pho = (handler_object_t *)obj;
910 
911 	/*	Find start of line.
912 	*/
913 	p1 = dk4str8_start(line, NULL);
914 
915 	/*	Ignore empty lines and comment lines
916 	*/
917 	if (NULL == p1) {
918 		goto finished;
919 	}
920 	if ('#' == *p1) {
921 		goto finished;
922 	}
923 
924 	/*	Retrieve hexadecimal number
925 	*/
926 	(void)dk4str8_next(p1, NULL);
927 	res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp);
928 	if (0 == res) {
929 		/* ERROR: Syntax, not a number */
930 		goto finished;
931 	}
932 	c32 = (dk4_c32_t)ul;
933 
934 	/*	Check for number in global storage
935 	*/
936 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(
937 		pho->ulptr->i_ranges, &c32, 1
938 	);
939 	if (NULL != rptr) {
940 		/* WARNING erp: Ignoring redefinition */
941 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
942 		goto finished;
943 	}
944 
945 	/*	Check for number in storage for file
946 	*/
947 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &c32, 1);
948 	if (NULL != rptr) {
949 		/* WARNING erp: Ignoring redefinition */
950 		dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
951 		goto finished;
952 	}
953 
954 	/*	Check whether appending to existing range
955 	*/
956 	if (0UL < c32) {
957 		rbo = (dk4_c32_t)(c32 - 1UL);
958 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1);
959 		if (NULL != rptr) {
960 			rptr->end = c32;
961 #if	DK4_SIZEOF_LONG <= 4
962 			if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) {
963 #endif
964 				rbo = (dk4_c32_t)(c32 + 1UL);
965 				r2  = (dk4_uc2l_range_t *)dk4sto_it_find_like(
966 					pho->i_ra, &rbo, 1
967 				);
968 				if (NULL != r2) {
969 					dk4sto_remove(pho->s_ra, r2, NULL);
970 					rptr->end = r2->end;
971 					dk4uc2l_i_close_range(r2);
972 				}
973 #if	DK4_SIZEOF_LONG <= 4
974 			}
975 #endif
976 			goto finished;
977 		}
978 	}
979 
980 	/*	Check whether prepending to existing range
981 	*/
982 #if	DK4_SIZEOF_LONG <= 4
983 	if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) {
984 #endif
985 		rbo = (dk4_c32_t)(c32 + 1UL);
986 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1);
987 		if (NULL != rptr) {
988 			rptr->start = c32;
989 			if ((dk4_c32_t)0UL < c32) {
990 				rbo = (dk4_c32_t)(c32 - 1UL);
991 				r2  = (dk4_uc2l_range_t *)dk4sto_it_find_like(
992 					pho->i_ra, &rbo, 1
993 				);
994 				if (NULL != r2) {
995 					dk4sto_remove(pho->s_ra, r2, NULL);
996 					rptr->start = r2->start;
997 					dk4uc2l_i_close_range(r2);
998 				}
999 			}
1000 			goto finished;
1001 		}
1002 #if	DK4_SIZEOF_LONG <= 4
1003 	}
1004 #endif
1005 	/*	Create range on its own
1006 	*/
1007 	rptr = dk4uc2l_i_open_range(c32, pho->file, erp);
1008 	if (NULL == rptr) {
1009 		back = DK4_TSP_RES_FATAL;
1010 		goto finished;
1011 	}
1012 	if (0 == dk4sto_add(pho->ulptr->s_ranges, rptr, erp)) {
1013 		dk4uc2l_i_close_range(rptr);
1014 		back = DK4_TSP_RES_FATAL;
1015 	}
1016 
1017 	finished:
1018 
1019 	return back;
1020 }
1021 
1022 
1023 
1024 /**	Process one file in pass 1 specified by absolute path name.
1025 	@param	ulptr	Conversion structure to set up.
1026 	@param	rstrm	Stream, opened for binary reading.
1027 	@param	puc2lf	File structure.
1028 	@param	erp		Error report, may be NULL.
1029 	@param	bptr	Address of success variable to reset on errors.
1030 */
1031 static
1032 void
dk4uc2l_i_process_stream_pass1(dk4_uc2l_t * ulptr,dk4_stream_t * rstrm,dk4_uc2l_file_t * puc2lf,int * bptr,dk4_er_t * erp)1033 dk4uc2l_i_process_stream_pass1(
1034 	dk4_uc2l_t		*ulptr,
1035 	dk4_stream_t	*rstrm,
1036 	dk4_uc2l_file_t	*puc2lf,
1037 	int				*bptr,
1038 	dk4_er_t		*erp
1039 )
1040 {
1041 	char					 lnbuf[256];	/* Line buffer */
1042 	dk4_tsp08_t				 tsp08;			/* Text stream processor */
1043 	handler_object_t		 ho;			/* Handler object */
1044 	dk4_uc2l_range_t		*rptr;			/* Current range */
1045 	int						 res;			/* Operation result */
1046 	int						 cc;			/* Flag: Can continue */
1047 	char					 c;				/* Current character to process */
1048 
1049 
1050 	/*	Initialize handler object
1051 	*/
1052 	ho.file  = puc2lf;
1053 	ho.ulptr = ulptr;
1054 	ho.s_ra  = NULL;
1055 	ho.i_ra  = NULL;
1056 
1057 	/*	Create storage and iterator
1058 	*/
1059 	ho.s_ra = dk4sto_open(erp);
1060 	if (NULL == ho.s_ra) {
1061 		*bptr = 0;
1062 		ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1063 		goto finished;
1064 	}
1065 	dk4sto_set_comp(ho.s_ra, dk4uc2l_i_range_compare, 0);
1066 	ho.i_ra = dk4sto_it_open(ho.s_ra, erp);
1067 	if (NULL == ho.i_ra) {
1068 		*bptr = 0;
1069 		ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1070 		goto finished;
1071 	}
1072 
1073 	/*	Initialize text stream processor
1074 	*/
1075 	res = dk4tsp08_setup_line(
1076 		&tsp08, (void *)(&ho), dk4uc2l_handler_pass1, lnbuf, sizeof(lnbuf),
1077 		DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, erp
1078 	);
1079 	if (0 == res) {
1080 		*bptr = 0;
1081 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1082 		goto finished;
1083 	}
1084 
1085 	/*	Process file contents
1086 	*/
1087 	do {
1088 		cc = 0;
1089 		res = dk4stream_c8_read_byte(&c, rstrm, NULL);
1090 		if (0 != res) {
1091 			cc = 1;
1092 			res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c);
1093 			switch (res) {
1094 				case DK4_TSP_RES_ERROR : {
1095 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1096 					*bptr = 0;
1097 				} break;
1098 				case DK4_TSP_RES_FATAL : {
1099 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1100 					*bptr = 0;
1101 					goto finished;
1102 				} break;
1103 			}
1104 		}
1105 	} while (0 < cc);
1106 
1107 	/*	Finalize text stream processor
1108 	*/
1109 	res = dk4tsp08_finish(&tsp08);
1110 	switch (res) {
1111 		case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : {
1112 			*bptr = 0;
1113 			ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1114 			goto finished;
1115 		} break;
1116 	}
1117 
1118 	/*	Transfer ranges to global storage
1119 	*/
1120 	do {
1121 		dk4sto_it_reset(ho.i_ra);
1122 		rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra);
1123 		if (NULL != rptr) {
1124 			dk4sto_remove(ho.s_ra, rptr, erp);
1125 			if (0 == dk4sto_add(ulptr->s_ranges, rptr, erp)) {
1126 				dk4uc2l_i_close_range(rptr);
1127 				*bptr = 0;
1128 				goto finished;
1129 			}
1130 		}
1131 	} while (NULL != rptr);
1132 
1133 	/*	Release resources
1134 	*/
1135 	finished:
1136 	if (NULL != ho.s_ra) {
1137 		if (NULL != ho.i_ra) {
1138 			dk4sto_it_reset(ho.i_ra);
1139 			do {
1140 				rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra);
1141 				if (NULL != rptr) {
1142 					dk4uc2l_i_close_range(rptr);
1143 				}
1144 			} while (NULL != rptr);
1145 			dk4sto_it_close(ho.i_ra);
1146 		}
1147 		dk4sto_close(ho.s_ra);
1148 	}
1149 
1150 
1151 }
1152 
1153 
1154 /**	Process one file in pass 1 specified by absolute path name.
1155 	@param	ulptr	Conversion structure to set up.
1156 	@param	fn		Full (absolute) file name.
1157 	@param	sfn		Short file name within given directory.
1158 	@param	erp		Error report, may be NULL.
1159 	@param	bptr	Address of success variable to reset on errors.
1160 */
1161 static
1162 void
dk4uc2l_i_process_one_full_file_pass1(dk4_uc2l_t * ulptr,const dkChar * fn,const dkChar * sfn,int * bptr,dk4_er_t * erp)1163 dk4uc2l_i_process_one_full_file_pass1(
1164 	dk4_uc2l_t		*ulptr,
1165 	const dkChar	*fn,
1166 	const dkChar	*sfn,
1167 	int				*bptr,
1168 	dk4_er_t		*erp
1169 )
1170 {
1171 	dk4_stream_t	*rstrm;
1172 	dk4_uc2l_file_t	*puc2lf;
1173 	int				 fnsi;
1174 
1175 
1176 	puc2lf = (dk4_uc2l_file_t *)dk4sto_it_find_like(ulptr->i_files, sfn, 1);
1177 	if (NULL == puc2lf) {
1178 		puc2lf = dk4uc2l_i_open_file(sfn, erp);
1179 		if (NULL != puc2lf) {
1180 			if (0 != dk4sto_add(ulptr->s_files, puc2lf, erp)) {
1181 				fnsi = dk4uc2l_i_find_suffix_index(fn);
1182 				if (-1 < fnsi) {
1183 					if (0 != dk4uc2l_i_suffix_index_supported(fnsi)) {
1184 						rstrm = dk4stream_open_file_reader(fn, erp);
1185 						if (NULL != rstrm) {
1186 							/* Process stream */
1187 							dk4uc2l_i_process_stream_pass1(
1188 								ulptr, rstrm, puc2lf, bptr, erp
1189 							);
1190 							dk4stream_close(rstrm, NULL);
1191 						}
1192 						else {
1193 							ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
1194 							*bptr = 0;
1195 						}
1196 					}
1197 					else {
1198 						ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
1199 						*bptr = 0;
1200 						/* ERROR erp: Compression type not supported */
1201 						dk4error_set_simple_error_code(erp, DK4_E_NOT_SUPPORTED);
1202 					}
1203 				}
1204 				else {
1205 					/* Ignoring unsupported file */
1206 				}
1207 			}
1208 			else {
1209 				dk4uc2l_i_close_file(puc2lf);
1210 			}
1211 		}
1212 #if TRACE_DEBUG
1213 		else {
1214 		}
1215 #endif
1216 	}
1217 #if TRACE_DEBUG
1218 	else {
1219 	}
1220 #endif
1221 
1222 }
1223 
1224 
1225 
1226 /**	Process one file in pass 1.
1227 	@param	ulptr	Conversion structure to set up.
1228 	@param	pth		Directory path name, may be NULL.
1229 	@param	fn		Short file name within given directory.
1230 	@param	erp		Error report, may be NULL.
1231 	@param	bptr	Address of success variable to reset on errors.
1232 */
1233 static
1234 void
dk4uc2l_i_process_one_file_pass1(dk4_uc2l_t * ulptr,const dkChar * pth,const dkChar * fn,int * bptr,dk4_er_t * erp)1235 dk4uc2l_i_process_one_file_pass1(
1236 	dk4_uc2l_t		*ulptr,
1237 	const dkChar	*pth,
1238 	const dkChar	*fn,
1239 	int				*bptr,
1240 	dk4_er_t		*erp
1241 )
1242 {
1243 	dkChar			 fnb[DK4_MAX_PATH];
1244 	size_t			 szfnb	= DK4_SIZEOF(fnb,dkChar);
1245 
1246 	if (NULL != pth) {
1247 		if (0 != dk4str_cpy_s(fnb, szfnb, pth, erp)) {
1248 			if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[3], erp)) {
1249 				if (0 != dk4str_cat_s(fnb, szfnb, fn, erp)) {
1250 					dk4path_correct_sep(fnb);
1251 					dk4uc2l_i_process_one_full_file_pass1(
1252 						ulptr, fnb, fn, bptr, erp
1253 					);
1254 				}
1255 				else {
1256 					*bptr = 0;
1257 				}
1258 			}
1259 			else {
1260 				*bptr = 0;
1261 			}
1262 		}
1263 		else {
1264 			*bptr = 0;
1265 		}
1266 	}
1267 	else {
1268 		dk4uc2l_i_process_one_full_file_pass1(ulptr, fn, fn, bptr, erp);
1269 	}
1270 
1271 }
1272 
1273 
1274 
1275 /**	First pass to gather information which Unicode position is configured
1276 	in which data file.
1277 	This function is run while creating a new conversion structure
1278 	to fill the range structures so we can later find a file for a
1279 	Unicode position.
1280 	If this function fails, the conversion structure is considered
1281 	unusable.
1282 	The function fails only on memory allocation failures, not on
1283 	syntax errors in translation files.
1284 	@param	ulptr	Conversion structure.
1285 	@param	erp		Error report, may be NULL.
1286 	@return	1 on success, 0 on error.
1287 */
1288 static
1289 int
dk4uc2l_i_pass1(dk4_uc2l_t * ulptr,dk4_er_t * erp)1290 dk4uc2l_i_pass1(dk4_uc2l_t *ulptr, dk4_er_t *erp)
1291 {
1292 	const dkChar	*fn		= NULL;
1293 	const dkChar	*pth	= NULL;
1294 	dk4_dir_t		*pdir	= NULL;
1295 	int				 back	= 0;
1296 
1297 	pdir = dk4dir_open(ulptr->dname, DK4_DIR_OPEN_SORTED, erp);
1298 	if (NULL != pdir) {
1299 		pth = dk4dir_get_path(pdir);
1300 		back = 1;
1301 		do {
1302 			fn = dk4dir_next_file(pdir);
1303 			if (NULL != fn) {
1304 				if (-1 < dk4uc2l_i_find_suffix_index(fn)) {
1305 					dk4uc2l_i_process_one_file_pass1(ulptr,pth,fn,&back,erp);
1306 				}
1307 			}
1308 		} while (NULL != fn);
1309 		dk4dir_close(pdir);
1310 	}
1311 	else {
1312 		/* ERROR: Failed to open directory */
1313 		ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
1314 	}
1315 
1316 	return back;
1317 }
1318 
1319 
1320 
1321 /**	Internal function to open a new conversion structure.
1322 	@param	dn	Directory name (must be the name of an existing directory).
1323 	@param	erp	Error report, may be NULL.
1324 	@return	Valid pointer on success, NULL on error.
1325 */
1326 static
1327 dk4_uc2l_t *
dk4uc2l_i_open(const dkChar * dn,dk4_er_t * erp)1328 dk4uc2l_i_open(const dkChar *dn, dk4_er_t *erp)
1329 {
1330 	dk4_uc2l_t		*back	= NULL;
1331 
1332 	back = dk4uc2l_i_new(dn, erp);
1333 	if (NULL != back) {
1334 		if (0 == dk4uc2l_i_pass1(back, erp)) {
1335 			dk4uc2l_close(back);
1336 			back = NULL;
1337 		}
1338 #if TRACE_DEBUG
1339 		else {
1340 		}
1341 #endif
1342 	}
1343 #if TRACE_DEBUG
1344 	else {
1345 		/*	ERROR: Memory (already reported) */
1346 	}
1347 #endif
1348 
1349 	return back;
1350 }
1351 
1352 
1353 
1354 dk4_uc2l_t *
dk4uc2l_open(const dkChar * dn,dk4_er_t * erp)1355 dk4uc2l_open(const dkChar *dn, dk4_er_t *erp)
1356 {
1357 	dkChar			 fnb[DK4_MAX_PATH];
1358 	const dkChar	*shdn	= NULL;
1359 	dk4_uc2l_t		*back	= NULL;
1360 	const size_t	 szfnb	= DK4_SIZEOF(fnb,dkChar);
1361 	size_t			 i		= 0;
1362 
1363 
1364 	if (NULL != dn) {
1365 		if (0 != dk4file_is_directory(dn, erp)) {
1366 			back = dk4uc2l_i_open(dn, erp);
1367 		}
1368 	}
1369 	else {
1370 		shdn = dk4inst_get_directory(2);
1371 		for (i = 0; ((i < 3) && (NULL == dn)); i++) {
1372 			if (0 != dk4str_cpy_s(fnb, szfnb, shdn, NULL)) {
1373 				if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[i], NULL)) {
1374 					dk4path_correct_sep(fnb);
1375 					if (0 != dk4file_is_directory(fnb, NULL)) {
1376 						dn = fnb;
1377 					}
1378 				}
1379 			}
1380 		}
1381 		if (NULL != dn) {
1382 			back = dk4uc2l_i_open(dn, erp);
1383 		}
1384 		else {
1385 			/* ERROR: No directory found */
1386 			dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
1387 		}
1388 	}
1389 
1390 	return back;
1391 }
1392 
1393 
1394 
1395 void
dk4uc2l_allow_utf8(dk4_uc2l_t * ulptr,int enabled)1396 dk4uc2l_allow_utf8(dk4_uc2l_t *ulptr, int enabled)
1397 {
1398 
1399 #if	DK4_USE_ASSERT
1400 	assert(NULL != ulptr);
1401 #endif
1402 	if (NULL != ulptr) {
1403 		ulptr->utf8allowed = ((0 != enabled) ? 0x01 : 0x00);
1404 	}
1405 
1406 }
1407 
1408 
1409 
1410 void
dk4uc2l_clean_packages_and_fonts(dk4_uc2l_t * ulptr)1411 dk4uc2l_clean_packages_and_fonts(dk4_uc2l_t *ulptr)
1412 {
1413 	dk4_uc2l_pkg_t	*pptr;
1414 
1415 #if	DK4_USE_ASSERT
1416 	assert(NULL != ulptr);
1417 #endif
1418 	if (NULL != ulptr) {
1419 		ulptr->fallowed = DK4_UC2L_FONT_ENCODING_ALL;
1420 		dk4sto_it_reset(ulptr->i_pkgs);
1421 		do {
1422 			pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs);
1423 			if (NULL != pptr) {
1424 				pptr->used = 0x00;
1425 			}
1426 		} while (NULL != pptr);
1427 	}
1428 }
1429 
1430 
1431 
1432 unsigned char
dk4uc2l_retrieve_allowed_fe(dk4_uc2l_t * ulptr)1433 dk4uc2l_retrieve_allowed_fe(dk4_uc2l_t *ulptr)
1434 {
1435 	unsigned char	back	= 0x00;
1436 
1437 #if	DK4_USE_ASSERT
1438 	assert(NULL != ulptr);
1439 #endif
1440 	if (NULL != ulptr) {
1441 		back = ulptr->fallowed;
1442 	}
1443 
1444 	return back;
1445 }
1446 
1447 
1448 
1449 int
dk4uc2lat_direct(dk4_c32_t c32)1450 dk4uc2lat_direct(dk4_c32_t c32)
1451 {
1452 	int back = 0;
1453 	char c;	/* 8-bit character version of c32. */
1454 
1455 	if(128UL > dk4recode_c32_to_ul(c32)) {
1456 		c = (char)c32;
1457 		switch(c) {
1458 			case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1459 			case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
1460 			case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
1461 			case 's': case 't': case 'u': case 'v': case 'w': case 'x':
1462 			case 'y': case 'z': case 'A': case 'B': case 'C': case 'D':
1463 			case 'E': case 'F': case 'G': case 'H': case 'I': case 'J':
1464 			case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
1465 			case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V':
1466 			case 'W': case 'X': case 'Y': case 'Z': case '0': case '1':
1467 			case '2': case '3': case '4': case '5': case '6': case '7':
1468 			case '8': case '9': case ',': case '.': case ':': case ';':
1469 			case '+': case '-': case '?': case '!': case '|': case '@':
1470 			case '(': case ')': case '/': case '=': case ' ':
1471 			{
1472 				back = 1;
1473 			}
1474 			break;
1475 		}
1476 	}
1477 	return back;
1478 }
1479 
1480 
1481 
1482 int
dk4uc2l_i_keyword_index(const char * pkey)1483 dk4uc2l_i_keyword_index(const char *pkey)
1484 {
1485 	return (dk4str8_abbr_index(dk4uc2l_keywords, '$', pkey, 0));
1486 }
1487 
1488 
1489 
1490 
1491 unsigned char
dk4uc2l_font_encoding_from_name(const char * pname)1492 dk4uc2l_font_encoding_from_name(const char *pname)
1493 {
1494 	unsigned char	 back = 0x00;
1495 	switch (dk4str8_array_index(dk4uc2l_font_encodings, pname, 0)) {
1496 		case 0: {
1497 			back = DK4_UC2L_FONT_ENCODING_OT1;
1498 		} break;
1499 		case 1: {
1500 			back = DK4_UC2L_FONT_ENCODING_T1;
1501 		} break;
1502 		case 2: {
1503 			back = DK4_UC2L_FONT_ENCODING_T4;
1504 		} break;
1505 		case 3: {
1506 			back = DK4_UC2L_FONT_ENCODING_T5;
1507 		} break;
1508 	}
1509 	return back;
1510 }
1511 
1512 
1513 
1514 dk4_uc2l_pkg_t *
dk4uc2l_i_create_pkg(dk4_sto_t * s_pkgs,const char * pname)1515 dk4uc2l_i_create_pkg(
1516 	dk4_sto_t	*s_pkgs,
1517 	const char	*pname
1518 )
1519 {
1520 	dk4_uc2l_pkg_t	*back	= NULL;
1521 	back = dk4uc2l_i_open_pkg(pname, NULL);
1522 	if (NULL != back) {
1523 		if (0 == dk4sto_add(s_pkgs, back, NULL)) {
1524 			dk4uc2l_i_close_pkg(back);
1525 			back = NULL;
1526 		}
1527 	}
1528 	return back;
1529 }
1530 
1531 
1532 
1533 /**	Handler to process a line during pass 1.
1534 	@param	obj		Object to use and modify during processing.
1535 	@param	line	Current text line to process.
1536 	@param	lineno	Current line number.
1537 	@param	erp		Error report, may be NULL.
1538 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable
1539 	errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort.
1540 */
1541 static
1542 int
dk4uc2l_handler_pass2(void * obj,char * line,dk4_um_t lineno,dk4_er_t * erp)1543 dk4uc2l_handler_pass2(
1544 	void		*obj,
1545 	char		*line,
1546 	dk4_um_t	 lineno,
1547 	dk4_er_t	*erp
1548 )
1549 {
1550 	dk4_er_t			 er;
1551 	char				*pkgn[16];
1552 	handler_object_t	*lho	= NULL;
1553 	const char			*pe		= NULL;
1554 	char				*p1		= NULL;
1555 	char				*p2		= NULL;
1556 	char				*p3		= NULL;
1557 	char				*p4		= NULL;
1558 	dk4_uc2l_range_t	*rptr	= NULL;
1559 	dk4_uc2l_pkg_t		*pptr	= NULL;
1560 	size_t				 ind	= 0;
1561 	size_t				 numpkg	= 0;
1562 	size_t				 i		= 0;
1563 	unsigned long		 ul		= 0UL;
1564 	dk4_c32_t			 c32	= (dk4_c32_t)0UL;
1565 	int					 back	= DK4_TSP_RES_OK;
1566 	int					 res	= 0;
1567 	int					 adding	= 0;
1568 	unsigned char		 fex	= 0;
1569 	unsigned char		 feval	= 0;
1570 
1571 #if	TRACE_DEBUG
1572 	dk4str8_delnl(line);
1573 
1574 #endif
1575 
1576 	/*	Line handler object
1577 	*/
1578 	lho = (handler_object_t *)obj;
1579 
1580 	/*	Find start of line, ignore empty lines and comments
1581 	*/
1582 	p1 = dk4str8_start(line, NULL);
1583 	if (NULL == p1) {
1584 		goto finished;
1585 	}
1586 	if ('#' == *p1) {
1587 		goto finished;
1588 	}
1589 
1590 	/*	Retrieve character number
1591 	*/
1592 	p2 = dk4str8_next(p1, NULL);
1593 	res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp);
1594 	if (0 == res) {
1595 		/*	WARNING: Syntax, no number.
1596 			Already reported in pass 1.
1597 		*/
1598 		lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1599 		goto finished;
1600 	}
1601 	c32 = (dk4_c32_t)ul;
1602 
1603 	/*	Find and check range structure, attempt cached range pointer first
1604 	*/
1605 	if (NULL != lho->rpc) {
1606 		if ((lho->rpc->start <= c32) && (c32 <= lho->rpc->end)) {
1607 			rptr = lho->rpc;
1608 		}
1609 	}
1610 	if (NULL == rptr) {
1611 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(lho->ulptr->i_ranges,&c32,1);
1612 	}
1613 	if (NULL == rptr) {
1614 		/*	ERROR: No range found.
1615 			Already reported in pass 1.
1616 		*/
1617 		lho->ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1618 		back = DK4_TSP_RES_FATAL;
1619 		goto finished;
1620 	}
1621 	if (0 != dk4str_cmp(lho->file->fn, rptr->file->fn)) {
1622 		/*	ERROR: Not owned by current file.
1623 			Already reported in pass 1.
1624 		*/
1625 
1626 		lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1627 		goto finished;
1628 	}
1629 
1630 	/*	Initialize range structure (allocate memory) if not yet done
1631 	*/
1632 	if (0x00 == rptr->ia) {
1633 		if (0 == dk4uc2l_i_init_range(rptr, erp)) {
1634 
1635 			lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1636 			back = DK4_TSP_RES_FATAL;
1637 			goto finished;
1638 		}
1639 		rptr->ia = 0x01;
1640 	}
1641 	else {
1642 	}
1643 
1644 	/*	Find index
1645 	*/
1646 	ind = (size_t)(c32 - rptr->start);
1647 
1648 	/*	Check whether character already defined
1649 	*/
1650 	if (NULL != rptr->lno) {
1651 		if ((dk4_um_t)0UL != (rptr->lno)[ind]) {
1652 			/*	ERROR: Redefinition.
1653 				Already reported in pass 1.
1654 			*/
1655 
1656 			lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1657 			goto finished;
1658 		}
1659 		else {
1660 			(rptr->lno)[ind] = lineno;
1661 		}
1662 	}
1663 
1664 	/*	Traverse all strings in line
1665 	*/
1666 	p1 = p2;
1667 	while (NULL != p1) {
1668 		p2 = dk4str8_next(p1, NULL);
1669 		p3 = dk4str8_chr(p1, '=');
1670 		if (NULL != p3) {
1671 			*(p3++) = '\0';
1672 			p3 = dk4str8_start(p3, NULL);
1673 			if (NULL != p3) {
1674 
1675 				res = dk4uc2l_i_keyword_index(p1);
1676 				switch (res) {
1677 					case 0 : {
1678 						if (NULL != rptr->both) {
1679 							if (NULL == (rptr->both)[ind]) {
1680 								(rptr->both)[ind] = dk4str8_dup(p3, erp);
1681 								if (NULL == (rptr->both)[ind]) {
1682 
1683 									lho->ulptr->had_error |=
1684 									DK4_UC2L_ERROR_MEMORY;
1685 								}
1686 							}
1687 							else {
1688 								/*	ERROR: Already defined.
1689 									Bug: Should not happen.
1690 								*/
1691 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1692 							}
1693 						}
1694 						else {
1695 							/*	ERROR: Memory.
1696 								Already reported during range initialization.
1697 							*/
1698 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1699 						}
1700 					} break;
1701 					case 1 : {
1702 						if (NULL != rptr->text) {
1703 							if (NULL == (rptr->text)[ind]) {
1704 								(rptr->text)[ind] = dk4str8_dup(p3, erp);
1705 								if (NULL == (rptr->text)[ind]) {
1706 
1707 									lho->ulptr->had_error |=
1708 									DK4_UC2L_ERROR_MEMORY;
1709 								}
1710 							}
1711 							else {
1712 								/*	ERROR: Already defined.
1713 									Bug: Should not happen.
1714 								*/
1715 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1716 							}
1717 						}
1718 						else {
1719 							/*	ERROR: Memory
1720 								Already reported during range initialization.
1721 							*/
1722 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1723 						}
1724 					} break;
1725 					case 2 : {
1726 						if (NULL != rptr->math) {
1727 							if (NULL == (rptr->math)[ind]) {
1728 								(rptr->math)[ind] = dk4str8_dup(p3, erp);
1729 								if (NULL == (rptr->math)[ind]) {
1730 
1731 									lho->ulptr->had_error |=
1732 									DK4_UC2L_ERROR_MEMORY;
1733 								}
1734 							}
1735 							else {
1736 								/*	ERROR: Already defined.
1737 									Bug: Should not happen.
1738 								*/
1739 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1740 							}
1741 						}
1742 						else {
1743 							/*	ERROR: Memory.
1744 								Already reported during range initialization.
1745 							*/
1746 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1747 						}
1748 					} break;
1749 					case 3 : {
1750 						if (NULL != rptr->fenc) {
1751 							adding = 1;
1752 							feval  = 0x00;
1753 							if ('!' == *p3) {
1754 								adding = 0;
1755 								p3++;
1756 								feval = DK4_UC2L_FONT_ENCODING_ALL;
1757 							}
1758 							while (NULL != p3) {
1759 								p4 = dk4str8_chr(p3, ',');
1760 								if (NULL != p4) {
1761 									*(p4++) = '\0';
1762 								}
1763 								fex = dk4uc2l_font_encoding_from_name(p3);
1764 								if (0x00 != fex) {
1765 									if (0 != adding) {
1766 										feval |= fex;
1767 									}
1768 									else {
1769 										feval = (unsigned char)(feval & (~(fex)));
1770 									}
1771 								}
1772 								else {
1773 									/* ERROR: Illegal encoding name */
1774 									dk4error_set_simple_error_code(
1775 										erp, DK4_E_SYNTAX
1776 									);
1777 									lho->ulptr->had_error |=
1778 									DK4_UC2L_ERROR_SYNTAX;
1779 								}
1780 								p3 = p4;
1781 							}
1782 							(rptr->fenc)[ind] = feval;
1783 						}
1784 						else {
1785 							/*	ERROR: Memory.
1786 								Already reported during range initialization.
1787 							*/
1788 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1789 						}
1790 					} break;
1791 					case 4 : {
1792 						if (NULL != rptr->pkgs) {
1793 							if (NULL == (rptr->pkgs)[ind]) {
1794 								dk4error_init(&er);
1795 								numpkg = dk4str8_tokenize(
1796 									pkgn, 16, p3, ",", &er
1797 								);
1798 								if (0 < numpkg) {
1799 									(rptr->pkgs)[ind] =
1800 									dk4mem_new(dk4_uc2l_pkg_p,(numpkg+1),erp);
1801 									if (NULL != (rptr->pkgs)[ind]) {
1802 										for (i = 0; i <= numpkg; i++) {
1803 											((rptr->pkgs)[ind])[i] = NULL;
1804 										}
1805 										for (i = 0; i < numpkg; i++) {
1806 											pptr =
1807 											(dk4_uc2l_pkg_t *)dk4sto_it_find_like(
1808 												lho->ulptr->i_pkgs, pkgn[i], 1
1809 											);
1810 											if (NULL != pptr) {
1811 												((rptr->pkgs)[ind])[i] = pptr;
1812 											}
1813 											else {
1814 												pptr = dk4uc2l_i_create_pkg(
1815 													lho->ulptr->s_pkgs, pkgn[i]
1816 												);
1817 												if (NULL != pptr) {
1818 													((rptr->pkgs)[ind])[i] =
1819 													pptr;
1820 												}
1821 												else {
1822 													dk4error_set_simple_error_code(
1823 														erp,
1824 														DK4_E_MEMORY_ALLOCATION_FAILED
1825 													);
1826 													lho->ulptr->had_error |=
1827 													DK4_UC2L_ERROR_MEMORY;
1828 												}
1829 											}
1830 										}
1831 									}
1832 									else {
1833 										dk4error_set_simple_error_code(
1834 											erp,
1835 											DK4_E_MEMORY_ALLOCATION_FAILED
1836 										);
1837 										lho->ulptr->had_error |=
1838 										DK4_UC2L_ERROR_MEMORY;
1839 									}
1840 								}
1841 								else {
1842 									/* ERROR: Syntax, empty list */
1843 									dk4error_set_simple_error_code(
1844 										erp, DK4_E_SYNTAX
1845 									);
1846 									lho->ulptr->had_error |=
1847 									DK4_UC2L_ERROR_SYNTAX;
1848 								}
1849 							}
1850 							else {
1851 								/*	ERROR: Already defined.
1852 									Bug: Should not happen.
1853 								*/
1854 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1855 							}
1856 						}
1857 						else {
1858 							/*	ERROR: Memory.
1859 								Already reported during range initalization.
1860 							*/
1861 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1862 						}
1863 					} break;
1864 					default : {
1865 						/* ERROR: Illegal key name */
1866 						dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1867 						lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1868 					} break;
1869 				}
1870 				p1 = p2;
1871 			}
1872 			else {
1873 				/* ERROR: Syntax, not a key=value */
1874 				dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1875 				lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1876 				p1 = NULL;
1877 			}
1878 		}
1879 		else {
1880 			/* ERROR: Syntax, not a key=value */
1881 			dk4error_set_simple_error_code(erp, DK4_E_SYNTAX);
1882 			lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1883 			p1 = NULL;
1884 		}
1885 	}
1886 
1887 	finished:
1888 
1889 	return back;
1890 }
1891 
1892 
1893 
1894 /**	Load data file.
1895 	@param	ulptr	Conversion structure.
1896 	@param	fptr	File structure to load.
1897 	@param	erp		Error report, may be NULL.
1898 */
1899 static
1900 void
dk4uc2l_load_data_file(dk4_uc2l_t * ulptr,dk4_uc2l_file_t * fptr,dk4_er_t * erp)1901 dk4uc2l_load_data_file(
1902 	dk4_uc2l_t		*ulptr,
1903 	dk4_uc2l_file_t	*fptr,
1904 	dk4_er_t		*erp
1905 )
1906 {
1907 	dkChar				 fnb[DK4_MAX_PATH];
1908 	char				 lnb[256];
1909 	handler_object_t	 ho;
1910 	dk4_tsp08_t			 tsp08;
1911 	dk4_stream_t		*rstrm			= NULL;
1912 	size_t				 fnbsz			= DK4_SIZEOF(fnb,dkChar);
1913 	size_t				 szlnb			= sizeof(lnb);
1914 	int					 res;
1915 	int					 cc;
1916 	char				 c;
1917 
1918 
1919 
1920 	/*	Initialize handler object
1921 	*/
1922 	ho.ulptr = ulptr;
1923 	ho.s_ra  = NULL;
1924 	ho.i_ra  = NULL;
1925 	ho.file  = fptr;
1926 	ho.rpc   = NULL;
1927 
1928 	/*	Save source file name and line number
1929 	*/
1930 
1931 	/*	Each file should be loaded only once
1932 	*/
1933 	if (0x00 != fptr->loaded) {
1934 		goto finished;
1935 	}
1936 	fptr->loaded = 0x01;
1937 
1938 	/*	Construct full path name
1939 	*/
1940 	if (0 == dk4str_cpy_s(fnb, fnbsz, ulptr->dname, erp)) {
1941 		/* ERROR: Directory name too long */
1942 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1943 		goto finished;
1944 	}
1945 	if (0 == dk4str_cat_s(fnb, fnbsz, dk4uc2l_kwnl[3], erp)) {
1946 		/* ERROR: Directory name too long */
1947 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1948 		goto finished;
1949 	}
1950 	if (0 == dk4str_cat_s(fnb, fnbsz, fptr->fn, erp)) {
1951 		/* ERROR: Directory name too long */
1952 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1953 		goto finished;
1954 	}
1955 	dk4path_correct_sep(fnb);
1956 
1957 	/*	Open reader stream
1958 	*/
1959 	rstrm = dk4stream_open_file_reader(fnb, erp);
1960 	if (NULL == rstrm) {
1961 		/* ERROR: Failed to read file */
1962 		ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
1963 		goto finished;
1964 	}
1965 
1966 	/*	Initialize text processing
1967 	*/
1968 	res = dk4tsp08_setup_line(
1969 		&tsp08, (void *)(&ho), dk4uc2l_handler_pass2, lnb, szlnb,
1970 		DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, erp
1971 	);
1972 	if (0 == res) {
1973 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1974 		/* ERROR: Memory */
1975 		goto finished;
1976 	}
1977 
1978 	/*	Process contents
1979 	*/
1980 	do {
1981 		cc = 0;
1982 		res = dk4stream_c8_read_byte(&c, rstrm, erp);
1983 		if (0 < res) {
1984 			cc = 1;
1985 			res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c);
1986 			switch (res) {
1987 				case DK4_TSP_RES_ERROR : {
1988 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1989 				} break;
1990 				case DK4_TSP_RES_FATAL : {
1991 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1992 					goto finished;
1993 				} break;
1994 			}
1995 		}
1996 	} while (0 < cc);
1997 
1998 	/*	Finish text processing
1999 	*/
2000 	res = dk4tsp08_finish(&tsp08);
2001 	switch (res) {
2002 		case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: {
2003 			ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
2004 		} break;
2005 	}
2006 
2007 	/*	Clean up
2008 	*/
2009 	finished:
2010 	if (NULL != rstrm) {
2011 		dk4stream_close(rstrm, NULL);
2012 	}
2013 
2014 }
2015 
2016 
2017 
2018 const char *
dk4uc2l_find(dk4_uc2l_t * ulptr,dk4_c32_t c,int mm,dk4_er_t * erp)2019 dk4uc2l_find(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_er_t *erp)
2020 {
2021 	dk4_uc2l_range_t	 *rptr;
2022 	dk4_uc2l_pkg_t		**pkgpp;
2023 	dk4_uc2l_file_t		 *fptr;
2024 	const char			 *back	= NULL;
2025 	size_t				  ind;
2026 	size_t				  blgt;
2027 	int					  res;
2028 
2029 #if	DK4_USE_ASSERT
2030 	assert(NULL != ulptr);
2031 #endif
2032 	/*	Check ulptr usability
2033 	*/
2034 	if (NULL == ulptr) {
2035 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2036 		goto finished;
2037 	}
2038 
2039 	/*	Attempt direct output
2040 	*/
2041 	if (0 != dk4uc2lat_direct(c)) {
2042 		ulptr->buf[0] = (char)c;
2043 		ulptr->buf[1] = '\0';
2044 		back = &(ulptr->buf[0]);
2045 		goto finished;
2046 	}
2047 
2048 	/*	Attempt data loaded from files
2049 	*/
2050 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(ulptr->i_ranges, &c, 1);
2051 	if (NULL != rptr) {
2052 		fptr = rptr->file;
2053 		if (0x00 == fptr->loaded) {
2054 			dk4uc2l_load_data_file(ulptr, fptr, erp);
2055 		}
2056 		ind = (size_t)(c - rptr->start);
2057 		if (0 != mm) {
2058 			if (NULL != rptr->math) {
2059 				back = (rptr->math)[ind];
2060 			}
2061 		}
2062 		else {
2063 			if (NULL != rptr->text) {
2064 				back = (rptr->text)[ind];
2065 			}
2066 		}
2067 		if (NULL == back) {
2068 			if (NULL != rptr->both) {
2069 				back = (rptr->both)[ind];
2070 			}
2071 		}
2072 		if (NULL != back) {
2073 			if (NULL != rptr->pkgs) {
2074 				pkgpp = (rptr->pkgs)[ind];
2075 				if (NULL != pkgpp) {
2076 					while (NULL != *pkgpp) {
2077 						(*(pkgpp++))->used = 0x01;
2078 					}
2079 				}
2080 			}
2081 			if (NULL != rptr->fenc) {
2082 				ulptr->fallowed &= (rptr->fenc)[ind];
2083 			}
2084 			goto finished;
2085 		}
2086 	}
2087 
2088 	/*	Attempt to use UTF-8 encoded data or ASCII data directly
2089 	*/
2090 
2091 	if (0 == mm) {
2092 		if (0x00 != ulptr->utf8allowed) {
2093 			blgt = 15;
2094 			res = dk4utf8_encode(
2095 				(unsigned char *)(&(ulptr->buf[0])), &blgt, c, erp
2096 			);
2097 			if (0 != res) {
2098 				ulptr->buf[blgt] = '\0';
2099 				back = &(ulptr->buf[0]);
2100 			}
2101 		}
2102 		else {
2103 			if (dkC32(0x00000100) > c) {
2104 				ulptr->buf[0] = (char)c;
2105 				ulptr->buf[1] = '\0';
2106 				back = &(ulptr->buf[0]);
2107 			}
2108 		}
2109 	}
2110 
2111 	finished:
2112 
2113 
2114 
2115 
2116 	return back;
2117 }
2118 
2119 
2120 
2121 static
2122 int
dk4uc2l_i_encoding(unsigned char enclist,unsigned char oneenc)2123 dk4uc2l_i_encoding(
2124 	unsigned char	enclist,
2125 	unsigned char	oneenc
2126 )
2127 {
2128 	int		 back	= 0;
2129 	if (0x00 != (enclist & ((unsigned char)oneenc))) {
2130 		back = 1;
2131 	}
2132 	return back;
2133 }
2134 
2135 
2136 
2137 void
dk4uc2l_recommendations(dk4_uc2l_t * ulptr,dk4_stream_t * wstrm,dk4_er_t * erp)2138 dk4uc2l_recommendations(dk4_uc2l_t *ulptr, dk4_stream_t *wstrm, dk4_er_t *erp)
2139 {
2140 	dk4_uc2l_pkg_t		*pptr;
2141 
2142 #if	DK4_USE_ASSERT
2143 	assert(NULL != wstrm);
2144 	assert(NULL != ulptr);
2145 #endif
2146 	if ((NULL != ulptr) && (NULL != wstrm)) {
2147 		dk4stream_write_char_string(
2148 			wstrm, dk4uc2l_kw8[0], erp
2149 		);
2150 		if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T1)) {
2151 			dk4stream_write_char_string(
2152 				wstrm, dk4uc2l_kw8[3], erp
2153 			);
2154 		}
2155 		if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_OT1)) {
2156 			dk4stream_write_char_string(
2157 				wstrm, dk4uc2l_kw8[2], erp
2158 			);
2159 		}
2160 		if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T4)) {
2161 			dk4stream_write_char_string(
2162 				wstrm, dk4uc2l_kw8[4], erp
2163 			);
2164 		}
2165 		if (dk4uc2l_i_encoding(ulptr->fallowed,DK4_UC2L_FONT_ENCODING_T5)) {
2166 			dk4stream_write_char_string(
2167 				wstrm, dk4uc2l_kw8[5], erp
2168 			);
2169 		}
2170 		dk4stream_write_byte(wstrm, '\n', erp);
2171 		dk4sto_it_reset(ulptr->i_pkgs);
2172 		do {
2173 			pptr = (dk4_uc2l_pkg_t *)dk4sto_it_next(ulptr->i_pkgs);
2174 			if (NULL != pptr) {
2175 				if (0x00 != pptr->used) {
2176 					dk4stream_write_char_string(
2177 						wstrm, dk4uc2l_kw8[1], erp
2178 					);
2179 					dk4stream_write_char_string(
2180 						wstrm, pptr->pn, erp
2181 					);
2182 					dk4stream_write_byte(wstrm, '\n', erp);
2183 				}
2184 			}
2185 		} while (NULL != pptr);
2186 	}
2187 
2188 }
2189 
2190 
2191 
2192 int
dk4uc2l_retrieve_errors(dk4_uc2l_t * ulptr)2193 dk4uc2l_retrieve_errors(dk4_uc2l_t *ulptr)
2194 {
2195 	int		 back	= 0;
2196 
2197 #if	DK4_USE_ASSERT
2198 	assert(NULL != ulptr);
2199 #endif
2200 	if (NULL != ulptr) {
2201 		back = ulptr->had_error;
2202 	}
2203 
2204 	return back;
2205 }
2206 
2207 
2208 
2209 void
dk4uc2l_reset_errors(dk4_uc2l_t * ulptr)2210 dk4uc2l_reset_errors(dk4_uc2l_t *ulptr)
2211 {
2212 #if	DK4_USE_ASSERT
2213 	assert(NULL != ulptr);
2214 #endif
2215 	if (NULL != ulptr) {
2216 		ulptr->had_error = 0;
2217 	}
2218 }
2219 
2220 
2221 
2222 /* ##### untested */
2223 static
2224 void
dk4uc2l_putc32(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,dk4_c32_t c32,int * pmm,int * pback,dk4_er_t * erp)2225 dk4uc2l_putc32(
2226 	dk4_stream_t		*wstrm,
2227 	dk4_uc2l_t			*ulptr,
2228 	dk4_c32_t			 c32,
2229 	int					*pmm,
2230 	int					*pback,
2231 	dk4_er_t			*erp
2232 )
2233 {
2234 	dk4_er_t	 er;
2235 	const char	*le		= NULL;
2236 
2237 #if	DK4_USE_ASSERT
2238 	assert(NULL != wstrm);
2239 	assert(NULL != ulptr);
2240 #endif
2241 	dk4error_init(&er);
2242 	le = dk4uc2l_find(ulptr, c32, 0, &er);
2243 	if (NULL != le) {
2244 		if (0 != *pmm) {
2245 			if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2246 				*pback = 0;
2247 			}
2248 			*pmm = 0;
2249 		}
2250 		if (0 == dk4stream_write_char_string(wstrm, le, erp)) {
2251 			*pback = 0;
2252 		}
2253 	}
2254 	else {
2255 		le = dk4uc2l_find(ulptr, c32, 1, &er);
2256 		if (NULL != le) {
2257 			if (0 == *pmm) {
2258 				if (0 == dk4stream_write_char_string(wstrm,dk4uc2l_mm[0],erp)) {
2259 					*pback = 0;
2260 				}
2261 				*pmm = 1;
2262 			}
2263 			if (0 == dk4stream_write_char_string(wstrm, le, erp)) {
2264 				*pback = 0;
2265 			}
2266 		}
2267 		else {
2268 			*pback = 0;
2269 			dk4error_set_simple_error_code(erp, DK4_E_NOT_FOUND);
2270 		}
2271 	}
2272 
2273 }
2274 
2275 
2276 
2277 /* ##### untested */
2278 int
dk4uc2l_string_c32(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dk4_c32_t * str,dk4_er_t * erp)2279 dk4uc2l_string_c32(
2280 	dk4_stream_t	*wstrm,
2281 	dk4_uc2l_t		*ulptr,
2282 	const dk4_c32_t	*str,
2283 	dk4_er_t		*erp
2284 )
2285 {
2286 	int			 back	= 0;
2287 	int			 mm		= 0;
2288 
2289 
2290 #if	DK4_USE_ASSERT
2291 	assert(NULL != wstrm);
2292 	assert(NULL != ulptr);
2293 	assert(NULL != str);
2294 #endif
2295 	/*	Check arguments
2296 	*/
2297 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2298 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2299 		goto finished;
2300 	}
2301 
2302 	/*	Process all characters from string
2303 	*/
2304 	back = 1;
2305 	while (dkC32(0) != *str) {
2306 		dk4uc2l_putc32(wstrm, ulptr, *(str++), &mm, &back, erp);
2307 	}
2308 
2309 	/*	Finalize math mode if necessary
2310 	*/
2311 	if (0 != mm) {
2312 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2313 			back = 0;
2314 		}
2315 	}
2316 
2317 	finished:
2318 
2319 	return back;
2320 }
2321 
2322 
2323 
2324 /* ##### untested */
2325 int
dk4uc2l_string_c16(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dk4_c16_t * str,dk4_er_t * erp)2326 dk4uc2l_string_c16(
2327 	dk4_stream_t	*wstrm,
2328 	dk4_uc2l_t		*ulptr,
2329 	const dk4_c16_t	*str,
2330 	dk4_er_t		*erp
2331 )
2332 {
2333 	dk4_utf16_decoder_t		 dec;
2334 	dk4_c32_t				 c32;
2335 	int						 mm		= 0;
2336 	int						 back	= 0;
2337 	int						 err	= 0;
2338 
2339 #if	DK4_USE_ASSERT
2340 	assert(NULL != wstrm);
2341 	assert(NULL != ulptr);
2342 	assert(NULL != str);
2343 #endif
2344 	/*	Check arguments
2345 	*/
2346 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2347 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2348 		goto finished;
2349 	}
2350 
2351 	back = 1;
2352 	dk4utf16_init(&dec);
2353 	while ((dkC16(0) != *str) && (0 == err)) {
2354 		switch (dk4utf16_add(&dec, *(str++))) {
2355 			case DK4_EDSTM_FINISHED : {
2356 				c32 = dk4utf16_get(&dec);
2357 				dk4utf16_init(&dec);
2358 				dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp);
2359 
2360 			} break;
2361 			case DK4_EDSTM_ERROR : {
2362 				err = 1;
2363 				dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED);
2364 				back = 0;
2365 			} break;
2366 		}
2367 	}
2368 	if (0 == err) {
2369 		if (0 == dk4utf16_is_empty(&dec)) {
2370 			dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED);
2371 			back = 0;
2372 		}
2373 	}
2374 	if (0 != mm) {
2375 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2376 			back = 0;
2377 		}
2378 	}
2379 
2380 	finished:
2381 
2382 	return back;
2383 }
2384 
2385 
2386 
2387 /* ##### untested */
2388 int
dk4uc2l_string_utf8(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_er_t * erp)2389 dk4uc2l_string_utf8(
2390 	dk4_stream_t	*wstrm,
2391 	dk4_uc2l_t		*ulptr,
2392 	const char		*str,
2393 	dk4_er_t		*erp
2394 )
2395 {
2396 	dk4_utf8_decoder_t	 dec;
2397 	dk4_c32_t			 c32;
2398 	int					 back	= 0;
2399 	int					 mm		= 0;
2400 	int					 err	= 0;
2401 
2402 #if	DK4_USE_ASSERT
2403 	assert(NULL != wstrm);
2404 	assert(NULL != ulptr);
2405 	assert(NULL != str);
2406 #endif
2407 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2408 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2409 		goto finished;
2410 	}
2411 
2412 	back = 1;
2413 	dk4utf8_init(&dec);
2414 	while(('\0' != *str) && (0 == err)) {
2415 		switch (dk4utf8_add(&dec, (unsigned char)(*(str++)))) {
2416 			case DK4_EDSTM_FINISHED : {
2417 				c32 = dk4utf8_get(&dec);
2418 				dk4utf8_init(&dec);
2419 				dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp);
2420 			} break;
2421 			case DK4_EDSTM_ERROR : {
2422 				err = 1;
2423 				dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED);
2424 				back = 0;
2425 			} break;
2426 		}
2427 	}
2428 	if (0 == err) {
2429 		if (0 == dk4utf8_is_empty(&dec)) {
2430 			dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED);
2431 			back = 0;
2432 		}
2433 	}
2434 	if (0 != mm) {
2435 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2436 			back = 0;
2437 		}
2438 	}
2439 
2440 	finished:
2441 
2442 	return back;
2443 }
2444 
2445 
2446 
2447 /* ##### untested */
2448 int
dk4uc2l_string_ansi(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_er_t * erp)2449 dk4uc2l_string_ansi(
2450 	dk4_stream_t	*wstrm,
2451 	dk4_uc2l_t		*ulptr,
2452 	const char		*str,
2453 	dk4_er_t		*erp
2454 )
2455 {
2456 	dk4_c32_t			 c32;
2457 	int					 back	= 0;
2458 	int					 mm		= 0;
2459 
2460 #if	DK4_USE_ASSERT
2461 	assert(NULL != wstrm);
2462 	assert(NULL != ulptr);
2463 	assert(NULL != str);
2464 #endif
2465 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2466 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2467 		goto finished;
2468 	}
2469 	back = 1;
2470 	while ('\0' != *str) {
2471 		if (0 != dk4ansi_decode(&c32, (unsigned char)(*(str++)))) {
2472 			dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp);
2473 		}
2474 		else {
2475 			dk4error_set_simple_error_code(erp, DK4_E_DECODING_FAILED);
2476 			back = 0;
2477 		}
2478 	}
2479 	if (0 != mm) {
2480 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2481 			back = 0;
2482 		}
2483 	}
2484 
2485 	finished:
2486 
2487 	return back;
2488 }
2489 
2490 
2491 
2492 /* ##### untested */
2493 int
dk4uc2l_string_ascii(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_er_t * erp)2494 dk4uc2l_string_ascii(
2495 	dk4_stream_t	*wstrm,
2496 	dk4_uc2l_t		*ulptr,
2497 	const char		*str,
2498 	dk4_er_t		*erp
2499 )
2500 {
2501 	dk4_c32_t			 c32;
2502 	int					 back	= 0;
2503 	int					 mm		= 0;
2504 
2505 #if	DK4_USE_ASSERT
2506 	assert(NULL != wstrm);
2507 	assert(NULL != ulptr);
2508 	assert(NULL != str);
2509 #endif
2510 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2511 		dk4error_set_simple_error_code(erp, DK4_E_INVALID_ARGUMENTS);
2512 		goto finished;
2513 	}
2514 
2515 	back = 1;
2516 	while ('\0' != *str) {
2517 		c32 = (dk4_c32_t)((unsigned char)(*(str++)));
2518 		dk4uc2l_putc32(wstrm, ulptr, c32, &mm, &back, erp);
2519 	}
2520 	if (0 != mm) {
2521 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], erp)) {
2522 			back = 0;
2523 		}
2524 	}
2525 
2526 	finished:
2527 
2528 	return back;
2529 }
2530 
2531 
2532 
2533 /* ##### untested */
2534 int
dk4uc2l_string_c8(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,int ie,dk4_er_t * erp)2535 dk4uc2l_string_c8(
2536 	dk4_stream_t	*wstrm,
2537 	dk4_uc2l_t		*ulptr,
2538 	const char		*str,
2539 	int				 ie,
2540 	dk4_er_t		*erp
2541 )
2542 {
2543 #if	DK4_USE_ASSERT
2544 	assert(NULL != wstrm);
2545 	assert(NULL != ulptr);
2546 	assert(NULL != str);
2547 #endif
2548 	switch (ie) {
2549 		case DK4_ENCODING_UTF8 : {
2550 			return (dk4uc2l_string_utf8(wstrm, ulptr, str, erp));
2551 		} break;
2552 		case DK4_ENCODING_WIN1252 : {
2553 			return (dk4uc2l_string_ansi(wstrm, ulptr, str, erp));
2554 		} break;
2555 		default : {
2556 			return (dk4uc2l_string_ascii(wstrm, ulptr, str, erp));
2557 		} break;
2558 	}
2559 }
2560 
2561 
2562 
2563 /* ##### untested */
2564 int
dk4uc2l_string_dk(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dkChar * str,int ie,dk4_er_t * erp)2565 dk4uc2l_string_dk(
2566 	dk4_stream_t	*wstrm,
2567 	dk4_uc2l_t		*ulptr,
2568 	const dkChar	*str,
2569 #if 1 == DK4_CHAR_SIZE
2570 	int				 ie,
2571 #else
2572 	int				 DK4_ARG_UNUSED(ie),
2573 #endif
2574 	dk4_er_t		*erp
2575 )
2576 {
2577 #if DK4_CHAR_SIZE > 1
2578 	DK4_UNUSED_ARG(ie)
2579 #endif
2580 #if	DK4_USE_ASSERT
2581 	assert(NULL != wstrm);
2582 	assert(NULL != ulptr);
2583 	assert(NULL != str);
2584 #endif
2585 #if	DK4_CHAR_SIZE > 1
2586 #if	DK4_CHAR_SIZE > 2
2587 
2588 	return (dk4uc2l_string_c32(wstrm, ulptr, str, erp));
2589 #else
2590 
2591 	return (dk4uc2l_string_c16(wstrm, ulptr, str, erp));
2592 #endif
2593 #else
2594 
2595 	return (dk4uc2l_string_c8(wstrm, ulptr, str, ie, erp));
2596 #endif
2597 }
2598 
2599 
2600 
2601 int
dk4uc2l_string_encoded(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const void * str,int ie,dk4_er_t * erp)2602 dk4uc2l_string_encoded(
2603 	dk4_stream_t	*wstrm,
2604 	dk4_uc2l_t		*ulptr,
2605 	const void		*str,
2606 	int				 ie,
2607 	dk4_er_t		*erp
2608 )
2609 {
2610 	int		back	= 0;
2611 #if DK4_CHAR_SIZE > 1
2612 	DK4_UNUSED_ARG(ie)
2613 #endif
2614 #if	DK4_USE_ASSERT
2615 	assert(NULL != wstrm);
2616 	assert(NULL != ulptr);
2617 	assert(NULL != str);
2618 #endif
2619 	switch (ie) {
2620 		case DK4_ENCODING_32 : {
2621 			back = dk4uc2l_string_c32(wstrm, ulptr, str, erp);
2622 		} break;
2623 		case DK4_ENCODING_UTF16 : {
2624 			back = dk4uc2l_string_c16(wstrm, ulptr, str, erp);
2625 		} break;
2626 		default : {
2627 			back = dk4uc2l_string_c8(wstrm, ulptr, str, ie, erp);
2628 		} break;
2629 	}
2630 	return back;
2631 }
2632 
2633 
2634 /* vim: set ai sw=4 ts=4 : */
2635 
2636