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: dk4uc2la.ctr
12 */
13 
14 /**	@file dk4uc2la.c The dk4uc2la 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 <libdk4lata/dk4uc2la.h>
32 #include <libdk4base/dk4mem.h>
33 #include <libdk4app/dk4mema.h>
34 #include <libdk4base/dk4str8.h>
35 #include <libdk4base/dk4strd.h>
36 #include <libdk4c/dk4utf8.h>
37 #include <libdk4c/dk4utf16.h>
38 #include <libdk4c/dk4ansi.h>
39 #include <libdk4ma/dk4maasz.h>
40 #include <libdk4c/dk4filed.h>
41 #include <libdk4base/dk4mpl.h>
42 #include <libdk4c/dk4strm.h>
43 #include <libdk4c/dk4strmr.h>
44 #include <libdk4c/dk4dir.h>
45 #include <libdk4app/dk4dira.h>
46 #include <libdk4c/dk4pathd.h>
47 #include <libdk4c/dk4tsp08.h>
48 #include <libdk4c/dk4enc.h>
49 #include <libdk4maio8h/dk4mai8hul.h>
50 #include <libdk4maiodh/dk4maodh.h>
51 #include <libdk4maiodd/dk4maodd.h>
52 #include <libdk4base/dk4unused.h>
53 #include <libdk4c/dk4rec26.h>
54 #include <libdk4lat/uc2l.h>
55 
56 #if DK4_HAVE_ASSERT_H
57 #ifndef	ASSERT_H_INCLUDED
58 #include <assert.h>
59 #define	ASSERT_H_INCLUDED 1
60 #endif
61 #endif
62 
63 
64 
65 
66 
67 
68 /**	Convert to unsigned long.
69 */
70 #define	UL(x)	((unsigned long)(x))
71 
72 
73 
74 /**	Object to use and modify from line handler.
75 */
76 typedef struct {
77 	dk4_uc2l_t				*ulptr;		/**< Conversion structure. */
78 	dk4_sto_t				*s_ra;		/**< Local range storage. */
79 	dk4_sto_it_t			*i_ra;		/**< Local range iterator. */
80 	dk4_uc2l_file_t			*file;		/**< File structure. */
81 	dk4_uc2l_range_t		*rpc;		/**< Range pointer cache, pass 2. */
82 	dk4_app_t				*app;		/**< Application structure. */
83 	const dkChar * const	*msgs;		/**< Localized message texts. */
84 	size_t					 szmsgs;	/**< Number of elements in msgs. */
85 	int						 e_d;		/**< Reported decoding errors. */
86 	int						 e_e;		/**< Reported encoding errors. */
87 	int						 e_p;		/**< Reported processing errors. */
88 } handler_object_t;
89 
90 
91 
92 /**	Fixed keywords used by the module, not localized.
93 */
94 static const dkChar * const	dk4uc2l_kwnl[] = {
95 /* 0 */
96 dkT("dir.charmap"),
97 
98 /* 1 */
99 dkT("/dktools/charmap"),
100 
101 /* 2 */
102 dkT("/dk4app/charmap"),
103 
104 /* 3 */
105 dkT("/dk3app/charmap"),
106 
107 /* 4 */
108 dkT(".t2l"),
109 
110 /* 5 */
111 dkT(".t2l.gz"),
112 
113 /* 6 */
114 dkT(".t2l.bz2"),
115 
116 /* 7 */
117 dkT("/"),
118 
119 /* 8 */
120 dkT("dk4uc2l.str"),
121 
122 NULL
123 
124 };
125 
126 
127 
128 /**	Localized texts.
129 */
130 static const dkChar * const	dk4uc2l_kw_def[] = {
131 /* 0 */
132 dkT("Syntax error!\n\tHexadecimal number required at start of line!"),
133 
134 /* 1 */
135 dkT("Syntax error!\n\tHexadecimal value outside allowed 32 bit range!"),
136 
137 /* 2 */
138 dkT("Syntax error!\n\tIgnoring redefinition of 0x"),
139 
140 /* 3 */
141 dkT("!"),
142 
143 /* 4 */
144 dkT("Syntax error!\n\tIgnoring redefinition of character!"),
145 
146 /* 5 */
147 dkT("Failed to set up text processing!"),
148 
149 /* 6 */
150 dkT("Failed to open file for reading:\n\t\""),
151 
152 /* 7 */
153 dkT("\"!"),
154 
155 /* 8 */
156 dkT("Syntax error!\n\tIllegal font encoding name!"),
157 
158 /* 9 */
159 dkT("Syntax error!\n\t1 to 15 packages names are allowed!"),
160 
161 /* 10 */
162 dkT("Syntax error!\n\tIllegal attribute name!"),
163 
164 /* 11 */
165 dkT("Syntax error!\n\tAttribute specified without value!"),
166 
167 /* 12 */
168 dkT("Conversion to UTF-8 failed for 0x"),
169 
170 /* 13 */
171 dkT("!"),
172 
173 /* 14 */
174 dkT("Conversion to UTF-8 failed for a character!"),
175 
176 /* 15 */
177 dkT("No directory for character mapping information found!"),
178 
179 /* 16 */
180 dkT("Decoding failed!\n\tByte:"),
181 
182 /* 17 */
183 dkT("Encoding failed!\n\tByte:"),
184 
185 /* 18 */
186 dkT("Processing failed!\n\tByte:"),
187 
188 /* 19 */
189 dkT(",\n\tCharacter:"),
190 
191 /* 20 */
192 dkT(",\n\tPosition in line:"),
193 
194 /* 21 */
195 dkT("."),
196 
197 /* 22 */
198 dkT("Decoding failed!"),
199 
200 /* 23 */
201 dkT("Encoding failed!"),
202 
203 /* 24 */
204 dkT("Processing failed!"),
205 
206 /* 25 */
207 dkT("Further decoding failures!"),
208 
209 /* 26 */
210 dkT("Further encoding failures!"),
211 
212 /* 27 */
213 dkT("Further processing failures!"),
214 
215 /* 28 */
216 dkT("Syntax error!\n\tIgnoring redefinition of 0x"),
217 
218 /* 29 */
219 dkT("\n\tpreviously defined in \""),
220 
221 /* 30 */
222 dkT("\"!"),
223 
224 /* 31 */
225 dkT("No LaTeX encoding found for U+"),
226 
227 /* 32 */
228 dkT("!"),
229 
230 NULL
231 
232 };
233 
234 
235 
236 /**	Opening and closing tag for math mode.
237 */
238 static const char * const	dk4uc2l_mm[] = {
239 "\\(", "\\)"
240 };
241 
242 
243 
244 
245 /**	Handler to process a line during pass 1.
246 	@param	obj		Object to use and modify during processing.
247 	@param	line	Current text line to process.
248 	@param	lineno	Current line number.
249 	@param	erp		Error report, may be NULL.
250 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable
251 	errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort.
252 */
253 static
254 int
dk4uc2l_handler_pass1(void * obj,char * line,dk4_um_t lineno,dk4_er_t * erp)255 dk4uc2l_handler_pass1(
256 	void		*obj,
257 	char		*line,
258 	dk4_um_t	 lineno,
259 	dk4_er_t	*erp
260 )
261 {
262 	dkChar				 numbuf[16*sizeof(dk4_um_t)];
263 	handler_object_t	*pho;
264 	char				*p1;
265 	dk4_uc2l_range_t	*rptr;
266 	dk4_uc2l_range_t	*r2;
267 	const char			*pe		= NULL;
268 	size_t				 sznb	= DK4_SIZEOF(numbuf,dkChar);
269 	size_t				 padsz	= 8;
270 	unsigned long		 ul		= 0UL;
271 	dk4_c32_t			 c32;
272 	dk4_c32_t			 rbo;
273 	int					 res;
274 	int					 back	= DK4_TSP_RES_OK;
275 #if TRACE_DEBUG
276 	dk4str8_delnl(line);
277 #endif
278 
279 	pho = (handler_object_t *)obj;
280 	dk4app_set_log_source_line(pho->app, lineno);
281 
282 	/*	Find start of line, ignore empty lines and comments
283 	*/
284 	p1 = dk4str8_start(line, NULL);
285 	if (NULL == p1) {
286 		goto finished;
287 	}
288 	if ('#' == *p1) {
289 		goto finished;
290 	}
291 
292 	/*	Retrieve hexadecimal number at start
293 	*/
294 	(void)dk4str8_next(p1, NULL);
295 	res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, erp);
296 	if (0 == res) {
297 		/* ERROR: Syntax, not a number */
298 		dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 0);
299 		goto finished;
300 	}
301 	c32 = (dk4_c32_t)ul;
302 
303 	/*	Check for number in global storage
304 	*/
305 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(
306 		pho->ulptr->i_ranges, &c32, 1
307 	);
308 	if (NULL != rptr) {
309 		/* ERROR: Ignoring redefinition */
310 		if ((dk4_c32_t)0xFFUL < c32) {
311 			if ((dk4_c32_t)0xFFFFUL < c32) {
312 				if ((dk4_c32_t)0xFFFFFFUL < c32) {
313 					padsz = 8;
314 				}
315 				else {
316 					padsz = 6;
317 				}
318 			}
319 			else {
320 				padsz = 4;
321 			}
322 		}
323 		else {
324 			padsz = 2;
325 		}
326 		if (0 != dk4ma_write_hex_unsigned(numbuf, sznb, c32, padsz, NULL)) {
327 			dk4app_log_5(
328 				pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR,
329 				28, 29, 30, numbuf, rptr->file->fn
330 			);
331 		}
332 		else {
333 			dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 4);
334 		}
335 		goto finished;
336 	}
337 
338 	/*	Check for number in storage for file
339 	*/
340 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &c32, 1);
341 	if (NULL != rptr) {
342 		/* ERROR: Ignoring redefinition */
343 		if ((dk4_c32_t)0xFFUL < c32) {
344 			if ((dk4_c32_t)0xFFFFUL < c32) {
345 				if ((dk4_c32_t)0xFFFFFFUL < c32) {
346 					padsz = 8;
347 				}
348 				else {
349 					padsz = 6;
350 				}
351 			}
352 			else {
353 				padsz = 4;
354 			}
355 		}
356 		else {
357 			padsz = 2;
358 		}
359 		if (0 != dk4ma_write_hex_unsigned(numbuf, sznb, c32, padsz, NULL)) {
360 			dk4app_log_3(
361 				pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 2, 3, numbuf
362 			);
363 		}
364 		else {
365 			dk4app_log_1(pho->app, pho->msgs, pho->szmsgs, DK4_LL_ERROR, 4);
366 		}
367 		goto finished;
368 	}
369 
370 	/*	Check whether appending to an existing range
371 	*/
372 	if (0UL < c32) {
373 		rbo = (dk4_c32_t)(c32 - 1UL);
374 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1);
375 		if (NULL != rptr) {
376 			rptr->end = c32;
377 #if	DK4_SIZEOF_LONG <= 4
378 			if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) {
379 #endif
380 				rbo = (dk4_c32_t)(c32 + 1UL);
381 				r2  = (dk4_uc2l_range_t *)dk4sto_it_find_like(
382 					pho->i_ra, &rbo, 1
383 				);
384 				if (NULL != r2) {
385 					dk4sto_remove(pho->s_ra, r2, NULL);
386 					rptr->end = r2->end;
387 					dk4uc2l_i_close_range(r2);
388 				}
389 #if	DK4_SIZEOF_LONG <= 4
390 			}
391 #endif
392 			goto finished;
393 		}
394 #if TRACE_DEBUG
395 		else {
396 		}
397 #endif
398 	}
399 
400 	/*	Check whether prepending to an existing range
401 	*/
402 #if	DK4_SIZEOF_LONG <= 4
403 	if ((dk4_um_t)(ULONG_MAX) > (dk4_um_t)c32) {
404 #endif
405 		rbo = (dk4_c32_t)(c32 + 1UL);
406 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(pho->i_ra, &rbo, 1);
407 		if (NULL != rptr) {
408 			rptr->start = c32;
409 			if ((dk4_c32_t)0UL < c32) {
410 				rbo = (dk4_c32_t)(c32 - 1UL);
411 				r2  = (dk4_uc2l_range_t *)dk4sto_it_find_like(
412 					pho->i_ra, &rbo, 1
413 				);
414 				if (NULL != r2) {
415 					dk4sto_remove(pho->s_ra, r2, NULL);
416 					rptr->start = r2->start;
417 					dk4uc2l_i_close_range(r2);
418 				}
419 			}
420 			goto finished;
421 		}
422 #if TRACE_DEBUG
423 		else {
424 		}
425 #endif
426 #if	DK4_SIZEOF_LONG <= 4
427 	}
428 #endif
429 
430 	/*	Create new range for one character on its own
431 	*/
432 	rptr = dk4uc2l_i_open_range(c32, pho->file, erp);
433 	if (NULL == rptr) {
434 		back = DK4_TSP_RES_FATAL;
435 		/* ERROR: Memory */
436 		dk4app_log_base1(pho->app, DK4_LL_ERROR, 90);
437 		goto finished;
438 	}
439 	if (0 == dk4sto_add(pho->s_ra, rptr, erp)) {
440 		dk4uc2l_i_close_range(rptr);
441 		/* ERROR: Memory */
442 		dk4app_log_base1(pho->app, DK4_LL_ERROR, 90);
443 		back = DK4_TSP_RES_FATAL;
444 	}
445 
446 	finished:
447 
448 	return back;
449 }
450 
451 
452 
453 /**	Report an error with position in source line.
454 	@param	i1		Index of first message part in array.
455 	@param	i2		Index of alternative first message part.
456 	@param	bno		Byte processed.
457 	@param	lno		Current line number.
458 	@param	cno		Current character number.
459 	@param	cil		Current character number in line.
460 	@param	dmsg	Localized error message texts.
461 	@param	szdmsg	Number of elements in dmsg array.
462 */
463 static
464 void
dk4uc2l_report_with_pos(dk4_app_t * app,size_t i1,size_t i2,dk4_um_t bno,dk4_um_t lno,dk4_um_t cno,dk4_um_t cil,const dkChar * const * dmsg,size_t szdmsg)465 dk4uc2l_report_with_pos(
466 	dk4_app_t				*app,
467 	size_t					 i1,
468 	size_t					 i2,
469 	dk4_um_t				 bno,
470 	dk4_um_t				 lno,
471 	dk4_um_t				 cno,
472 	dk4_um_t				 cil,
473 	const dkChar * const	*dmsg,
474 	size_t					 szdmsg
475 )
476 {
477 	dkChar		b1[8*(1+sizeof(dk4_um_t))];
478 	dkChar		b2[DK4_SIZEOF(b1,dkChar)];
479 	dkChar		b3[DK4_SIZEOF(b1,dkChar)];
480 	size_t		szbuf			= DK4_SIZEOF(b1,dkChar);
481 	dk4_um_t	oldlogline		= (dk4_um_t)0UL;
482 	int			allbuffersok	= 0;
483 
484 	oldlogline =	dk4app_get_log_source_line(app);
485 	dk4app_set_log_source_line(app, lno);
486 	if (0 != dk4ma_write_decimal_unsigned(b3, szbuf, cil, 0, NULL)) {
487 		if (0 != dk4ma_write_decimal_unsigned(b2, szbuf, cno, 0, NULL)) {
488 			if (0 != dk4ma_write_decimal_unsigned(b1, szbuf, bno, 0, NULL)) {
489 				allbuffersok = 1;
490 			}
491 		}
492 	}
493 	if (0 != allbuffersok) {
494 		dk4app_log_7(
495 			app, dmsg, szdmsg, DK4_LL_ERROR, i1, 19, 20, 21, b1, b2, b3
496 		);
497 	}
498 	else {
499 		dk4app_log_1(
500 			app, dmsg, szdmsg, DK4_LL_ERROR, i2
501 		);
502 	}
503 	dk4app_set_log_source_line(app, oldlogline);
504 }
505 
506 
507 
508 /**	Report errors from text stream processing.
509 	@param	app		Application structure, may be NULL.
510 	@param	obj		Object modified by line handler.
511 	@param	er_en	Error report for decoding and encoding errors.
512 	@param	er_pr	Error report for processing errors.
513 	@param	dmsg	Localized error message texts.
514 	@param	szmsg	Number of elements in dmsg array.
515 */
516 static
517 void
dk4uc2l_report_errors(dk4_app_t * app,handler_object_t * obj,dk4_er_t * er_en,dk4_er_t * er_pr,const dkChar * const * dmsg,size_t szdmsg)518 dk4uc2l_report_errors(
519 	dk4_app_t				*app,
520 	handler_object_t		*obj,
521 	dk4_er_t				*er_en,
522 	dk4_er_t				*er_pr,
523 	const dkChar * const	*dmsg,
524 	size_t					 szdmsg
525 )
526 {
527 	if (NULL != er_en) {
528 		switch (er_en->ec) {
529 			case DK4_E_DECODING_FAILED: {
530 				switch (obj->e_d) {
531 					case 0: case 1: {
532 						dk4uc2l_report_with_pos(
533 							app, 16, 22,
534 							er_en->dt.fpos.byteno,
535 							er_en->dt.fpos.lineno,
536 							er_en->dt.fpos.charno,
537 							er_en->dt.fpos.charinline,
538 							dmsg, szdmsg
539 						);
540 					} break;
541 					case 2: {
542 						dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 25); } break; }
543 				if (3 > obj->e_d) { obj->e_d += 1; }
544 			} break;
545 			case DK4_E_ENCODING_FAILED: {
546 				switch (obj->e_e) {
547 					case 0: case 1: {
548 						dk4uc2l_report_with_pos(
549 							app, 17, 23,
550 							er_en->dt.fpos.byteno,
551 							er_en->dt.fpos.lineno,
552 							er_en->dt.fpos.charno,
553 							er_en->dt.fpos.charinline,
554 							dmsg, szdmsg
555 						);
556 					} break;
557 					case 2: {
558 						dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 26);
559 					} break;
560 				}
561 				if (3 > obj->e_e) { obj->e_e += 1; }
562 			} break;
563 		}
564 	}
565 	if (NULL != er_pr) {
566 		if (DK4_E_NONE != er_pr->ec) {
567 			switch (obj->e_p) {
568 				case 0: case 1: {
569 					dk4uc2l_report_with_pos(
570 						app, 18, 24,
571 						er_pr->dt.fpos.byteno,
572 						er_pr->dt.fpos.lineno,
573 						er_pr->dt.fpos.charno,
574 						er_pr->dt.fpos.charinline,
575 						dmsg, szdmsg
576 					);
577 				} break;
578 				case 2: {
579 					dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 27);
580 				} break;
581 			}
582 			if (3 > obj->e_p) { obj->e_p += 1; }
583 		}
584 	}
585 }
586 
587 
588 /**	Process one stream from file in pass 1.
589 	@param	ulptr	Conversion structure to set up.
590 	@param	rstrm	Stream to read data from.
591 	@param	puc2lf	File structure.
592 	@param	bptr	Address of success variable to reset on error.
593 	@param	app		Application structure for diagnostics.
594 	@param	dmsg	Localized messages texts.
595 	@param	szdmsg	Size of dmsg array (number of string pointers).
596 */
597 static
598 void
dk4uc2l_i_process_stream_pass1(dk4_uc2l_t * ulptr,dk4_stream_t * rstrm,dk4_uc2l_file_t * puc2lf,int * bptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)599 dk4uc2l_i_process_stream_pass1(
600 	dk4_uc2l_t				*ulptr,
601 	dk4_stream_t			*rstrm,
602 	dk4_uc2l_file_t			*puc2lf,
603 	int						*bptr,
604 	dk4_app_t				*app,
605 	const dkChar * const	*dmsg,
606 	size_t					 szdmsg
607 )
608 {
609 	char					 lnbuf[256];
610 	dk4_tsp08_t				 tsp08;
611 	handler_object_t		 ho;
612 	dk4_er_t				 er_en;
613 	dk4_er_t				 er_pr;
614 	dk4_uc2l_range_t		*rptr;
615 	int						 res;
616 	int						 cc;
617 	char					 c;
618 
619 
620 	/*	Initialize handler object
621 	*/
622 	ho.file   = puc2lf;
623 	ho.ulptr  = ulptr;
624 	ho.s_ra   = NULL;
625 	ho.i_ra   = NULL;
626 	ho.app    = app;
627 	ho.msgs   = dmsg;
628 	ho.szmsgs = szdmsg;
629 	ho.e_d    = 0;
630 	ho.e_e    = 0;
631 	ho.e_p    = 0;
632 	dk4error_init(&er_en);
633 	dk4error_init(&er_pr);
634 
635 	/*	Allocate storage and iterator
636 	*/
637 	ho.s_ra = dk4sto_open(NULL);
638 	if (NULL == ho.s_ra) {
639 		*bptr = 0;
640 		ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
641 		/* ERROR: Memory */
642 		dk4app_log_base1(app, DK4_LL_ERROR, 90);
643 		goto finished;
644 	}
645 	dk4sto_set_comp(ho.s_ra, dk4uc2l_i_range_compare, 0);
646 	ho.i_ra = dk4sto_it_open(ho.s_ra, NULL);
647 	if (NULL == ho.i_ra) {
648 		*bptr = 0;
649 		ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
650 		/* ERROR: Memory */
651 		dk4app_log_base1(app, DK4_LL_ERROR, 90);
652 		goto finished;
653 	}
654 
655 	/*	Initialize text stream processor
656 	*/
657 	res = dk4tsp08_setup_line(
658 		&tsp08, (void *)(&ho), dk4uc2l_handler_pass1, lnbuf, sizeof(lnbuf),
659 		DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, NULL
660 	);
661 	if (0 == res) {
662 		*bptr = 0;
663 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
664 		/* ERROR: Failed to initialize  text stream processor */
665 		dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 5);
666 		goto finished;
667 	}
668 
669 	/*	Process input data
670 	*/
671 	do {
672 		cc = 0;
673 		res = dk4stream_c8_read_byte(&c, rstrm, NULL);
674 		if (0 != res) {
675 			cc = 1;
676 			res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c);
677 			switch (res) {
678 				case DK4_TSP_RES_ERROR : {
679 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
680 					*bptr = 0;
681 					dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
682 					dk4uc2l_report_errors(
683 						app, &ho, &er_en, &er_pr, dmsg, szdmsg
684 					);
685 					dk4error_init(&er_en);
686 					dk4error_init(&er_pr);
687 				} break;
688 				case DK4_TSP_RES_FATAL : {
689 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
690 					*bptr = 0;
691 					dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
692 					dk4uc2l_report_errors(
693 						app, &ho, &er_en, &er_pr, dmsg, szdmsg
694 					);
695 					dk4error_init(&er_en);
696 					dk4error_init(&er_pr);
697 					goto finished;
698 				} break;
699 			}
700 		}
701 	} while (0 < cc);
702 
703 	/*	Finalize text stream processor
704 	*/
705 	res = dk4tsp08_finish(&tsp08);
706 	switch (res) {
707 		case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: {
708 			ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
709 			*bptr = 0;
710 			dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
711 			dk4uc2l_report_errors(
712 				app, &ho, &er_en, &er_pr, dmsg, szdmsg
713 			);
714 			goto finished;
715 		} break;
716 	}
717 
718 	/*	Transfer ranges to global storage
719 	*/
720 	do {
721 		dk4sto_it_reset(ho.i_ra);
722 		rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra);
723 		if (NULL != rptr) {
724 			dk4sto_remove(ho.s_ra, rptr, NULL);
725 			if (0 == dk4sto_add(ulptr->s_ranges, rptr, NULL)) {
726 				dk4uc2l_i_close_range(rptr);
727 				*bptr = 0;
728 				/* ERROR: Memory */
729 				dk4app_log_base1(app, DK4_LL_ERROR, 90);
730 				goto finished;
731 			}
732 		}
733 	} while (NULL != rptr);
734 
735 	/*	Release resources
736 	*/
737 	finished:
738 	if (NULL != ho.s_ra) {
739 		if (NULL != ho.i_ra) {
740 			dk4sto_it_reset(ho.i_ra);
741 			do {
742 				rptr = (dk4_uc2l_range_t *)dk4sto_it_next(ho.i_ra);
743 				if (NULL != rptr) {
744 					dk4uc2l_i_close_range(rptr);
745 				}
746 			} while (NULL != rptr);
747 			dk4sto_it_close(ho.i_ra);
748 		}
749 		dk4sto_close(ho.s_ra);
750 	}
751 
752 
753 }
754 
755 
756 
757 
758 /**	Process one file in pass 1 specified by absolute path name.
759 	@param	ulptr	Conversion structure to set up.
760 	@param	fn		Absolute file name.
761 	@param	sfn		Short (relative) file name within given directory.
762 	@param	bptr	Address of success variable to reset on error.
763 	@param	app		Application structure for diagnostics.
764 	@param	dmsg	Localized messages texts.
765 	@param	szdmsg	Size of dmsg array (number of string pointers).
766 */
767 static
768 void
dk4uc2l_i_process_one_full_file_pass1(dk4_uc2l_t * ulptr,const dkChar * fn,const dkChar * sfn,int * bptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)769 dk4uc2l_i_process_one_full_file_pass1(
770 	dk4_uc2l_t				*ulptr,
771 	const dkChar			*fn,
772 	const dkChar			*sfn,
773 	int						*bptr,
774 	dk4_app_t				*app,
775 	const dkChar * const	*dmsg,
776 	size_t					 szdmsg
777 )
778 {
779 	const dkChar	*oldsourcefile;
780 	dk4_stream_t	*rstrm;
781 	dk4_uc2l_file_t	*puc2lf;
782 	dk4_um_t		 oldsourceline;
783 	int				 fnsi;
784 
785 	oldsourcefile = dk4app_get_log_source_file(app);
786 	oldsourceline = dk4app_get_log_source_line(app);
787 	dk4app_set_log_source_file(app, fn);
788 	dk4app_set_log_source_line(app, (dk4_um_t)0UL);
789 	puc2lf = (dk4_uc2l_file_t *)dk4sto_it_find_like(ulptr->i_files, sfn, 1);
790 	if (NULL == puc2lf) {
791 		puc2lf = dk4uc2l_i_open_file(sfn, NULL);
792 		if (NULL != puc2lf) {
793 			if (0 != dk4sto_add(ulptr->s_files, puc2lf, NULL)) {
794 				fnsi = dk4uc2l_i_find_suffix_index(fn);
795 				if (-1 < fnsi) {
796 					if (0 != dk4uc2l_i_suffix_index_supported(fnsi)) {
797 						rstrm = dk4stream_open_file_reader(fn, NULL);
798 						if (NULL != rstrm) {
799 							dk4uc2l_i_process_stream_pass1(
800 								ulptr, rstrm, puc2lf, bptr, app, dmsg, szdmsg
801 							);
802 							dk4stream_close(rstrm, NULL);
803 						}
804 						else {
805 							ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
806 							/* ERROR: Failed to read file */
807 							dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn);
808 							*bptr = 0;
809 						}
810 					}
811 					else {
812 						/* ERROR: Unsupported compression mechanism */
813 						dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn);
814 						ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
815 						*bptr = 0;
816 					}
817 				}
818 				else {
819 					/* Warning: Unsupported file type */
820 					dk4app_log_3(app,dmsg,szdmsg,DK4_LL_ERROR,6,7,fn);
821 				}
822 			}
823 			else {
824 				dk4uc2l_i_close_file(puc2lf);
825 				/* ERROR: Memory */
826 				dk4app_log_base1(app, DK4_LL_ERROR, 90);
827 			}
828 		}
829 		else {
830 			/* ERROR: Memory */
831 			dk4app_log_base1(app, DK4_LL_ERROR, 90);
832 		}
833 	}
834 	else {
835 		/* BUG file already processed */
836 	}
837 	dk4app_set_log_source_file(app, oldsourcefile);
838 	dk4app_set_log_source_line(app, oldsourceline);
839 
840 }
841 
842 
843 
844 /**	Process one file in pass 1.
845 	@param	ulptr	Conversion structure to set up.
846 	@param	pth		Directory path name, may be NULL.
847 	@param	fn		Short file name within given directory.
848 	@param	bptr	Address of success variable to reset on error.
849 	@param	app		Application structure for diagnostics.
850 	@param	dmsg	Localized messages texts.
851 	@param	szdmsg	Size of dmsg array (number of string pointers).
852 */
853 static
854 void
dk4uc2l_i_process_one_file_pass1(dk4_uc2l_t * ulptr,const dkChar * pth,const dkChar * fn,int * bptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)855 dk4uc2l_i_process_one_file_pass1(
856 	dk4_uc2l_t				*ulptr,
857 	const dkChar			*pth,
858 	const dkChar			*fn,
859 	int						*bptr,
860 	dk4_app_t				*app,
861 	const dkChar * const	*dmsg,
862 	size_t					 szdmsg
863 )
864 {
865 	dkChar			 fnb[DK4_MAX_PATH];
866 	size_t			 szfnb = DK4_SIZEOF(fnb,dkChar);
867 
868 	if (NULL != pth) {
869 		if (0 != dk4str_cpy_s(fnb, szfnb, pth, NULL)) {
870 			if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[7], NULL)) {
871 				if (0 != dk4str_cat_s(fnb, szfnb, fn, NULL)) {
872 					dk4path_correct_sep(fnb);
873 					dk4uc2l_i_process_one_full_file_pass1(
874 						ulptr, fnb, fn, bptr, app, dmsg, szdmsg
875 					);
876 				}
877 				else {
878 					*bptr = 0;
879 					/* ERROR pth and/or fn too long */
880 					dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth);
881 				}
882 			}
883 			else {
884 				*bptr = 0;
885 				/* ERROR: pth too long */
886 				dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth);
887 			}
888 		}
889 		else {
890 			*bptr = 0;
891 			/* ERROR: pth too long */
892 			dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth);
893 		}
894 	}
895 	else {
896 		dk4uc2l_i_process_one_full_file_pass1(ulptr,fn,fn,bptr,app,dmsg,szdmsg);
897 	}
898 
899 }
900 
901 
902 
903 /**	First pass to gather information which Unicode position is configured
904 	in which data file.
905 	This function is run while creating a new conversion structure
906 	to fill the range structures so we can later find a file for a
907 	Unicode position.
908 	If this function fails, the conversion structure is considered
909 	unusable.
910 	The function fails only on memory allocation failures.
911 	Syntax errors in translation files are reported as errors through
912 	app, but the function indicates success.
913 	@param	ulptr	Conversion structure.
914 	@param	app		Application structure for diagnostics, may be NULL.
915 	@return	1 on success, 0 on error.
916 */
917 static
918 int
dk4uc2l_i_pass1(dk4_uc2l_t * ulptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)919 dk4uc2l_i_pass1(
920 	dk4_uc2l_t				*ulptr,
921 	dk4_app_t				*app,
922 	const dkChar * const	*dmsg,
923 	size_t					 szdmsg
924 )
925 {
926 	const dkChar	*fn		= NULL;
927 	const dkChar	*pth	= NULL;
928 	dk4_dir_t		*pdir	= NULL;
929 	int				 back	= 0;
930 
931 	pdir = dk4dir_open_app(ulptr->dname, 0, app);
932 	if (NULL != pdir) {
933 		pth = dk4dir_get_path(pdir);
934 		back = 1;
935 		do {
936 			fn = dk4dir_next_file(pdir);
937 			if (NULL != fn) {
938 				if (-1 < dk4uc2l_i_find_suffix_index(fn)) {
939 					dk4uc2l_i_process_one_file_pass1(
940 						ulptr, pth, fn, &back, app, dmsg, szdmsg
941 					);
942 				}
943 			}
944 		} while (NULL != fn);
945 		dk4dir_close(pdir);
946 	}
947 	else {
948 		/* ERROR: Failed to open directory (already reported) */
949 		ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
950 	}
951 
952 	return back;
953 }
954 
955 
956 
957 /**	Handler to process a line during pass 1.
958 	@param	obj		Object to use and modify during processing.
959 	@param	line	Current text line to process.
960 	@param	lineno	Current line number.
961 	@param	erp		Error report, may be NULL.
962 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on recoverable
963 	errors, DK4_TSP_RES_FATAL on fatal errors requiring an abort.
964 */
965 static
966 int
dk4uc2l_handler_pass2(void * obj,char * line,dk4_um_t lineno,dk4_er_t * DK4_ARG_UNUSED (erp))967 dk4uc2l_handler_pass2(
968 	void		*obj,
969 	char		*line,
970 	dk4_um_t	 lineno,
971 	dk4_er_t	* DK4_ARG_UNUSED(erp)
972 )
973 {
974 	dk4_er_t			 er;
975 	char				*pkgn[16];
976 	handler_object_t	*lho	= NULL;
977 	const char			*pe		= NULL;
978 	char				*p1		= NULL;
979 	char				*p2		= NULL;
980 	char				*p3		= NULL;
981 	char				*p4		= NULL;
982 	dk4_uc2l_range_t	*rptr	= NULL;
983 	dk4_uc2l_pkg_t		*pptr	= NULL;
984 	size_t				 ind	= 0;
985 	size_t				 numpkg	= 0;
986 	size_t				 i		= 0;
987 	unsigned long		 ul		= 0UL;
988 	dk4_c32_t			 c32	= (dk4_c32_t)0UL;
989 	int					 back	= DK4_TSP_RES_OK;
990 	int					 res	= 0;
991 	int					 adding	= 0;
992 	unsigned char		 fex	= 0;
993 	unsigned char		 feval	= 0;
994 
995 	DK4_UNUSED_ARG(erp)
996 
997 #if	TRACE_DEBUG
998 	dk4str8_delnl(line);
999 
1000 #endif
1001 
1002 	/*	Line handler object
1003 	*/
1004 	lho = (handler_object_t *)obj;
1005 	dk4app_set_log_source_line(lho->app, lineno);
1006 
1007 	/*	Find start of line, ignore empty lines and comments
1008 	*/
1009 	p1 = dk4str8_start(line, NULL);
1010 	if (NULL == p1) {
1011 		goto finished;
1012 	}
1013 	if ('#' == *p1) {
1014 		goto finished;
1015 	}
1016 
1017 	/*	Retrieve character number
1018 	*/
1019 	p2 = dk4str8_next(p1, NULL);
1020 	res = dk4ma_input_c8_hex_ulong(&ul, p1, &pe, 1, NULL);
1021 	if (0 == res) {
1022 		/*	WARNING: Syntax, no number.
1023 			Already reported in pass 1.
1024 		*/
1025 		lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1026 		goto finished;
1027 	}
1028 	c32 = (dk4_c32_t)ul;
1029 
1030 	/*	Find and check range structure, attempt cached range pointer first
1031 	*/
1032 	if (NULL != lho->rpc) {
1033 		if ((lho->rpc->start <= c32) && (c32 <= lho->rpc->end)) {
1034 			rptr = lho->rpc;
1035 		}
1036 	}
1037 	if (NULL == rptr) {
1038 		rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(lho->ulptr->i_ranges,&c32,1);
1039 	}
1040 	if (NULL == rptr) {
1041 		/*	ERROR: No range found.
1042 			Already reported in pass 1.
1043 		*/
1044 		lho->ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1045 		back = DK4_TSP_RES_FATAL;
1046 		goto finished;
1047 	}
1048 	if (0 != dk4str_cmp(lho->file->fn, rptr->file->fn)) {
1049 		/*	ERROR: Not owned by current file.
1050 			Already reported in pass 1.
1051 		*/
1052 
1053 		lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1054 		goto finished;
1055 	}
1056 
1057 	/*	Initialize range structure (allocate memory) if not yet done
1058 	*/
1059 	if (0x00 == rptr->ia) {
1060 		if (0 == dk4uc2l_i_init_range(rptr, NULL)) {
1061 			/* ERROR: Memory */
1062 			dk4app_log_base1(lho->app, DK4_LL_ERROR, 90);
1063 
1064 			lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1065 			back = DK4_TSP_RES_FATAL;
1066 			goto finished;
1067 		}
1068 		rptr->ia = 0x01;
1069 	}
1070 
1071 	/*	Find index
1072 	*/
1073 	ind = (size_t)(c32 - rptr->start);
1074 
1075 	/*	Check whether character already defined
1076 	*/
1077 	if (NULL != rptr->lno) {
1078 		if ((dk4_um_t)0UL != (rptr->lno)[ind]) {
1079 			/*	ERROR: Redefinition.
1080 				Already reported in pass 1.
1081 			*/
1082 
1083 			lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1084 			goto finished;
1085 		}
1086 		else {
1087 			(rptr->lno)[ind] = lineno;
1088 		}
1089 	}
1090 
1091 	/*	Traverse all strings in line
1092 	*/
1093 	p1 = p2;
1094 	while (NULL != p1) {
1095 		p2 = dk4str8_next(p1, NULL);
1096 		p3 = dk4str8_chr(p1, '=');
1097 		if (NULL != p3) {
1098 			*(p3++) = '\0';
1099 			p3 = dk4str8_start(p3, NULL);
1100 			if (NULL != p3) {
1101 
1102 				res = dk4uc2l_i_keyword_index(p1);
1103 				switch (res) {
1104 					case 0 : {
1105 						if (NULL != rptr->both) {
1106 							if (NULL == (rptr->both)[ind]) {
1107 								(rptr->both)[ind] = dk4str8_dup(p3, NULL);
1108 								if (NULL == (rptr->both)[ind]) {
1109 									/* ERROR: Memory */
1110 									dk4app_log_base1(lho->app, DK4_LL_ERROR, 90);
1111 
1112 									lho->ulptr->had_error |=
1113 									DK4_UC2L_ERROR_MEMORY;
1114 								}
1115 							}
1116 							else {
1117 								/*	ERROR: Already defined.
1118 									Bug: Should not happen.
1119 								*/
1120 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1121 							}
1122 						}
1123 						else {
1124 							/*	ERROR: Memory.
1125 								Already reported during range initialization.
1126 							*/
1127 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1128 						}
1129 					} break;
1130 					case 1 : {
1131 						if (NULL != rptr->text) {
1132 							if (NULL == (rptr->text)[ind]) {
1133 								(rptr->text)[ind] = dk4str8_dup(p3, NULL);
1134 								if (NULL == (rptr->text)[ind]) {
1135 									/* ERROR: Memory */
1136 									dk4app_log_base1(lho->app, DK4_LL_ERROR, 90);
1137 
1138 									lho->ulptr->had_error |=
1139 									DK4_UC2L_ERROR_MEMORY;
1140 								}
1141 							}
1142 							else {
1143 								/*	ERROR: Already defined.
1144 									Bug: Should not happen.
1145 								*/
1146 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1147 							}
1148 						}
1149 						else {
1150 							/*	ERROR: Memory
1151 								Already reported during range initialization.
1152 							*/
1153 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1154 						}
1155 					} break;
1156 					case 2 : {
1157 						if (NULL != rptr->math) {
1158 							if (NULL == (rptr->math)[ind]) {
1159 								(rptr->math)[ind] = dk4str8_dup(p3, NULL);
1160 								if (NULL == (rptr->math)[ind]) {
1161 									/* ERROR: Memory */
1162 									dk4app_log_base1(lho->app, DK4_LL_ERROR, 90);
1163 
1164 									lho->ulptr->had_error |=
1165 									DK4_UC2L_ERROR_MEMORY;
1166 								}
1167 							}
1168 							else {
1169 								/*	ERROR: Already defined.
1170 									Bug: Should not happen.
1171 								*/
1172 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1173 							}
1174 						}
1175 						else {
1176 							/*	ERROR: Memory.
1177 								Already reported during range initialization.
1178 							*/
1179 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1180 						}
1181 					} break;
1182 					case 3 : {
1183 						if (NULL != rptr->fenc) {
1184 							adding = 1;
1185 							feval  = 0x00;
1186 							if ('!' == *p3) {
1187 								adding = 0;
1188 								p3++;
1189 								feval = DK4_UC2L_FONT_ENCODING_ALL;
1190 							}
1191 							while (NULL != p3) {
1192 								p4 = dk4str8_chr(p3, ',');
1193 								if (NULL != p4) {
1194 									*(p4++) = '\0';
1195 								}
1196 								fex = dk4uc2l_font_encoding_from_name(p3);
1197 								if (0x00 != fex) {
1198 									if (0 != adding) {
1199 										feval |= fex;
1200 									}
1201 									else {
1202 										feval = (unsigned char)(feval & (~(fex)));
1203 									}
1204 								}
1205 								else {
1206 									/* ERROR: Illegal encoding name */
1207 									dk4app_log_1(
1208 										lho->app, lho->msgs, lho->szmsgs,
1209 										DK4_LL_ERROR, 8
1210 									);
1211 									lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1212 								}
1213 								p3 = p4;
1214 							}
1215 							(rptr->fenc)[ind] = feval;
1216 						}
1217 						else {
1218 							/*	ERROR: Memory.
1219 								Already reported during range initialization.
1220 							*/
1221 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1222 						}
1223 					} break;
1224 					case 4 : {
1225 						if (NULL != rptr->pkgs) {
1226 							if (NULL == (rptr->pkgs)[ind]) {
1227 								dk4error_init(&er);
1228 								numpkg = dk4str8_tokenize(
1229 									pkgn, 16, p3, ",", &er
1230 								);
1231 								if (0 < numpkg) {
1232 									(rptr->pkgs)[ind] =
1233 									dk4mem_new(dk4_uc2l_pkg_p,(numpkg+1),NULL);
1234 									if (NULL != (rptr->pkgs)[ind]) {
1235 										for (i = 0; i <= numpkg; i++) {
1236 											((rptr->pkgs)[ind])[i] = NULL;
1237 										}
1238 										for (i = 0; i < numpkg; i++) {
1239 											pptr =
1240 											(dk4_uc2l_pkg_t *)dk4sto_it_find_like(
1241 												lho->ulptr->i_pkgs, pkgn[i], 1
1242 											);
1243 											if (NULL != pptr) {
1244 												((rptr->pkgs)[ind])[i] = pptr;
1245 											}
1246 											else {
1247 												pptr = dk4uc2l_i_create_pkg(
1248 													lho->ulptr->s_pkgs, pkgn[i]
1249 												);
1250 												if (NULL != pptr) {
1251 													((rptr->pkgs)[ind])[i] =
1252 													pptr;
1253 												}
1254 												else {
1255 													/* ERROR: Memory */
1256 													dk4app_log_base1(
1257 														lho->app,DK4_LL_ERROR,90
1258 													);
1259 													lho->ulptr->had_error |=
1260 													DK4_UC2L_ERROR_MEMORY;
1261 												}
1262 											}
1263 										}
1264 									}
1265 									else {
1266 										/* ERROR: Memory */
1267 										dk4app_log_base1(
1268 											lho->app, DK4_LL_ERROR, 90
1269 										);
1270 										lho->ulptr->had_error |=
1271 										DK4_UC2L_ERROR_MEMORY;
1272 									}
1273 								}
1274 								else {
1275 									dk4app_log_1(
1276 										lho->app, lho->msgs, lho->szmsgs,
1277 										DK4_LL_ERROR, 9
1278 									);
1279 								}
1280 							}
1281 							else {
1282 								/*	ERROR: Already defined.
1283 									Bug: Should not happen.
1284 								*/
1285 								lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1286 							}
1287 						}
1288 						else {
1289 							/*	ERROR: Memory.
1290 								Already reported during range initalization.
1291 							*/
1292 							lho->ulptr->had_error |= DK4_UC2L_ERROR_MEMORY;
1293 						}
1294 					} break;
1295 					default : {
1296 						/* ERROR: Illegal key name */
1297 						dk4app_log_1(
1298 							lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 10
1299 						);
1300 						lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1301 					} break;
1302 				}
1303 				p1 = p2;
1304 			}
1305 			else {
1306 				/* ERROR: Syntax, not a key=value */
1307 				dk4app_log_1(lho->app,lho->msgs,lho->szmsgs,DK4_LL_ERROR,11);
1308 				lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1309 				p1 = NULL;
1310 			}
1311 		}
1312 		else {
1313 			/* ERROR: Syntax, not a key=value */
1314 			dk4app_log_1(lho->app, lho->msgs, lho->szmsgs, DK4_LL_ERROR, 11);
1315 			lho->ulptr->had_error |= DK4_UC2L_ERROR_SYNTAX;
1316 			p1 = NULL;
1317 		}
1318 	}
1319 
1320 	finished:
1321 
1322 	return back;
1323 }
1324 
1325 
1326 
1327 /**	Load one data file.
1328 	@param	ulptr	Conversion structure.
1329 	@param	fptr	File to load.
1330 	@param	app		Application structure for diagnostics.
1331 	@param	dmsg	Localized message texts.
1332 	@param	szdmsg	Number of elements in dmsg array.
1333 */
1334 static
1335 void
dk4uc2l_load_data_file(dk4_uc2l_t * ulptr,dk4_uc2l_file_t * fptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)1336 dk4uc2l_load_data_file(
1337 	dk4_uc2l_t				*ulptr,
1338 	dk4_uc2l_file_t			*fptr,
1339 	dk4_app_t				*app,
1340 	const dkChar * const	*dmsg,
1341 	size_t					 szdmsg
1342 )
1343 {
1344 	dkChar				 fnb[DK4_MAX_PATH];
1345 	char				 lnb[256];
1346 	handler_object_t	 ho;
1347 	dk4_er_t			 er_en;
1348 	dk4_er_t			 er_pr;
1349 	dk4_tsp08_t			 tsp08;
1350 	dk4_stream_t		*rstrm			= NULL;
1351 	const dkChar		*oldsourcefile	= NULL;
1352 	dk4_um_t			 oldsourceline	= (dk4_um_t)0UL;
1353 	size_t				 fnbsz			= DK4_SIZEOF(fnb,dkChar);
1354 	size_t				 szlnb			= sizeof(lnb);
1355 	int					 res;
1356 	int					 cc;
1357 	char				 c;
1358 
1359 
1360 
1361 	/*	Save old source file and line, set new source file
1362 	*/
1363 	oldsourcefile = dk4app_get_log_source_file(app);
1364 	oldsourceline = dk4app_get_log_source_line(app);
1365 	dk4app_set_log_source_file(app, fptr->fn);
1366 	dk4app_set_log_source_line(app, (dk4_um_t)0UL);
1367 
1368 	/*	Initialize handler object
1369 	*/
1370 	ho.ulptr	= ulptr;
1371 	ho.s_ra		= NULL;
1372 	ho.i_ra		= NULL;
1373 	ho.file		= fptr;
1374 	ho.rpc		= NULL;
1375 	ho.app		= app;
1376 	ho.msgs		= dmsg;
1377 	ho.szmsgs	= szdmsg;
1378 	ho.e_d		= 0;
1379 	ho.e_e		= 0;
1380 	ho.e_p		= 0;
1381 	dk4error_init(&er_en);
1382 	dk4error_init(&er_pr);
1383 
1384 	/*	Save source file name and line number
1385 	*/
1386 
1387 	/*	Each file should be loaded only once
1388 	*/
1389 	if (0x00 != fptr->loaded) {
1390 		goto finished;
1391 	}
1392 	fptr->loaded = 0x01;
1393 
1394 	/*	Construct full path name
1395 	*/
1396 	if (0 == dk4str_cpy_s(fnb, fnbsz, ulptr->dname, NULL)) {
1397 		/* ERROR: Directory name too long */
1398 		dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname);
1399 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1400 		goto finished;
1401 	}
1402 	if (0 == dk4str_cat_s(fnb, fnbsz, dk4uc2l_kwnl[7], NULL)) {
1403 		/* ERROR: Directory name too long */
1404 		dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname);
1405 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1406 		goto finished;
1407 	}
1408 	if (0 == dk4str_cat_s(fnb, fnbsz, fptr->fn, NULL)) {
1409 		/* ERROR: Directory name too long */
1410 		dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, ulptr->dname);
1411 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1412 		goto finished;
1413 	}
1414 	dk4path_correct_sep(fnb);
1415 	dk4app_set_log_source_file(app, fnb);
1416 
1417 	/*	Open reader stream
1418 	*/
1419 	rstrm = dk4stream_open_file_reader(fnb, NULL);
1420 	if (NULL == rstrm) {
1421 		/* ERROR: Failed to read file */
1422 		dk4app_log_3(app, dmsg, szdmsg, DK4_LL_ERROR, 6, 7, fnb);
1423 		ulptr->had_error |= DK4_UC2L_ERROR_FOPEN;
1424 		goto finished;
1425 	}
1426 
1427 	/*	Initialize text processing
1428 	*/
1429 	res = dk4tsp08_setup_line(
1430 		&tsp08, (void *)(&ho), dk4uc2l_handler_pass2, lnb, szlnb,
1431 		DK4_ENCODING_PLAIN, DK4_ENCODING_PLAIN, NULL
1432 	);
1433 	if (0 == res) {
1434 		ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1435 		/* ERROR: Memory */
1436 		dk4app_log_base1(app, DK4_LL_ERROR, 90);
1437 		goto finished;
1438 	}
1439 
1440 	/*	Process contents
1441 	*/
1442 	do {
1443 		cc = 0;
1444 		res = dk4stream_c8_read_byte(&c, rstrm, NULL);
1445 		if (0 < res) {
1446 			cc = 1;
1447 			res = dk4tsp08_add_one_byte(&tsp08, (unsigned char)c);
1448 			switch (res) {
1449 				case DK4_TSP_RES_ERROR : {
1450 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1451 					dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
1452 					dk4uc2l_report_errors(
1453 						app, &ho, &er_en, &er_pr, dmsg, szdmsg
1454 					);
1455 					dk4error_init(&er_en);
1456 					dk4error_init(&er_pr);
1457 				} break;
1458 				case DK4_TSP_RES_FATAL : {
1459 					ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1460 					dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
1461 					dk4uc2l_report_errors(
1462 						app, &ho, &er_en, &er_pr, dmsg, szdmsg
1463 					);
1464 					dk4error_init(&er_en);
1465 					dk4error_init(&er_pr);
1466 					goto finished;
1467 				} break;
1468 			}
1469 		}
1470 	} while (0 < cc);
1471 
1472 	/*	Finish text processing
1473 	*/
1474 	res = dk4tsp08_finish(&tsp08);
1475 	switch (res) {
1476 		case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: {
1477 			ulptr->had_error |= DK4_UC2L_ERROR_PROCESSING;
1478 			dk4tsp08_get_errors(&er_en, &er_pr, &tsp08);
1479 			dk4uc2l_report_errors(
1480 				app, &ho, &er_en, &er_pr, dmsg, szdmsg
1481 			);
1482 		} break;
1483 	}
1484 
1485 	/*	Clean up
1486 	*/
1487 	finished:
1488 	if (NULL != rstrm) {
1489 		dk4stream_close(rstrm, NULL);
1490 	}
1491 
1492 	/*	Restore source file name and line number
1493 	*/
1494 	dk4app_set_log_source_file(app, oldsourcefile);
1495 	dk4app_set_log_source_line(app, oldsourceline);
1496 
1497 }
1498 
1499 
1500 /**	Second pass to load all data files immediately.
1501 	@param	ulptr	Conversion structure.
1502 	@param	app		Application structure for diagnostics, may be NULL.
1503 	@param	dmsg	Localized message texts.
1504 	@param	szdmsg	Number of elements in dmsg array.
1505 	@return	1 on success, 0 on error.
1506 */
1507 static
1508 int
dk4uc2l_i_pass2(dk4_uc2l_t * ulptr,dk4_app_t * app,const dkChar * const * dmsg,size_t szdmsg)1509 dk4uc2l_i_pass2(
1510 	dk4_uc2l_t				*ulptr,
1511 	dk4_app_t				*app,
1512 	const dkChar * const	*dmsg,
1513 	size_t					 szdmsg
1514 )
1515 {
1516 	dk4_sto_it_t	*i_files	= NULL;
1517 	dk4_uc2l_file_t	*fptr;
1518 	int				 back		= 0;
1519 
1520 	/*	Create iterator through files
1521 	*/
1522 	i_files = dk4sto_it_open(ulptr->s_files, NULL);
1523 	if (NULL == i_files) {
1524 		goto finished;
1525 	}
1526 
1527 	back = 1;
1528 	dk4sto_it_reset(i_files);
1529 	do {
1530 		fptr = (dk4_uc2l_file_t *)dk4sto_it_next(i_files);
1531 		if (NULL != fptr) {
1532 			dk4uc2l_load_data_file(
1533 				ulptr, fptr, app, dmsg, szdmsg
1534 			);
1535 		}
1536 	} while (NULL != fptr);
1537 
1538 	/*	Clean up
1539 	*/
1540 	finished:
1541 	if (NULL != i_files) {
1542 		dk4sto_it_close(i_files);
1543 	}
1544 	return back;
1545 }
1546 
1547 
1548 
1549 /**	Open Unicode to LaTeX conversion structure with application support.
1550 	@param	dn		Directory name containing the translation files.
1551 	@param	app		Application structure for diagnostics.
1552 	@param	la		Flag: Load all data files immediately.
1553 	@param	dmsg	Localized messages array.
1554 	@param	szdmsg	Localized messages array size.
1555 	@return	Valid pointer on success (use dk4uc2l_close() to release
1556 	resources after use), NULL on error.
1557 */
1558 static
1559 dk4_uc2l_t *
dk4uc2l_i_open_app(const dkChar * dn,dk4_app_t * app,int la,const dkChar * const * dmsg,size_t szdmsg)1560 dk4uc2l_i_open_app(
1561 	const dkChar			*dn,
1562 	dk4_app_t				*app,
1563 	int						 la,
1564 	const dkChar * const	*dmsg,
1565 	size_t					 szdmsg
1566 )
1567 {
1568 	dk4_er_t		 er;
1569 	dk4_uc2l_t		*back	= NULL;
1570 
1571 	dk4error_init(&er);
1572 	back = dk4uc2l_i_new(dn, &er);
1573 	if (NULL != back) {
1574 		if (0 == dk4uc2l_i_pass1(back, app, dmsg, szdmsg)) {
1575 			dk4uc2l_close(back);
1576 			back = NULL;
1577 		}
1578 		else {
1579 			if (0 != la) {
1580 				if (0 == dk4uc2l_i_pass2(back, app, dmsg, szdmsg)) {
1581 					dk4uc2l_close(back);
1582 					back = NULL;
1583 				}
1584 			}
1585 		}
1586 	}
1587 	else {
1588 		/* ERROR: Memory */
1589 		dk4app_log_base1(app, DK4_LL_ERROR, 90);
1590 	}
1591 
1592 	return back;
1593 }
1594 
1595 
1596 
1597 dk4_uc2l_t *
dk4uc2l_open_app_ex1(const dkChar * dn,dk4_app_t * app,int la)1598 dk4uc2l_open_app_ex1(const dkChar *dn, dk4_app_t *app, int la)
1599 {
1600 	dkChar					 fnb[DK4_MAX_PATH];
1601 	const dkChar * const	*dmsg	=	NULL;
1602 	dk4_uc2l_t				*back	= NULL;
1603 	size_t					 i;
1604 	size_t					 szdmsg	= 0;
1605 	const size_t			 szfnb	= DK4_SIZEOF(fnb,dkChar);
1606 	int						 toolo	= 0;
1607 
1608 	if (NULL != app) {
1609 		szdmsg = dk4app_string_table_size(dk4uc2l_kw_def);
1610 		dmsg   = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def);
1611 		/*
1612 			Retrieve fallback from preferences
1613 		*/
1614 		if (NULL == dn) {
1615 			if (0 != dk4app_pref_get(fnb, szfnb, app, dk4uc2l_kwnl[0], 0)) {
1616 				dk4path_correct_sep(fnb);
1617 				if (0 != dk4file_is_directory(fnb, NULL)) {
1618 					dn = fnb;
1619 				}
1620 				else {
1621 					/* ERROR: Not a directory */
1622 					dk4app_log_base3(app, DK4_LL_ERROR, 152, 153, fnb);
1623 				}
1624 			}
1625 		}
1626 		/*	Retrieve builtin fallbacks
1627 		*/
1628 		if (NULL == dn) {
1629 			for (i = 1; ((i < 4) && (NULL == dn)); i++) {
1630 				if (0 != dk4str_cpy_s(fnb, szfnb, app->dir_share, NULL)) {
1631 					if (0 != dk4str_cat_s(fnb, szfnb, dk4uc2l_kwnl[i], NULL)) {
1632 						dk4path_correct_sep(fnb);
1633 						if (0 != dk4file_is_directory(fnb, NULL)) {
1634 							dn = fnb;
1635 						}
1636 					}
1637 					else {
1638 						toolo = 1;
1639 					}
1640 				}
1641 				else {
1642 					toolo = 1;
1643 				}
1644 			}
1645 		}
1646 		if (NULL != dn) {
1647 			if (0 != dk4file_is_directory(dn, NULL)) {
1648 				back = dk4uc2l_i_open_app(dn, app, la, dmsg, szdmsg);
1649 			}
1650 			else {
1651 				/* ERROR: Not a directory */
1652 				dk4app_log_base3(app, DK4_LL_ERROR, 152, 153, dn);
1653 			}
1654 		}
1655 		else {
1656 			if (0 != toolo) {
1657 				/* ERROR: Shared directory name too long! */
1658 				dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, app->dir_share);
1659 			}
1660 			else {
1661 				/* ERROR: No directory found */
1662 				dk4app_log_1(app, dmsg, szdmsg, DK4_LL_ERROR, 15);
1663 			}
1664 		}
1665 	}
1666 	else {
1667 		back = dk4uc2l_open(dn, NULL);
1668 	}
1669 
1670 	return back;
1671 }
1672 
1673 
1674 
1675 dk4_uc2l_t *
dk4uc2l_open_app(const dkChar * dn,dk4_app_t * app)1676 dk4uc2l_open_app(const dkChar *dn, dk4_app_t *app)
1677 {
1678 	return (dk4uc2l_open_app_ex1(dn, app, 0));
1679 }
1680 
1681 
1682 
1683 dk4_uc2l_t *
dk4uc2l_open_from_app(dk4_app_t * app)1684 dk4uc2l_open_from_app(dk4_app_t *app)
1685 {
1686 	return (dk4uc2l_open_app(NULL, app));
1687 }
1688 
1689 
1690 
1691 dk4_uc2l_t *
dk4uc2l_open_from_app_ex1(dk4_app_t * app,int la)1692 dk4uc2l_open_from_app_ex1(dk4_app_t *app, int la)
1693 {
1694 	return (dk4uc2l_open_app_ex1(NULL, app, la));
1695 }
1696 
1697 
1698 
1699 static
1700 const char *
dk4uc2l_i_find_app(dk4_uc2l_t * ulptr,dk4_c32_t c,int mm,dk4_app_t * app)1701 dk4uc2l_i_find_app(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_app_t *app)
1702 {
1703 	dk4_uc2l_range_t		 *rptr;
1704 	dk4_uc2l_pkg_t			**pkgpp;
1705 	dk4_uc2l_file_t			 *fptr;
1706 	const char				 *back	= NULL;
1707 	const dkChar * const	 *dmsg;
1708 	size_t					  ind;
1709 	size_t					  szdmsg;
1710 	size_t					  blgt;
1711 	int						  res;
1712 
1713 #if	DK4_USE_ASSERT
1714 	assert(NULL != ulptr);
1715 #endif
1716 	/*	Attempt direct output
1717 	*/
1718 	if (0 != dk4uc2lat_direct(c)) {
1719 		ulptr->buf[0] = (char)c;
1720 		ulptr->buf[1] = '\0';
1721 		back = &(ulptr->buf[0]);
1722 		goto finished;
1723 	}
1724 
1725 	/*	Attempt data loaded from file
1726 	*/
1727 	rptr = (dk4_uc2l_range_t *)dk4sto_it_find_like(ulptr->i_ranges, &c, 1);
1728 	if (NULL != rptr) {
1729 		fptr = rptr->file;
1730 		if (0x00 == fptr->loaded) {
1731 			szdmsg = dk4app_string_table_size(dk4uc2l_kw_def);
1732 			dmsg   = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def);
1733 			dk4uc2l_load_data_file(ulptr, fptr, app, dmsg, szdmsg);
1734 		}
1735 		ind = (size_t)(c - rptr->start);
1736 		if (0 != mm) {
1737 			if (NULL != rptr->math) {
1738 				back = (rptr->math)[ind];
1739 			}
1740 		}
1741 		else {
1742 			if (NULL != rptr->text) {
1743 				back = (rptr->text)[ind];
1744 			}
1745 		}
1746 		if (NULL == back) {
1747 			if (NULL != rptr->both) {
1748 				back = (rptr->both)[ind];
1749 			}
1750 		}
1751 		if (NULL != back) {
1752 			if (NULL != rptr->pkgs) {
1753 				pkgpp = (rptr->pkgs)[ind];
1754 				if (NULL != pkgpp) {
1755 					while (NULL != *pkgpp) {
1756 						(*(pkgpp++))->used = 0x01;
1757 					}
1758 				}
1759 			}
1760 			if (NULL != rptr->fenc) {
1761 				ulptr->fallowed &= (rptr->fenc)[ind];
1762 			}
1763 			goto finished;
1764 		}
1765 	}
1766 
1767 	/*	Attempt to use UTF-8 encoded or ASCII data directly
1768 	*/
1769 	if (0 == mm) {
1770 		if (0x00 != ulptr->utf8allowed) {
1771 			blgt = 15;
1772 			res = dk4utf8_encode(
1773 				(unsigned char *)(&(ulptr->buf[0])), &blgt, c, NULL
1774 			);
1775 			if (0 != res) {
1776 				ulptr->buf[blgt] = '\0';
1777 				back = &(ulptr->buf[0]);
1778 			}
1779 			else {
1780 				/* ##### ERROR: UTF-8 encoding failed */
1781 			}
1782 		}
1783 		else {
1784 			if (dkC32(0x00000100) > c) {
1785 				ulptr->buf[0] = (char)c;
1786 				ulptr->buf[1] = '\0';
1787 				back = &(ulptr->buf[0]);
1788 			}
1789 		}
1790 	}
1791 
1792 	finished:
1793 	if (NULL != back) {
1794 		/*	ERROR: No LaTeX encoding found for ...
1795 			The calling application should attempt to recover from this
1796 			error or report it.
1797 		*/
1798 	}
1799 
1800 	return back;
1801 }
1802 
1803 
1804 
1805 const char *
dk4uc2l_find_app(dk4_uc2l_t * ulptr,dk4_c32_t c,int mm,dk4_app_t * app)1806 dk4uc2l_find_app(dk4_uc2l_t *ulptr, dk4_c32_t c, int mm, dk4_app_t *app)
1807 {
1808 
1809 	const char	*back	= NULL;
1810 
1811 #if	DK4_USE_ASSERT
1812 	assert(NULL != ulptr);
1813 #endif
1814 	if (NULL != ulptr) {
1815 		if (NULL != app) {
1816 			back = dk4uc2l_i_find_app(ulptr, c, mm, app);
1817 		}
1818 		else {
1819 			back = dk4uc2l_find(ulptr, c, mm, NULL);
1820 		}
1821 	}
1822 
1823 	return back;
1824 }
1825 
1826 
1827 
1828 /* ##### untested */
1829 static
1830 void
dk4uc2l_putc32_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,dk4_c32_t c32,int * pmm,int * pback,dk4_app_t * app)1831 dk4uc2l_putc32_app(
1832 	dk4_stream_t		*wstrm,
1833 	dk4_uc2l_t			*ulptr,
1834 	dk4_c32_t			 c32,
1835 	int					*pmm,
1836 	int					*pback,
1837 	dk4_app_t			*app
1838 )
1839 {
1840 	dkChar					 nb[16*sizeof(dk4_um_t)];
1841 	dk4_er_t				 er;
1842 	const dkChar * const	*dmsg;
1843 	const char				*le		= NULL;
1844 	size_t					 padsz	= 8;
1845 	size_t					 szdmsg	= 0;
1846 	size_t					 sznb = DK4_SIZEOF(nb,dkChar);
1847 
1848 	le = dk4uc2l_find(ulptr, c32, 0, NULL);
1849 	if (NULL != le) {
1850 		if (0 != *pmm) {
1851 			dk4error_init(&er);
1852 			if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
1853 				*pback = 0;
1854 				/* ERROR: Write failed */
1855 				dk4app_log_base1(app, DK4_LL_ERROR, 128);
1856 			}
1857 			*pmm = 0;
1858 		}
1859 		dk4error_init(&er);
1860 		if (0 == dk4stream_write_char_string(wstrm, le, &er)) {
1861 			*pback = 0;
1862 			/* ERROR: Write failed */
1863 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
1864 		}
1865 	}
1866 	else {
1867 		dk4error_init(&er);
1868 		le = dk4uc2l_find(ulptr, c32, 1, &er);
1869 		if (NULL != le) {
1870 			if (0 == *pmm) {
1871 				if (0 == dk4stream_write_char_string(wstrm,dk4uc2l_mm[0],&er)) {
1872 					*pback = 0;
1873 					/* ERROR: Write failed */
1874 					dk4app_log_base1(app, DK4_LL_ERROR, 128);
1875 				}
1876 				*pmm = 1;
1877 			}
1878 			dk4error_init(&er);
1879 			if (0 == dk4stream_write_char_string(wstrm, le, &er)) {
1880 				*pback = 0;
1881 				/* ERROR: Write failed */
1882 				dk4app_log_base1(app, DK4_LL_ERROR, 128);
1883 			}
1884 		}
1885 		else {
1886 			*pback = 0;
1887 			/* ERROR: Not found */
1888 			szdmsg = dk4app_string_table_size(dk4uc2l_kw_def);
1889 			dmsg   = dk4app_string_table(app, dk4uc2l_kwnl[8], dk4uc2l_kw_def);
1890 			if ((dk4_c32_t)0xFFUL < c32) {
1891 				if ((dk4_c32_t)0xFFFFUL < c32) {
1892 					if ((dk4_c32_t)0xFFFFFFUL < c32) {
1893 						padsz = 8;
1894 					}
1895 					else {
1896 						padsz = 6;
1897 					}
1898 				}
1899 				else {
1900 					padsz = 4;
1901 				}
1902 			}
1903 			else {
1904 				padsz = 2;
1905 			}
1906 			if (0 != dk4ma_write_hex_unsigned(nb, sznb, c32, padsz, NULL)) {
1907 				dk4app_log_3(app, dmsg, szdmsg, DK4_LL_ERROR, 31, 32, nb);
1908 			}
1909 #if TRACE_DEBUG
1910 			else {
1911 			}
1912 #endif
1913 		}
1914 	}
1915 
1916 }
1917 
1918 
1919 
1920 /* ##### untested */
1921 int
dk4uc2l_string_c32_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dk4_c32_t * str,dk4_app_t * app)1922 dk4uc2l_string_c32_app(
1923 	dk4_stream_t	*wstrm,
1924 	dk4_uc2l_t		*ulptr,
1925 	const dk4_c32_t	*str,
1926 	dk4_app_t		*app
1927 )
1928 {
1929 	dk4_er_t	 er;
1930 	int			 back	= 0;
1931 	int			 mm		= 0;
1932 
1933 #if	DK4_USE_ASSERT
1934 	assert(NULL != wstrm);
1935 	assert(NULL != ulptr);
1936 	assert(NULL != str);
1937 #endif
1938 	/*	Check arguments
1939 	*/
1940 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
1941 		goto finished;
1942 	}
1943 
1944 	/*	Process string
1945 	*/
1946 	back = 1;
1947 	while (dkC32(0) != *str) {
1948 		dk4uc2l_putc32_app(wstrm, ulptr, *(str++), &mm, &back, app);
1949 	}
1950 
1951 	/*	Finalize math mode if necessary
1952 	*/
1953 	if (0 != mm) {
1954 		dk4error_init(&er);
1955 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
1956 			back = 0;
1957 			/* ERROR: Write failed */
1958 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
1959 		}
1960 	}
1961 
1962 	finished:
1963 
1964 	return back;
1965 }
1966 
1967 
1968 
1969 /* ##### untested */
1970 int
dk4uc2l_string_c16_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dk4_c16_t * str,dk4_app_t * app)1971 dk4uc2l_string_c16_app(
1972 	dk4_stream_t	*wstrm,
1973 	dk4_uc2l_t		*ulptr,
1974 	const dk4_c16_t	*str,
1975 	dk4_app_t		*app
1976 )
1977 {
1978 	dk4_utf16_decoder_t		 dec;
1979 	dk4_er_t				 er;
1980 	dk4_c32_t				 c32;
1981 	int						 mm		= 0;
1982 	int						 back	= 0;
1983 	int						 err	= 0;
1984 
1985 #if	DK4_USE_ASSERT
1986 	assert(NULL != wstrm);
1987 	assert(NULL != ulptr);
1988 	assert(NULL != str);
1989 #endif
1990 	/*	Check arguments
1991 	*/
1992 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
1993 		goto finished;
1994 	}
1995 
1996 	/*	Process string
1997 	*/
1998 	back = 1;
1999 	dk4utf16_init(&dec);
2000 	while ((dkC16(0) != *str) && (0 == err)) {
2001 		switch (dk4utf16_add(&dec, *(str++))) {
2002 			case DK4_EDSTM_FINISHED : {
2003 				c32 = dk4utf16_get(&dec);
2004 				dk4utf16_init(&dec);
2005 				dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app);
2006 			} break;
2007 			case DK4_EDSTM_ERROR : {
2008 				err = 1;
2009 				back = 0;
2010 				/* ##### ERROR: Decoding failed */
2011 			} break;
2012 		}
2013 	}
2014 	if (0 == err) {
2015 		if (0 == dk4utf16_is_empty(&dec)) {
2016 			back = 0;
2017 			/* ##### ERROR: Decoding failed */
2018 		}
2019 	}
2020 
2021 	/*	Finalize math mode if necessary
2022 	*/
2023 	if (0 != mm) {
2024 		dk4error_init(&er);
2025 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
2026 			back = 0;
2027 			/* ERROR: Write failed */
2028 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
2029 		}
2030 	}
2031 	finished:
2032 
2033 	return back;
2034 }
2035 
2036 
2037 
2038 /* ##### untested */
2039 int
dk4uc2l_string_utf8_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_app_t * app)2040 dk4uc2l_string_utf8_app(
2041 	dk4_stream_t	*wstrm,
2042 	dk4_uc2l_t		*ulptr,
2043 	const char		*str,
2044 	dk4_app_t		*app
2045 )
2046 {
2047 	dk4_utf8_decoder_t	 dec;
2048 	dk4_er_t			 er;
2049 	dk4_c32_t			 c32;
2050 	int					 back	= 0;
2051 	int					 mm		= 0;
2052 	int					 err	= 0;
2053 
2054 #if	DK4_USE_ASSERT
2055 	assert(NULL != wstrm);
2056 	assert(NULL != ulptr);
2057 	assert(NULL != str);
2058 #endif
2059 	/*	Check arguments
2060 	*/
2061 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2062 		goto finished;
2063 	}
2064 
2065 	/*	Process string
2066 	*/
2067 	back = 1;
2068 	dk4utf8_init(&dec);
2069 	while(('\0' != *str) && (0 == err)) {
2070 		switch (dk4utf8_add(&dec, (unsigned char)(*(str++)))) {
2071 			case DK4_EDSTM_FINISHED : {
2072 				c32 = dk4utf8_get(&dec);
2073 				dk4utf8_init(&dec);
2074 				dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app);
2075 			} break;
2076 			case DK4_EDSTM_ERROR : {
2077 				err = 1;
2078 				back = 0;
2079 				/* ##### ERROR: Decoding failed */
2080 			} break;
2081 		}
2082 	}
2083 	if (0 == err) {
2084 		if (0 == dk4utf8_is_empty(&dec)) {
2085 			back = 0;
2086 			/* ##### ERROR: Decoding failed */
2087 		}
2088 	}
2089 
2090 	/*	Finalize math mode if necessary
2091 	*/
2092 	if (0 != mm) {
2093 		dk4error_init(&er);
2094 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
2095 			back = 0;
2096 			/* ERROR: Write failed */
2097 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
2098 		}
2099 	}
2100 	finished:
2101 
2102 	return back;
2103 }
2104 
2105 
2106 
2107 /* ##### untested */
2108 int
dk4uc2l_string_ansi_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_app_t * app)2109 dk4uc2l_string_ansi_app(
2110 	dk4_stream_t	*wstrm,
2111 	dk4_uc2l_t		*ulptr,
2112 	const char		*str,
2113 	dk4_app_t		*app
2114 )
2115 {
2116 	dk4_er_t			 er;
2117 	dk4_c32_t			 c32;
2118 	int					 back	= 0;
2119 	int					 mm		= 0;
2120 
2121 #if	DK4_USE_ASSERT
2122 	assert(NULL != wstrm);
2123 	assert(NULL != ulptr);
2124 	assert(NULL != str);
2125 #endif
2126 	/*	Check arguments
2127 	*/
2128 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2129 		goto finished;
2130 	}
2131 
2132 	/*	Process string
2133 	*/
2134 	back = 1;
2135 	while ('\0' != *str) {
2136 		if (0 != dk4ansi_decode(&c32, (unsigned char)(*(str++)))) {
2137 			dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app);
2138 		}
2139 		else {
2140 			back = 0;
2141 			/* ##### ERROR: Decoding failed */
2142 		}
2143 	}
2144 
2145 	/*	Finalize math mode if necessary
2146 	*/
2147 	if (0 != mm) {
2148 		dk4error_init(&er);
2149 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
2150 			back = 0;
2151 			/* ERROR: Write failed */
2152 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
2153 		}
2154 	}
2155 	finished:
2156 
2157 	return back;
2158 }
2159 
2160 
2161 
2162 /* ##### untested */
2163 int
dk4uc2l_string_ascii_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,dk4_app_t * app)2164 dk4uc2l_string_ascii_app(
2165 	dk4_stream_t	*wstrm,
2166 	dk4_uc2l_t		*ulptr,
2167 	const char		*str,
2168 	dk4_app_t		*app
2169 )
2170 {
2171 	dk4_er_t			 er;
2172 	dk4_c32_t			 c32;
2173 	int					 back	= 0;
2174 	int					 mm		= 0;
2175 
2176 #if	DK4_USE_ASSERT
2177 	assert(NULL != wstrm);
2178 	assert(NULL != ulptr);
2179 	assert(NULL != str);
2180 #endif
2181 	/*	Check arguments
2182 	*/
2183 	if ((NULL == wstrm) || (NULL == ulptr) || (NULL == str)) {
2184 		goto finished;
2185 	}
2186 
2187 	/*	Process string
2188 	*/
2189 	back = 1;
2190 	while ('\0' != *str) {
2191 		c32 = (dk4_c32_t)((unsigned char)(*(str++)));
2192 		dk4uc2l_putc32_app(wstrm, ulptr, c32, &mm, &back, app);
2193 	}
2194 
2195 	/*	Finalize math mode if necessary
2196 	*/
2197 	if (0 != mm) {
2198 		dk4error_init(&er);
2199 		if (0 == dk4stream_write_char_string(wstrm, dk4uc2l_mm[1], &er)) {
2200 			back = 0;
2201 			/* ERROR: Write failed */
2202 			dk4app_log_base1(app, DK4_LL_ERROR, 128);
2203 		}
2204 	}
2205 	finished:
2206 
2207 	return back;
2208 }
2209 
2210 
2211 
2212 int
dk4uc2l_string_c8_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const char * str,int ie,dk4_app_t * app)2213 dk4uc2l_string_c8_app(
2214 	dk4_stream_t	*wstrm,
2215 	dk4_uc2l_t		*ulptr,
2216 	const char		*str,
2217 	int				 ie,
2218 	dk4_app_t		*app
2219 )
2220 {
2221 #if	DK4_USE_ASSERT
2222 	assert(NULL != wstrm);
2223 	assert(NULL != ulptr);
2224 	assert(NULL != str);
2225 #endif
2226 	switch (ie) {
2227 		case DK4_ENCODING_UTF8 : {
2228 			return (dk4uc2l_string_utf8_app(wstrm, ulptr, str, app));
2229 		} break;
2230 		case DK4_ENCODING_WIN1252 : {
2231 			return (dk4uc2l_string_ansi_app(wstrm, ulptr, str, app));
2232 		} break;
2233 		default : {
2234 			return (dk4uc2l_string_ascii_app(wstrm, ulptr, str, app));
2235 		} break;
2236 	}
2237 }
2238 
2239 
2240 
2241 /* ##### untested */
2242 int
dk4uc2l_string_dk_app(dk4_stream_t * wstrm,dk4_uc2l_t * ulptr,const dkChar * str,int DK4_ARG_UNUSED (ie),dk4_app_t * app)2243 dk4uc2l_string_dk_app(
2244 	dk4_stream_t	*wstrm,
2245 	dk4_uc2l_t		*ulptr,
2246 	const dkChar	*str,
2247 #if	DK4_CHAR_SIZE > 1
2248 	int				 DK4_ARG_UNUSED(ie),
2249 #else
2250 	int				 ie,
2251 #endif
2252 	dk4_app_t		*app
2253 )
2254 {
2255 #if	DK4_CHAR_SIZE > 1
2256 	DK4_UNUSED_ARG(ie)
2257 #endif
2258 #if	DK4_USE_ASSERT
2259 	assert(NULL != wstrm);
2260 	assert(NULL != ulptr);
2261 	assert(NULL != str);
2262 #endif
2263 #if	DK4_CHAR_SIZE > 1
2264 #if	DK4_CHAR_SIZE > 2
2265 	return (dk4uc2l_string_c32_app(wstrm, ulptr, str, app));
2266 #else
2267 	return (dk4uc2l_string_c16_app(wstrm, ulptr, str, app));
2268 #endif
2269 #else
2270 	return (dk4uc2l_string_c8_app(wstrm, ulptr, str, ie, app));
2271 #endif
2272 }
2273 
2274 
2275 
2276 /* vim: set ai sw=4 ts=4 : */
2277 
2278