1 /*
2 Copyright (C) 2011-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: dk3app.ctr
12 */
13 
14 /**	@file dk3app.c The dk3app module.
15 */
16 
17 
18 #include <libdk3c/dk3all.h>
19 #include <libdk3c/dk3unused.h>
20 
21 
22 
23 #if DK3_HAVE_OPENSSL_RAND_H
24 #include <openssl/rand.h>
25 #endif
26 
27 
28 
29 
30 
31 
32 
33 /**	Names of preference scope attributes.
34 */
35 static dkChar const * const dk3app_scope_attributes[] = {
36 /*  0 */ dkT("user"),
37 /*  1 */ dkT("application"),
38 /*  2 */ dkT("application-group"),
39 /*  3 */ dkT("host"),
40 /*  4 */ dkT("language"),
41 /*  5 */ dkT("region"),
42 NULL
43 };
44 
45 
46 
47 /**	Text strings, not localized.
48 */
49 static dkChar const * const dk3app_no_loc[] = {
50 /*  0 */ dkT("bin"),		/* Used to build bindir. */
51 /*  1 */ dkT("etc"),		/* Used to build etcdir. */
52 /*  2 */ dkT("share"),		/* Used to build sharedir. */
53 /*  3 */ dkT("var"),		/* Used to build vardir. */
54 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
55 /*  4 */ dkT("\\log"),		/* Used to build log directory. */
56 #else
57 /*  4 */ dkT("/log"),		/* Used to build log directory. */
58 #endif
59 /*  5 */ dkT("-"),		/* Used to build log file name. */
60 /*  6 */ dkT(".log"),		/* Used to build log file name. */
61 /*  7 */ dkT("/"),		/* Used to build log directory. */
62 /*  8 */ dkT("a"),		/* Open mode for log file. */
63 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
64 /*  9 */ dkT("\\tmp"),		/* Subdirectory for temporary files. */
65 #else
66 /*  9 */ dkT("/tmp"),		/* Subdirectory for temporary files. */
67 #endif
68 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
69 /* 10 */ dkT("\\run"),		/* Subdirectory for temporary files. */
70 #else
71 /* 10 */ dkT("/run"),		/* Subdirectory for temporary files. */
72 #endif
73 /* 11 */ dkT("LANG"),		/* Environment variable for language. */
74 /* 12 */ dkT("Control Panel\\International"), /* Reg key for language. */
75 /* 13 */ dkT("LocaleName"),	/* Reg entry name for language. */
76 /* 14 */ dkT("sLanguage"),	/* Alternative reg entry name for language. */
77 /* 15 */ dkT("utf8"),		/* Encoding UTF-8 (modern variant). */
78 /* 16 */ dkT("UTF-8"),		/* Encoding UTF-8 (older variant). */
79 /* 17 */ dkT("dk3app"),		/* Subdirectory in system configuration. */
80 /* 18 */ dkT(".dk3app"),	/* Subdirectory in home directory. */
81 /* 19 */ dkT("."),		/* Current directory. */
82 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
83 /* 20 */ dkT("\\"),		/* File name separator. */
84 #else
85 /* 20 */ dkT("/"),		/* File name separator. */
86 #endif
87 /* 21 */ dkT("dk3pref.conf"),	/* Configuration file name. */
88 /* 22 */ dkT("r"),		/* File open mode for reading. */
89 /* 23 */ dkT("dk3app.str"),	/* String table name. */
90 /* 24 */ dkT("w"),		/* File open mode. */
91 /* 25 */ dkT("="),		/* Used when writing preferences. */
92 /* 26 */ dkT("\n"),		/* Used when writing preferences. */
93 /* 27 */ dkT("/ui/lang"),	/* User interface, language. */
94 /* 28 */ dkT("/log/file/level"),	/* Required log level for file. */
95 /* 29 */ dkT("/log/file/keep"),		/* Required level to keep file. */
96 /* 30 */ dkT("/log/stderr/level"),	/* Required log level for stderr. */
97 /* 31 */ dkT("/temp/dir/keep"),		/* Required to keep temp dir. */
98 /* 32 */ dkT("-site"),		/* Check for site-specific config files. */
99 /* 33 */ dkT("*"),		/* Wildcard for all users ... */
100 /* 34 */ dkT("dk3conf.conf"),	/* Configuration file name. */
101 /* 35 */ dkT("%lu"),		/* scanf/printf format. */
102 /* 36 */ dkT("rb"),		/* File open mode: Read binary. */
103 /* 37 */ dkT("/rand/types"),	/* Preference name for allowed PRNG types. */
104 /* 38 */ dkT(".rnd-simple"),	/* Preference name for simple seed file. */
105 /* 39 */ dkT(".rnd-lrand48"),	/* Preference name for lrand48() seed file. */
106 /* 40 */ dkT(".rnd-random"),	/* Preference name for random() seed file. */
107 /* 41 */ dkT(".rnd-openssl"),	/* Preference name for OpenSSL seed file. */
108 /* 42 */ dkT("/rand/egd/name"),	/* Preference name for EGD socket. */
109 /* 43 */ dkT("EGDSOCKET"),	/* Environment variable name for EGD socket. */
110 /* 44 */ dkT("/dev/urandom"),	/* Device name for seed data. */
111 /* 45 */ dkT("/dev/random"),	/* Device name for seed data. */
112 /* 46 */ dkT("/rand/file/allowed"),	/* Preference name. */
113 /* 47 */ dkT("en"),		/* Default language name. */
114 #if 0
115 /* 48 */ dkT("/dir/uc2lat-t"),	/* Preference name for LaTeX encoding. */
116 #else
117 /* 48 */ dkT("/dir/charmap"),	/* Preference name for LaTeX encoding. */
118 #endif
119 /* 49 */
120 #if 0
121 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
122 dkT("\\uc2lat-t"),
123 #else
124 dkT("/uc2lat-t"),
125 #endif
126 #else
127 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
128 dkT("\\dktools\\charmap"),	/* Character map subdirectory of share. */
129 #else
130 dkT("/dktools/charmap"),		/* Character map subdirectory of share. */
131 #endif
132 #endif
133 /* 50 */ dkT("/silent"),	/* Preference name for silent work. */
134 /* 51 */ dkT("/input/encoding/file"),	/* Preference name. */
135 /* 52 */ dkT("/input/encoding/stdin"),	/* Preference name. */
136 /* 53 */ dkT("wb"),		/* File open mode: Read binary. */
137 /* 54 */ dkT(".dir"),		/* Suffix for uc2lat *.dir files. */
138 /* 55 */ dkT(".lat"),		/* Suffix for uc2lat *.lat files. */
139 /* 56 */ dkT("sbin"),		/* sbin dirctory. */
140 };
141 
142 
143 
144 /**	Directories where binary executable can reside.
145 */
146 static dkChar const * const	dk3app_bindir_candidates[] = {
147 /* 0 */
148 dkT("bin"),
149 
150 /* 1 */
151 dkT("sbin"),
152 
153 /* 2 */
154 dkT("lib"),
155 
156 /* 3 */
157 dkT("libexec"),
158 
159 NULL
160 
161 };
162 
163 
164 
165 /**	Keywords for users configuration files.
166 	These keywords can be used in the $HOME/.dk3app/dk3conf.conf file.
167 */
168 dkChar const * const dk3app_conf_file[] = {
169 /*  0 */ dkT("use-system-config-files"),
170 /*  1 */ dkT("ignore-system-config-files"),
171 NULL
172 };
173 
174 
175 /**	Log level names.
176 */
177 static dkChar const * const dk3app_log_levels[] = {
178 dkT("n$one"),
179 dkT("pa$nic"),
180 dkT("f$atal"),
181 dkT("e$rror"),
182 dkT("w$arning"),
183 dkT("in$fo"),
184 dkT("pr$ogress"),
185 dkT("d$ebug"),
186 dkT("ig$nore"),
187 NULL
188 };
189 
190 #if 0
191 static dkChar const * const dk3app_prng_type_names[] = {
192 /*  0 */ dkT("openssl"),	/* OpenSSL PRNG. */
193 /*  1 */ dkT("random"),		/* initstate()/setstate()/random() */
194 /*  2 */ dkT("rand48"),		/* lrand48(). */
195 /*  3 */ dkT("simple"),		/* srand()/rand(). */
196 NULL
197 };
198 #endif
199 
200 
201 
202 /**	Text strings, localization needed.
203 The texts strings are used as parts of diagnostic messages.
204 */
205 static dkChar const * const dk3app_kw[] = {
206 /* 0 */
207 dkT("\n"),
208 
209 /* 1 */
210 dkT("PANIC"),
211 
212 /* 2 */
213 dkT("FATAL"),
214 
215 /* 3 */
216 dkT("ERROR"),
217 
218 /* 4 */
219 dkT("Warning"),
220 
221 /* 5 */
222 dkT("Information"),
223 
224 /* 6 */
225 dkT("Progress"),
226 
227 /* 7 */
228 dkT("Debug"),
229 
230 /* 8 */
231 dkT(" "),
232 
233 /* 9 */
234 dkT("Not enough memory (RAM/swap space)!"),
235 
236 /* 10 */
237 dkT("# "),
238 
239 /* 11 */
240 dkT(":"),
241 
242 /* 12 */
243 dkT("Memory allocation ("),
244 
245 /* 13 */
246 dkT(" bytes) failed!"),
247 
248 /* 14 */
249 dkT("Memory allocation failed!"),
250 
251 /* 15 */
252 dkT("Numeric overflow in size calculation!"),
253 
254 /* 16 */
255 dkT("Numeric overflow in size calculation ("),
256 
257 /* 17 */
258 dkT(" x "),
259 
260 /* 18 */
261 dkT(" bytes)!"),
262 
263 /* 19 */
264 dkT("Application \""),
265 
266 /* 20 */
267 dkT("\" started."),
268 
269 /* 21 */
270 dkT("Application \""),
271 
272 /* 22 */
273 dkT("\" finished."),
274 
275 /* 23 */
276 dkT("Application name:  "),
277 
278 /* 24 */
279 dkT("Application group: "),
280 
281 /* 25 */
282 dkT("Executable file:   "),
283 
284 /* 26 */
285 dkT("Directory \"bin\":   "),
286 
287 /* 27 */
288 dkT("Directory \"etc\":   "),
289 
290 /* 28 */
291 dkT("Directory \"share\": "),
292 
293 /* 29 */
294 dkT("Directory \"var\":   "),
295 
296 /* 30 */
297 dkT("Directory \"home\":  "),
298 
299 /* 31 */
300 dkT("Directory \"temp\":  "),
301 
302 /* 32 */
303 dkT("User:              "),
304 
305 /* 33 */
306 dkT("Log file:          "),
307 
308 /* 34 */
309 dkT("Language:          "),
310 
311 /* 35 */
312 dkT("Region:            "),
313 
314 /* 36 */
315 dkT("<unknown>"),
316 
317 /* 37 */
318 dkT("The name of the temporary directory is too long!"),
319 
320 /* 38 */
321 dkT("Destination buffer too small!"),
322 
323 /* 39 */
324 dkT("The LANG environment variable is too long!"),
325 
326 /* 40 */
327 dkT("Failed to find name of executable file!"),
328 
329 /* 41 */
330 dkT("Too few directories in hierarchy!\nExecutable files should not reside in the root directory!"),
331 
332 /* 42 */
333 dkT("File name of executable file too long!"),
334 
335 /* 43 */
336 dkT("Failed to obtain the users login name!"),
337 
338 /* 44 */
339 dkT("Failed to find the users home directory!"),
340 
341 /* 45 */
342 dkT("File name for log file gets too long!"),
343 
344 /* 46 */
345 dkT("Failed to create directory for log file!"),
346 
347 /* 47 */
348 dkT("Failed to convert process ID to text!"),
349 
350 /* 48 */
351 dkT("Failed to find application name!"),
352 
353 /* 49 */
354 dkT("The name of the temporary directory is too long!"),
355 
356 /* 50 */
357 dkT("Failed to find local state (var) directory!"),
358 
359 /* 51 */
360 dkT("Preference name too long!"),
361 
362 /* 52 */
363 dkT("Malformed preference entry on command line!"),
364 
365 /* 53 */
366 dkT("Failed to find current working directory!"),
367 
368 /* 54 */
369 dkT("Too many requests for temporary file names!"),
370 
371 /* 55 */
372 dkT("Internal error (bug): Missing a file or directory name!"),
373 
374 /* 56 */
375 dkT("Failed to save preference entry \""),
376 
377 /* 57 */
378 dkT("\"=\""),
379 
380 /* 58 */
381 dkT("\"!"),
382 
383 /* 59 */
384 dkT("Directory name \""),
385 
386 /* 60 */
387 dkT("\" too long!"),
388 
389 /* 61 */
390 dkT("Failed to obtain information about \""),
391 
392 /* 62 */
393 dkT("\"!\nThe stat() function failed!"),
394 
395 /* 63 */
396 dkT("Failed to read directory \""),
397 
398 /* 64 */
399 dkT("\"!"),
400 
401 /* 65 */
402 dkT("File name \""),
403 
404 /* 66 */
405 dkT("\" too long!"),
406 
407 /* 67 */
408 dkT("Illegal characters in source string, conversion failed!"),
409 
410 /* 68 */
411 dkT("Failed to remove directory!"),
412 
413 /* 69 */
414 dkT("Failed to remove directory \""),
415 
416 /* 70 */
417 dkT("\"!"),
418 
419 /* 71 */
420 dkT("The HOMEDRIVE environment variable is not set!"),
421 
422 /* 72 */
423 dkT("The HOMEPATH environment variable is not set!"),
424 
425 /* 73 */
426 dkT("Failed to obtain information about a file!"),
427 
428 /* 74 */
429 dkT("\""),
430 
431 /* 75 */
432 dkT("\" is a directory!"),
433 
434 /* 76 */
435 dkT("Can not open file, name refers to a directory!"),
436 
437 /* 77 */
438 dkT("Failed to open file \""),
439 
440 /* 78 */
441 dkT("\" for write access!"),
442 
443 /* 79 */
444 dkT("Failed to open file for write access!"),
445 
446 /* 80 */
447 dkT("Failed to obtain current time!"),
448 
449 /* 81 */
450 dkT("File \""),
451 
452 /* 82 */
453 dkT("\" exists but is not a directory!"),
454 
455 /* 83 */
456 dkT("File exists but is not a directory!"),
457 
458 /* 84 */
459 dkT("Failed to create directory \""),
460 
461 /* 85 */
462 dkT("\"!"),
463 
464 /* 86 */
465 dkT("Failed to create directory!"),
466 
467 /* 87 */
468 dkT("Directory name too long!"),
469 
470 /* 88 */
471 dkT("Failed to remove file \""),
472 
473 /* 89 */
474 dkT("\"!"),
475 
476 /* 90 */
477 dkT("Failed to remove file!"),
478 
479 /* 91 */
480 dkT("No user name entry in user record!"),
481 
482 /* 92 */
483 dkT("No user record for \""),
484 
485 /* 93 */
486 dkT("\"!"),
487 
488 /* 94 */
489 dkT("No matching user record found!"),
490 
491 /* 95 */
492 dkT("No home directory entry in user record!"),
493 
494 /* 96 */
495 dkT("Failed to obtain information about \""),
496 
497 /* 97 */
498 dkT("\"!\nThe lstat() function failed!"),
499 
500 /* 98 */
501 dkT("No information about a file, lstat() failed!"),
502 
503 /* 99 */
504 dkT("No information about a file, lstat() failed!"),
505 
506 /* 100 */
507 dkT("Owner of symlink \""),
508 
509 /* 101 */
510 dkT("\" is not owner of file!"),
511 
512 /* 102 */
513 dkT("Symlink owner is not file owner!"),
514 
515 /* 103 */
516 dkT("Command \""),
517 
518 /* 104 */
519 dkT("\" is too long!"),
520 
521 /* 105 */
522 dkT("Command is too long!"),
523 
524 /* 106 */
525 dkT("The PATH environment variable is not defined!"),
526 
527 /* 107 */
528 dkT("No mkdir() function available!"),
529 
530 /* 108 */
531 dkT("String too long!"),
532 
533 /* 109 */
534 dkT("Command name too long!"),
535 
536 /* 110 */
537 dkT("Too many \"..\" entries in file name \""),
538 
539 /* 111 */
540 dkT("\"!"),
541 
542 /* 112 */
543 dkT("Illegal character(s) in source string!"),
544 
545 /* 113 */
546 dkT("Illegal character(s) in source buffer!"),
547 
548 /* 114 */
549 dkT("Illegal destination encoding!"),
550 
551 /* 115 */
552 dkT("Conversion to UTF-8 failed!"),
553 
554 /* 116 */
555 dkT("Conversion to UTF-16 failed!"),
556 
557 /* 117 */
558 dkT("Result character(s) not available for destination encoding!"),
559 
560 /* 118 */
561 dkT("UTF-8 decoding failed!"),
562 
563 /* 119 */
564 dkT("UTF-16 decoding failed!"),
565 
566 /* 120 */
567 dkT("Failed to write data!"),
568 
569 /* 121 */
570 dkT("Failed to flush output!"),
571 
572 /* 122 */
573 dkT("Failed to close data stream object!"),
574 
575 /* 123 */
576 dkT("Stream not opened for write operations!"),
577 
578 /* 124 */
579 dkT("Failed to read data!"),
580 
581 /* 125 */
582 dkT("Mismatch between encoding and character size!"),
583 
584 /* 126 */
585 dkT("Too many \"..\" entries in file name!"),
586 
587 /* 127 */
588 dkT("Unknown message digest type: \""),
589 
590 /* 128 */
591 dkT("\"!"),
592 
593 /* 129 */
594 dkT("Unknown encoding: \""),
595 
596 /* 130 */
597 dkT("\"!"),
598 
599 /* 131 */
600 dkT("Failed to find current host name!"),
601 
602 /* 132 */
603 dkT("Host:              "),
604 
605 /* 133 */
606 dkT("Option \""),
607 
608 /* 134 */
609 dkT("\" requires an argument!"),
610 
611 /* 135 */
612 dkT("Option \""),
613 
614 /* 136 */
615 dkT("\" too long for processing"),
616 
617 /* 137 */
618 dkT("Ignoring irrelevant argument in \""),
619 
620 /* 138 */
621 dkT("\"!"),
622 
623 /* 139 */
624 dkT("Unknown option \""),
625 
626 /* 140 */
627 dkT("\"!"),
628 
629 /* 141 */
630 dkT("Not a numeric value: \""),
631 
632 /* 142 */
633 dkT("\"!"),
634 
635 /* 143 */
636 dkT("Failed to open file \""),
637 
638 /* 144 */
639 dkT("\"!"),
640 
641 /* 145 */
642 dkT("Failed to open file!"),
643 
644 /* 146 */
645 dkT("Not a boolean value: \""),
646 
647 /* 147 */
648 dkT("\"!"),
649 
650 /* 148 */
651 dkT("Resource file \""),
652 
653 /* 149 */
654 dkT("\" found."),
655 
656 /* 150 */
657 dkT("Resource file \""),
658 
659 /* 151 */
660 dkT("\" not found."),
661 
662 /* 152 */
663 dkT("Configuration file \""),
664 
665 /* 153 */
666 dkT("\" found."),
667 
668 /* 154 */
669 dkT("Configuration file \""),
670 
671 /* 155 */
672 dkT("\" not found."),
673 
674 /* 156 */
675 dkT("No support for message digest \""),
676 
677 /* 157 */
678 dkT("\"!"),
679 
680 /* 158 */
681 dkT("Illegal message digest or encoding number!"),
682 
683 /* 159 */
684 dkT("Checksumming is available for regular files only!"),
685 
686 /* 160 */
687 dkT("Option name missing in long option: \""),
688 
689 /* 161 */
690 dkT("\"!"),
691 
692 /* 162 */
693 dkT("Failed to convert a numeric value to text!"),
694 
695 /* 163 */
696 dkT("\"!"),
697 
698 /* 164 */
699 dkT("Too many command line arguments! Ignoring \""),
700 
701 /* 165 */
702 dkT("\"...!"),
703 
704 /* 166 */
705 dkT("Internal error (bug) "),
706 
707 /* 167 */
708 dkT("."),
709 
710 /* 168 */
711 dkT("Too many file names match pattern \""),
712 
713 /* 169 */
714 dkT("\", just one allowed!"),
715 
716 /* 170 */
717 dkT("Write operation failed, "),
718 
719 /* 171 */
720 dkT(" of "),
721 
722 /* 172 */
723 dkT(" bytes written!"),
724 
725 /* 173 */
726 dkT("Write operation failed!"),
727 
728 /* 174 */
729 dkT("Write operation failed, "),
730 
731 /* 175 */
732 dkT(" of "),
733 
734 /* 176 */
735 dkT(" elements written!"),
736 
737 /* 177 */
738 dkT("Failed to create random data!"),
739 
740 /* 178 */
741 dkT("No usable PRNG found!"),
742 
743 /* 179 */
744 dkT("Failed to seed simple PRNG!"),
745 
746 /* 180 */
747 dkT("Failed to seed lrand48() PRNG!"),
748 
749 /* 181 */
750 dkT("Failed to seed random() PRNG!"),
751 
752 /* 182 */
753 dkT("Failed to seed OpenSSL PRNG!"),
754 
755 /* 183 */
756 dkT("Seed file \""),
757 
758 /* 184 */
759 dkT("\" not used (permissions)!"),
760 
761 /* 185 */
762 dkT("Seed file \""),
763 
764 /* 186 */
765 dkT("\" not used (symlink owner)!"),
766 
767 /* 187 */
768 dkT("Unknown PRNG type: \""),
769 
770 /* 188 */
771 dkT("\"!"),
772 
773 /* 189 */
774 dkT("The srand()/rand() PRNG is not available!"),
775 
776 /* 190 */
777 dkT("The srand48()/lrand48() PRNG is not available!"),
778 
779 /* 191 */
780 dkT("The random() PRNG is not available!"),
781 
782 /* 192 */
783 dkT("The OpenSSL PRNG is not available!"),
784 
785 /* 193 */
786 dkT("Failed to save random seed data!"),
787 
788 /* 194 */
789 dkT("HOME directory name too long!"),
790 
791 /* 195 */
792 dkT("System configuration files skipped by user."),
793 
794 /* 196 */
795 dkT("Attempt to obtain seed data from \""),
796 
797 /* 197 */
798 dkT("\"."),
799 
800 /* 198 */
801 dkT("Seed data: "),
802 
803 /* 199 */
804 dkT(" bytes found."),
805 
806 /* 200 */
807 dkT("Index out of range!"),
808 
809 /* 201 */
810 dkT("Matrix expansion requires a square matrix!"),
811 
812 /* 202 */
813 dkT("Not a directory: \""),
814 
815 /* 203 */
816 dkT("\"!"),
817 
818 /* 204 */
819 dkT("Encoding not supported by C runtime library!"),
820 
821 /* 205 */
822 dkT("No directory containing LaTeX encoding tables found!"),
823 
824 /* 206 */
825 dkT("Redefinition,\noverwriting \""),
826 
827 /* 207 */
828 dkT("\" by \""),
829 
830 /* 208 */
831 dkT("\"."),
832 
833 /* 209 */
834 dkT("Syntax error,\nindex "),
835 
836 /* 210 */
837 dkT(" is out of range 0...255."),
838 
839 /* 211 */
840 dkT("Syntax error\nnear \""),
841 
842 /* 212 */
843 dkT("\"!"),
844 
845 /* 213 */
846 dkT("Syntax error,\nmissing LaTeX encoding!"),
847 
848 /* 214 */
849 dkT("Syntax error,\nmissing index!"),
850 
851 /* 215 */
852 dkT("No file name matches pattern \""),
853 
854 /* 216 */
855 dkT("\"!"),
856 
857 /* 217 */
858 dkT("Missing name of long option!"),
859 
860 /* 218 */
861 dkT("Incomplete input sequence."),
862 
863 /* 219 */
864 dkT("String contains non-ISO-LATIN-1 characters!"),
865 
866 /* 220 */
867 dkT("Misconfigured start/end for range!"),
868 
869 /* 221 */
870 dkT("New range conflicts with existing one!"),
871 
872 /* 222 */
873 dkT("Not a hex number!"),
874 
875 /* 223 */
876 dkT("Syntax error!"),
877 
878 /* 224 */
879 dkT("Character redefinition!"),
880 
881 /* 225 */
882 dkT("Range not declared in character directory!"),
883 
884 /* 226 */
885 dkT("Package name conflicts with previous definition!"),
886 
887 /* 227 */
888 dkT("Attempt to obtain seed data from CryptoAPI."),
889 
890 /* 228 */
891 dkT("Attempt to obtain seed data from screen."),
892 
893 /* 229 */
894 dkT("OpenSSL PRNG seeded successfully."),
895 
896 /* 230 */
897 dkT("Attempt to read preferences file \""),
898 
899 /* 231 */
900 dkT("\"."),
901 
902 /* 232 */
903 dkT("LaTeX table directory: \""),
904 
905 /* 233 */
906 dkT("\"."),
907 
908 /* 234 */
909 dkT("Attempting LaTeX table directory: \""),
910 
911 /* 235 */
912 dkT("\"."),
913 
914 /* 236 */
915 dkT("Reading LaTeX table dir: \""),
916 
917 /* 237 */
918 dkT("\"."),
919 
920 /* 238 */
921 dkT("Registering LaTeX conversion range "),
922 
923 /* 239 */
924 dkT("."),
925 
926 /* 240 */
927 dkT("Loading LaTeX conversion data file \""),
928 
929 /* 241 */
930 dkT("\"."),
931 
932 /* 242 */
933 dkT("Failed to change into directory: \""),
934 
935 /* 243 */
936 dkT("\"!"),
937 
938 /* 244 */
939 dkT("Failed to enumerate printers!"),
940 
941 /* 245 */
942 dkT("Record too large!"),
943 
944 /* 246 */
945 dkT("File damaged or not a database file!"),
946 
947 /* 247 */
948 dkT("No support for database type \""),
949 
950 /* 248 */
951 dkT("\" available!"),
952 
953 /* 249 */
954 dkT("Key not found in database!"),
955 
956 /* 250 */
957 dkT("DB entry probably damaged - not a multibyte char string!"),
958 
959 /* 251 */
960 dkT("Database opened for read access only!"),
961 
962 /* 252 */
963 dkT("Error(s) occured while processing command line options!"),
964 
965 /* 253 */
966 dkT("Failed to retrieve current locale!"),
967 
968 /* 254 */
969 dkT("Current locale too long!"),
970 
971 /* 255 */
972 dkT("Not a regular file: \""),
973 
974 /* 256 */
975 dkT("\"!"),
976 
977 /* 257 */
978 dkT("Image file type unknown or not supported!"),
979 
980 /* 258 */
981 dkT("Bits per component restricted to 16!"),
982 
983 /* 259 */
984 dkT("Incorrect page setup, no usable space between borders!"),
985 
986 /* 260 */
987 dkT("Mathematical error in graphics calculations!"),
988 
989 /* 261 */
990 dkT("Failed to set bitmap image frame!"),
991 
992 /* 262 */
993 dkT("Flate compression not supported!"),
994 
995 /* 263 */
996 dkT("Illegal compression cell type used!"),
997 
998 /* 264 */
999 dkT("Error during previous compression operations!"),
1000 
1001 /* 265 */
1002 dkT("Failed to retrieve console settings!"),
1003 
1004 /* 266 */
1005 dkT("Failed to restore console settings!"),
1006 
1007 /* 267 */
1008 dkT("Failed to modify console settings!"),
1009 
1010 /* 268 */
1011 dkT("Failed to convert timestamp to local time!"),
1012 
1013 /* 269 */
1014 dkT("No file name available for database!"),
1015 
1016 /* 270 */
1017 dkT("Failed to change ownership for file:\n\""),
1018 
1019 /* 271 */
1020 dkT("\"!"),
1021 
1022 /* 272 */
1023 dkT("Failed to change permissions for file:\n\""),
1024 
1025 /* 273 */
1026 dkT("\"!"),
1027 
1028 /* 274 */
1029 dkT("Insufficient permissions to open network connection!"),
1030 
1031 /* 275 */
1032 dkT("Unknown or illegal address family!"),
1033 
1034 /* 276 */
1035 dkT("Process table overflow!"),
1036 
1037 /* 277 */
1038 dkT("Too many open files!"),
1039 
1040 /* 278 */
1041 dkT("Protocol not supported!"),
1042 
1043 /* 279 */
1044 dkT("Failed to open network socket!"),
1045 
1046 /* 280 */
1047 dkT("Failed to close socket!"),
1048 
1049 /* 281 */
1050 dkT("Interrupted by signal or explicitly cancelled!"),
1051 
1052 /* 282 */
1053 dkT("Failed to connect!"),
1054 
1055 /* 283 */
1056 dkT("Failed to listen for incoming requests!"),
1057 
1058 /* 284 */
1059 dkT("Failed to find IP address for:\n\""),
1060 
1061 /* 285 */
1062 dkT("\"!"),
1063 
1064 /* 286 */
1065 dkT("Host not found!"),
1066 
1067 /* 287 */
1068 dkT("Host exists, but no IP address assigned!"),
1069 
1070 /* 288 */
1071 dkT("Problem on DNS server!"),
1072 
1073 /* 289 */
1074 dkT("Temporary problem on DNS server, try again later!"),
1075 
1076 /* 290 */
1077 dkT("No gethostbyname() function available!"),
1078 
1079 /* 291 */
1080 dkT("Can not connect to remote port 0!"),
1081 
1082 /* 292 */
1083 dkT("Access denied by firewall or due to insufficient permissions!"),
1084 
1085 /* 293 */
1086 dkT("Local address already in use!"),
1087 
1088 /* 294 */
1089 dkT("Resources shortage, network operation failed!"),
1090 
1091 /* 295 */
1092 dkT("Previous connection attempt not yet completed!"),
1093 
1094 /* 296 */
1095 dkT("Connection refused, port not open on peer!"),
1096 
1097 /* 297 */
1098 dkT("Socket already connected!"),
1099 
1100 /* 298 */
1101 dkT("Network unreachable!"),
1102 
1103 /* 299 */
1104 dkT("Timeout occured."),
1105 
1106 /* 300 */
1107 dkT("No select() function available, timeout settings ignored!"),
1108 
1109 /* 301 */
1110 dkT("Failed to retrieve socket state!"),
1111 
1112 /* 302 */
1113 dkT("Failed to bind local address!"),
1114 
1115 /* 303 */
1116 dkT(""),
1117 
1118 /* 304 */
1119 dkT("Socket already bound to local address!"),
1120 
1121 /* 305 */
1122 dkT("Failed to write data to socket!"),
1123 
1124 /* 306 */
1125 dkT("Operation would block!"),
1126 
1127 /* 307 */
1128 dkT("Connection reset by peer!"),
1129 
1130 /* 308 */
1131 dkT("Peer address is required to send data via connectionless socket!"),
1132 
1133 /* 309 */
1134 dkT("Peer address specification is not allowed for connected sockets!"),
1135 
1136 /* 310 */
1137 dkT("Message too large to be sent atomically!"),
1138 
1139 /* 311 */
1140 dkT("Sending queue full for socket!"),
1141 
1142 /* 312 */
1143 dkT("Writing to a pipe without a reader!"),
1144 
1145 /* 313 */
1146 dkT("Less bytes were written than required!"),
1147 
1148 /* 314 */
1149 dkT("Failed to read data from socket!"),
1150 
1151 /* 315 */
1152 dkT("Failed to shut down socket!"),
1153 
1154 /* 316 */
1155 dkT("Socket not connected!"),
1156 
1157 /* 317 */
1158 dkT("Failed to accept incoming connection request!"),
1159 
1160 /* 318 */
1161 dkT("Connection aborted!"),
1162 
1163 /* 319 */
1164 dkT("Network protocol error!"),
1165 
1166 /* 320 */
1167 dkT("Network subsystem not available!"),
1168 
1169 /* 321 */
1170 dkT("Windows sockets not initialized!"),
1171 
1172 /* 322 */
1173 dkT("A blocking Winsock 1.1 operation is in progress!"),
1174 
1175 /* 323 */
1176 dkT("Socket type doesn't correspond to address family!"),
1177 
1178 /* 324 */
1179 dkT("Socket not configured for broadcasts!"),
1180 
1181 /* 325 */
1182 dkT("Requested address is not available!"),
1183 
1184 /* 326 */
1185 dkT("Host unreachable!"),
1186 
1187 /* 327 */
1188 dkT("Windows sockets version not available!"),
1189 
1190 /* 328 */
1191 dkT("Too many processes use Windows sockets at this time!"),
1192 
1193 /* 329 */
1194 dkT("I/O error occured!"),
1195 
1196 /* 330 */
1197 dkT("Too many symbolic links in path!"),
1198 
1199 /* 331 */
1200 dkT("Illegal pathname (missing a parent directory)!"),
1201 
1202 /* 332 */
1203 dkT("File system is mounted read-only!"),
1204 
1205 /* 333 */
1206 dkT("Stale NFS file handle!"),
1207 
1208 /* 334 */
1209 dkT("Server for remote file not available!"),
1210 
1211 /* 335 */
1212 dkT("No space left on device!"),
1213 
1214 /* 336 */
1215 dkT("Failed to wait for sockets to become ready!"),
1216 
1217 /* 337 */
1218 dkT("Failed to convert text address to address!"),
1219 
1220 /* 338 */
1221 dkT("Failed to find address for host!"),
1222 
1223 /* 339 */
1224 dkT("Failed to set socket options!"),
1225 
1226 /* 340 */
1227 dkT("Error while closing file!"),
1228 
1229 /* 341 */
1230 dkT("Error while closing file\n\""),
1231 
1232 /* 342 */
1233 dkT("\"!"),
1234 
1235 /* 343 */
1236 dkT("Failed to write data to file:\n\""),
1237 
1238 /* 344 */
1239 dkT("\"!"),
1240 
1241 /* 345 */
1242 dkT("Failed to read data from file!"),
1243 
1244 /* 346 */
1245 dkT("Failed to read data from file:\n\""),
1246 
1247 /* 347 */
1248 dkT("\"!"),
1249 
1250 /* 348 */
1251 dkT("Not an IP address: \""),
1252 
1253 /* 349 */
1254 dkT("\"!"),
1255 
1256 /* 350 */
1257 dkT("Not an IP address!"),
1258 
1259 /* 351 */
1260 dkT("Failed to connect to: \""),
1261 
1262 /* 352 */
1263 dkT("\"!"),
1264 
1265 /* 353 */
1266 dkT("No function available to check blocking/non-blocking state!"),
1267 
1268 /* 354 */
1269 dkT("Netmask is not a dotted IP address!"),
1270 
1271 /* 355 */
1272 dkT("Netmask is not a bit number!"),
1273 
1274 /* 356 */
1275 dkT("Netmask is not an IPv6 address!"),
1276 
1277 /* 357 */
1278 dkT("No name resolution available, please specify IP address!"),
1279 
1280 /* 358 */
1281 dkT("No select() function available!"),
1282 
1283 /* 359 */
1284 dkT("No valid socket found in set!"),
1285 
1286 /* 360 */
1287 dkT("Socket "),
1288 
1289 /* 361 */
1290 dkT(" connected to client: "),
1291 
1292 /* 362 */
1293 dkT("Connection from \""),
1294 
1295 /* 363 */
1296 dkT("\" rejected!"),
1297 
1298 /* 364 */
1299 dkT("Failed to create any listener socket for socket set!"),
1300 
1301 /* 365 */
1302 dkT("Preference value of /threads/max higher than number of cores!"),
1303 
1304 /* 366 */
1305 dkT("Failed to find unique file identifier for file\n\""),
1306 
1307 /* 367 */
1308 dkT("\"!"),
1309 
1310 /* 368 */
1311 dkT("Failed to find unique file identifier for a file!"),
1312 
1313 /* 369 */
1314 dkT("Preference \""),
1315 
1316 /* 370 */
1317 dkT("\" does not point to a directory!"),
1318 
1319 /* 371 */
1320 dkT(""),
1321 
1322 /* 372 */
1323 dkT("Socket "),
1324 
1325 /* 373 */
1326 dkT(" listening: "),
1327 
1328 /* 374 */
1329 dkT(""),
1330 
1331 /* 375 */
1332 dkT("Socket "),
1333 
1334 /* 376 */
1335 dkT(" connected:"),
1336 
1337 /* 377 */
1338 dkT(""),
1339 
1340 /* 378 */
1341 dkT("Multiple different font encodings required!"),
1342 
1343 /* 379 */
1344 dkT("Font encoding both required and denied: `"),
1345 
1346 /* 380 */
1347 dkT("'!"),
1348 
1349 /* 381 */
1350 dkT("Font encoding can be used: `"),
1351 
1352 /* 382 */
1353 dkT("'!"),
1354 
1355 /* 383 */
1356 dkT("The following font encoding can not be used: `"),
1357 
1358 /* 384 */
1359 dkT("'."),
1360 
1361 /* 385 */
1362 dkT("All font encodings denied!"),
1363 
1364 /* 386 */
1365 dkT("Too many entries on position "),
1366 
1367 /* 387 */
1368 dkT(" in text line:\n\""),
1369 
1370 /* 388 */
1371 dkT("\""),
1372 
1373 /* 389 */
1374 dkT("Unexpected end of text after backslash in text:\n\""),
1375 
1376 /* 390 */
1377 dkT("\""),
1378 
1379 /* 391 */
1380 dkT("UTF-8 decoding failed for string:\n\""),
1381 
1382 /* 392 */
1383 dkT("UTF-16 decoding failed for string:\n\""),
1384 
1385 /* 393 */
1386 dkT("Non-ANSI characters in string:\n\""),
1387 
1388 /* 394 */
1389 dkT("Non-URL characters in string:\n\""),
1390 
1391 /* 395 */
1392 dkT("Character 0x"),
1393 
1394 /* 396 */
1395 dkT("already defined!"),
1396 
1397 /* 397 */
1398 dkT("Character redefinition!"),
1399 
1400 /* 398 */
1401 dkT("First word is not a hexadecimal number!"),
1402 
1403 /* 399 */
1404 dkT("_UNUSED_"),
1405 
1406 /* 400 */
1407 dkT("No configuration data found for character!"),
1408 
1409 /* 401 */
1410 dkT("No support for zlib compression!"),
1411 
1412 /* 402 */
1413 dkT("No support for bzip2 compression!"),
1414 
1415 /* 403 */
1416 dkT("No data files found to process!"),
1417 
1418 /* 404 */
1419 dkT("Syntax error, unknown encoding!"),
1420 
1421 /* 405 */
1422 dkT("Syntax error, no package names found!"),
1423 
1424 /* 406 */
1425 dkT("Syntax error, missing value for attribute!"),
1426 
1427 /* 407 */
1428 dkT("Missing \"share\" directory!"),
1429 
1430 /* 408 */
1431 dkT("No data found for character!"),
1432 
1433 /* 409 */
1434 dkT("No data found for character 0x"),
1435 
1436 /* 410 */
1437 dkT("!"),
1438 
1439 /* 411 */
1440 dkT("Conflicting font encoding requirements!"),
1441 
1442 /* 412 */
1443 dkT("Failed to set buffer for file\n\""),
1444 
1445 /* 413 */
1446 dkT("\"!"),
1447 
1448 NULL
1449 
1450 };
1451 
1452 
1453 
1454 /**	Preferences entry.
1455 */
1456 typedef struct _dk3app_pref_t {
1457   dkChar const *k;	/**< Key (name). */
1458   dkChar const *v;	/**< Value. */
1459 } dk3app_pref_t;
1460 
1461 
1462 
1463 /**	Message catalog.
1464 */
1465 typedef struct _dk3app_mc_t_ {
1466   dkChar const		*n;	/**< Name (always dynamically allocated). */
1467   dkChar const		**msg;	/**< Message texts. */
1468   int			f;	/**< Flag: Messages dynamically allocated. */
1469   size_t		nmsg;	/**< Number of messages. */
1470 } dk3app_mc_t;
1471 
1472 
1473 
1474 /**	Delete preferences entry, release memory.
1475 	@param	p	Preference entry to delete.
1476 */
1477 static
1478 void
dk3app_pref_delete(dk3app_pref_t * p)1479 dk3app_pref_delete(dk3app_pref_t *p)
1480 {
1481   if(p) {
1482     dk3_release(p->k);
1483     dk3_release(p->v);
1484     dk3_delete(p);
1485   }
1486 }
1487 
1488 
1489 
1490 /**	Create new preferences entry, allocate memory.
1491 	@param	k	Key (preference name).
1492 	@param	v	Value.
1493 	@return	Pointer to new entry on success, NULL on error.
1494 */
1495 static
1496 dk3app_pref_t *
dk3app_pref_new(dkChar const * k,dkChar const * v)1497 dk3app_pref_new(dkChar const *k, dkChar const *v)
1498 {
1499   dk3app_pref_t *back = NULL;
1500 
1501   if((k) && (v)) {
1502     back = dk3_new(dk3app_pref_t,1);
1503     if(back) {
1504       back->k = dk3str_dup_app(k, NULL);
1505       back->v = dk3str_dup_app(v, NULL);
1506       if(!((back->k) && (back->v))) {
1507         dk3app_pref_delete(back); back = NULL;
1508       }
1509     }
1510   }
1511   return back;
1512 }
1513 
1514 
1515 
1516 /**	Compare two preference entries by name.
1517 	@param	l	Left entry.
1518 	@param	r	Right entry.
1519 	@param	crit	Comparison criteria (ignored).
1520 	@return	Comparison result l <=> r.
1521 */
1522 static
1523 int
dk3app_compare_pref(void const * l,void const * r,int DK3_ARG_UNUSED (crit))1524 dk3app_compare_pref(void const *l, void const *r, int DK3_ARG_UNUSED(crit) )
1525 {
1526   int back = 0;
1527   dk3app_pref_t const *pl	= NULL;	/* Left object. */
1528   dk3app_pref_t const *pr	= NULL;	/* Right object. */
1529 
1530   DK3_UNUSED_ARG(crit)
1531   if(l) {
1532     if(r) {
1533       pl = (dk3app_pref_t const *)l; pr = (dk3app_pref_t const *)r;
1534       if(pl->k) {
1535         if(pr->k) {
1536 	  back = dk3str_cmp(pl->k, pr->k);
1537 	} else { back = 1; }
1538       } else {
1539         if(pr->k) { back = -1; }
1540       }
1541     } else { back = 1; }
1542   } else {
1543     if(r) { back = -1; }
1544   }
1545   return  back;
1546 }
1547 
1548 
1549 
1550 /**	Delete string table.
1551 	@param	ta	Table to delete.
1552 	@param	n	Number of entries in the table.
1553 */
1554 static
1555 void
dk3app_mc_table_delete(dkChar const ** ta,size_t n)1556 dk3app_mc_table_delete(dkChar const **ta, size_t n)
1557 {
1558   dkChar const	**ptr	= NULL;	/* Start of string table. */
1559   size_t	i	= 0;	/* Index of current element to process. */
1560 
1561   ptr = ta;
1562   for(i = 0; i < n; i++) {
1563     if(*ptr) {
1564       dk3_delete(*ptr);
1565     }
1566     *(ptr++) = NULL;
1567   }
1568   dk3_delete(ta);
1569 }
1570 
1571 
1572 
1573 /**	Delete message catalog entry.
1574 	@param	mc	Message catalog entry to delete.
1575 */
1576 static
1577 void
dk3app_mc_delete(dk3app_mc_t * mc)1578 dk3app_mc_delete(dk3app_mc_t *mc)
1579 {
1580 
1581   if(mc) {
1582     dk3_release(mc->n);
1583     if(mc->f) {
1584       if(mc->msg) {
1585         dk3app_mc_table_delete(mc->msg, mc->nmsg);
1586       }
1587     } mc->f = 0; mc->msg = NULL;
1588     dk3_delete(mc);
1589   }
1590 }
1591 
1592 
1593 
1594 /**	Create message catalog entry.
1595 	@param	n	Short file name of string table file.
1596 	@param	msg	String table.
1597 	@param	nmsg	Number of entries in \a msg.
1598 	@param	f	Flag: The memory for \a msg was dynamically allocated.
1599 	@param	app	Application structure for diagnostics, may be NULL.
1600 	@return	Pointer to message catalog entry on success, NULL on error.
1601 */
1602 static
1603 dk3app_mc_t *
dk3app_mc_new(dkChar const * n,dkChar const ** msg,size_t nmsg,int f,dk3_app_t * app)1604 dk3app_mc_new(
1605   dkChar const *n, dkChar const **msg, size_t nmsg, int f, dk3_app_t *app
1606 )
1607 {
1608   dk3app_mc_t *back = NULL;
1609 
1610   back = dk3_new_app(dk3app_mc_t,1,app);
1611   if(back) {
1612     back->n = NULL; back->msg = NULL; back->f = f; back->nmsg = nmsg;
1613     back->n = dk3str_dup_app(n, app);
1614     if(back->n) {
1615       back->msg = msg;
1616     } else {
1617       dk3app_mc_delete(back); back = NULL;
1618     }
1619   }
1620   return back;
1621 }
1622 
1623 
1624 
1625 /**	Compare two message catalog entries.
1626 	@param	l	Left entry.
1627 	@param	r	Right entry.
1628 	@param	cr	Comparison criteria (ignored).
1629 	@return	Comparison result.
1630 */
1631 static
1632 int
dk3app_mc_compare(void const * l,void const * r,int DK3_ARG_UNUSED (cr))1633 dk3app_mc_compare(void const *l, void const *r, int DK3_ARG_UNUSED(cr) )
1634 {
1635   int back = 0;
1636   dk3app_mc_t const	*pl	= NULL;	/* Left message catalog. */
1637   dk3app_mc_t const	*pr	= NULL;	/* Right message catalog. */
1638 
1639   DK3_UNUSED_ARG(cr)
1640   if(l) {
1641     if(r) {
1642       pl = (dk3app_mc_t const *)l; pr = (dk3app_mc_t const *)r;
1643       if(pl->n) {
1644         if(pr->n) {
1645 	  back = dk3str_cmp(pl->n, pr->n);
1646 	} else { back =  1; }
1647       } else {
1648         if(pr->n) { back = -1; }
1649       }
1650     } else { back =  1; }
1651   } else {
1652     if(r)  { back = -1; }
1653   }
1654   return back;
1655 }
1656 
1657 
1658 
1659 /**	Write log message to a file.
1660 	If the time has changed since the last message written to that
1661 	file we write a new timestamp before writing the message.
1662 	@param	app	Application structure.
1663 	@param	ll	Log level, DK3_LL_xxx.
1664 	@param	msg	Array of message parts.
1665 	@param	nmsg	Number of elements in \a msg.
1666 	@param	fipo	File to write to.
1667 	@param	last_time	Timestamp of last message written to that file.
1668 */
1669 static
1670 void
dk3app_log_to_file(dk3_app_t * app,int ll,dkChar const * const * msg,size_t nmsg,FILE * fipo,dk3_time_t * last_time)1671 dk3app_log_to_file(
1672   dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg,
1673   FILE *fipo, dk3_time_t *last_time
1674 )
1675 {
1676   dk3_time_t	time_now;	/* Current time. */
1677   dkChar	tb[64];		/* Buffer to store current time as text. */
1678   char		ulb[64];	/* Buffer for current time as char text. */
1679   char		*sp	= NULL;	/* Source pointer used in conversion. */
1680   size_t	i	= 0;	/* Index of current string to process. */
1681 
1682   if(dk3sf_time(&time_now)) {
1683     if(time_now != *last_time) {
1684       if(dk3sf_time_convert_app(tb, DK3_SIZEOF(tb,dkChar), &time_now, NULL)) {
1685         *last_time = time_now;
1686 	dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[10], fipo);
1687 	dk3sf_fputs(tb, fipo);
1688 	dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[0], fipo);
1689       }
1690     }
1691   }
1692   if(app->n_sourcefile) {
1693     dk3sf_fputs(app->n_sourcefile, fipo);
1694     dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo);
1695     if(app->sourceline) {
1696       sprintf(ulb, "%lu", app->sourceline);
1697       sp = ulb;
1698       while(*sp) { dk3sf_fputc( (dkChar)(*(sp++)), fipo); }
1699       dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo);
1700     }
1701     dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[8], fipo);
1702   }
1703   if((ll >= DK3_LL_PANIC) && (ll <= DK3_LL_WARNING)) {
1704     dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[ll], fipo);
1705     dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[11], fipo);
1706     dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[8], fipo);
1707   }
1708   for(i = 0; i < nmsg; i++) {
1709     if(msg[i]) {
1710       dk3sf_fputs(msg[i], fipo);
1711     }
1712   }
1713   dk3sf_fputs(((app->msg) ? app->msg : dk3app_kw)[0], fipo);
1714 }
1715 
1716 
1717 
1718 static
1719 void
dk3app_create_parent_directory(const dkChar * fn)1720 dk3app_create_parent_directory(const dkChar *fn)
1721 {
1722   dkChar	 fnb[DK3_MAX_PATH];
1723   dkChar	*ptr;
1724   dkChar	*lptr;
1725 
1726   if (dk3str_len(fn) < DK3_SIZEOF(fnb,dkChar)) {
1727     dk3str_cpy_not_overlapped(fnb, fn);
1728     ptr= fnb; lptr = NULL;
1729     while (dkT('\0') != *ptr) {
1730 #if DK3_ON_WINDOWS || DK3_HAVE_BACKSLASH
1731       if (dkT('\\') == *ptr) { lptr = ptr; }
1732 #else
1733       if (dkT('/')  == *ptr) { lptr = ptr; }
1734 #endif
1735       ptr++;
1736     }
1737     if (NULL != lptr) {
1738       *lptr = dkT('\0');
1739       (void)dk3sf_mkdir_app(fnb, 0700, NULL);
1740     }
1741   }
1742 }
1743 
1744 
1745 
1746 /**	Create ${HOME}/log directory for known log file name.
1747 	@param	app	Application structure containing log file
1748 			name in n_logfilename.
1749 */
1750 static
1751 void
dk3app_create_log_directory(dk3_app_t * app)1752 dk3app_create_log_directory(dk3_app_t *app)
1753 {
1754   dk3app_create_parent_directory(app->n_logfilename);
1755 }
1756 
1757 
1758 
1759 /**	Create ${HOME}/tmp directory for known log file name.
1760 	@param	app	Application structure containing log file
1761 			name in n_logfilename.
1762 */
1763 static
1764 void
dk3app_create_tmp_directory(dk3_app_t * app)1765 dk3app_create_tmp_directory(dk3_app_t *app)
1766 {
1767   dk3app_create_parent_directory(app->n_tmpdir);
1768 }
1769 
1770 
1771 
1772 /**	Write log message to log file.
1773 	If the time has changed since the last message written to that
1774 	file we write a new timestamp before writing the message.
1775 	@param	app	Application structure.
1776 	@param	ll	Log level, DK3_LL_xxx.
1777 	@param	msg	Array of message parts.
1778 	@param	nmsg	Number of elements in \a msg.
1779 */
1780 static
1781 void
dk3app_log_file(dk3_app_t * app,int ll,dkChar const * const * msg,size_t nmsg)1782 dk3app_log_file(dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg)
1783 {
1784   FILE *fipo;				/* Output file. */
1785   dk3_stat_t	stb;			/* File stat buffer. */
1786 
1787   if(app->n_logfilename) {
1788     if (0 == app->cr_log) {
1789       /*
1790 	Create ${HOME}/log directory if not yet done.
1791       */
1792       dk3app_create_log_directory(app);
1793       app->cr_log = 1;
1794     }
1795     if(app->f_first_file_log) {
1796       /*
1797 	Daemons always attempt to append after existing log.
1798       */
1799       if(app->app_type == DK3_APP_TYPE_DAEMON) {
1800         app->f_first_file_log  = 0;
1801 	if(!dk3sf_stat_app(&stb, app->n_logfilename, NULL)) {
1802 	  app->f_first_file_log = 1;
1803 	}
1804       }
1805     }
1806     fipo = dk3sf_fopen_app(app->n_logfilename, dk3app_no_loc[8], NULL);
1807     /* WRITE */
1808     if(fipo) {
1809 #if DK3_ON_WINDOWS && (DK3_CHAR_SIZE > 1)
1810       /* Switch to 16 bit characters. */
1811 #if defined(_MSC_VER)
1812       (void)_setmode(_fileno(fipo), _O_U16TEXT);
1813 #endif
1814       /* Write byte order marker. */
1815       if(app->f_first_file_log) {
1816         fputwc(0xFEFF, fipo);
1817       }
1818 #endif
1819       app->f_first_file_log = 0;
1820       dk3app_log_to_file(
1821         app, ll, msg, nmsg, fipo, &(app->t_last_log_file)
1822       );
1823       fclose(fipo);
1824     } else {
1825     }
1826   }
1827 }
1828 
1829 
1830 
1831 int
dk3app_max_log_level(dk3_app_t const * app)1832 dk3app_max_log_level(dk3_app_t const *app)
1833 {
1834   int back = 0;
1835   if(app) {
1836     if(app->app_type != DK3_APP_TYPE_SILENT) {
1837       back = app->ll_file;
1838       if(app->app_type == DK3_APP_TYPE_COMMAND) {
1839         if(app->ll_stderr > back) {
1840           back = app->ll_stderr;
1841         }
1842       }
1843     }
1844   }
1845   return back;
1846 }
1847 
1848 void
dk3app_log_msg(dk3_app_t * app,int ll,dkChar const * const * msg,size_t nmsg)1849 dk3app_log_msg(dk3_app_t *app, int ll, dkChar const * const * msg, size_t nmsg)
1850 {
1851 
1852   if((app) && (msg) && (nmsg)) {
1853     if(app->f_readytolog) {
1854       if(ll < app->ll_highest) {
1855         app->ll_highest = ll;
1856       }
1857       switch(app->app_type) {
1858         case DK3_APP_TYPE_COMMAND: {
1859           if(app->ll_file >= ll) {
1860 	    dk3app_log_file(app, ll, msg, nmsg);
1861 	  } else {
1862 	  }
1863 	  if(app->ll_stderr >= ll) {
1864 	    dk3sf_initialize_stderr();
1865 	    dk3app_log_to_file(
1866 	      app, ll, msg, nmsg, stderr, &(app->t_last_log_stderr)
1867 	    );
1868 	  } else {
1869 	  }
1870         } break;
1871         case DK3_APP_TYPE_GUI:
1872         case DK3_APP_TYPE_DAEMON:
1873         {
1874           if(app->ll_file >= ll) {
1875 	    dk3app_log_file(app, ll, msg, nmsg);
1876 	  }
1877         } break;
1878       }
1879     } else {
1880     }
1881   } else {
1882   }
1883 }
1884 
1885 
1886 
1887 void
dk3app_log_1(dk3_app_t * app,int ll,dkChar const * const * msg,size_t i1)1888 dk3app_log_1(dk3_app_t *app, int ll, dkChar const * const * msg, size_t i1)
1889 {
1890   dkChar const *m[2];	/* Message parts. */
1891 
1892   if((app) && (msg)) {
1893     m[0] = msg[i1];
1894     m[1] = NULL;
1895     dk3app_log_msg(app, ll, (dkChar const * const *)m, 1);
1896   }
1897 }
1898 
1899 
1900 
1901 void
dk3app_log_2(dk3_app_t * app,int ll,dkChar const * const * msg,size_t i,dkChar const * st)1902 dk3app_log_2(
1903   dk3_app_t *app, int ll, dkChar const * const * msg,
1904   size_t i, dkChar const *st
1905 )
1906 {
1907   dkChar const	*m[3];
1908   if((app) && (msg)) {
1909     m[0] = msg[i];
1910     m[1] = st;
1911     m[2] = NULL;
1912     dk3app_log_msg(app, ll, (dkChar const * const *)m, 2);
1913   }
1914 }
1915 
1916 
1917 void
dk3app_log_3(dk3_app_t * app,int ll,dkChar const * const * msg,size_t i1,size_t i2,dkChar const * st)1918 dk3app_log_3(
1919   dk3_app_t *app, int ll, dkChar const * const * msg,
1920   size_t i1, size_t i2, dkChar const *st
1921 )
1922 {
1923   dkChar const *m[4];	/* Message parts. */
1924 
1925   if((app) && (msg)) {
1926     m[0] = msg[i1];
1927     m[1] = st;
1928     m[2] = msg[i2];
1929     m[3] = NULL;
1930     dk3app_log_msg(app, ll, (dkChar const * const *)m, 3);
1931   }
1932 }
1933 
1934 
1935 
1936 void
dk3app_log_5(dk3_app_t * app,int ll,dkChar const * const * msg,size_t i1,size_t i2,size_t i3,dkChar const * st1,dkChar const * st2)1937 dk3app_log_5(
1938   dk3_app_t *app, int ll, dkChar const * const * msg,
1939   size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2
1940 )
1941 {
1942   dkChar const *m[6];	/* Message parts. */
1943 
1944   if((app) && (msg)) {
1945     m[0] = msg[i1];
1946     m[1] = st1;
1947     m[2] = msg[i2];
1948     m[3] = st2;
1949     m[4] = msg[i3];
1950     m[5] = NULL;
1951     dk3app_log_msg(app, ll, (dkChar const * const *)m, 5);
1952   }
1953 }
1954 
1955 
1956 
1957 void
dk3app_log_i1(dk3_app_t * app,int ll,size_t i1)1958 dk3app_log_i1(dk3_app_t *app, int ll, size_t i1)
1959 {
1960 
1961   if(app) {
1962     dk3app_log_1(app, ll, ((app->msg) ? app->msg : dk3app_kw), i1);
1963   }
1964 }
1965 
1966 
1967 
1968 void
dk3app_log_i2(dk3_app_t * app,int ll,size_t i,dkChar const * st)1969 dk3app_log_i2(dk3_app_t *app, int ll, size_t i, dkChar const * st)
1970 {
1971   dkChar const *msg[3];		/* Message parts. */
1972 
1973   if((app) && (i) && (st)) {
1974     if(i < DK3_SIZEOF(dk3app_kw,DK3_PCDKCHAR)) {
1975       msg[0] = ((app->msg) ? app->msg : dk3app_kw)[i];
1976       msg[1] = st;
1977       msg[2] = NULL;
1978       dk3app_log_msg(app, ll, (dkChar const * const *)msg, 2);
1979     }
1980   }
1981 }
1982 
1983 
1984 
1985 void
dk3app_log_i3(dk3_app_t * app,int ll,size_t i1,size_t i2,dkChar const * st)1986 dk3app_log_i3(
1987   dk3_app_t *app, int ll,
1988   size_t i1, size_t i2, dkChar const *st
1989 )
1990 {
1991 
1992   if(app) {
1993     dk3app_log_3(app, ll, ((app->msg) ? app->msg : dk3app_kw), i1, i2, st);
1994   }
1995 }
1996 
1997 
1998 
1999 void
dk3app_log_i5(dk3_app_t * app,int ll,size_t i1,size_t i2,size_t i3,dkChar const * st1,dkChar const * st2)2000 dk3app_log_i5(
2001   dk3_app_t *app, int ll,
2002   size_t i1, size_t i2, size_t i3, dkChar const *st1, dkChar const *st2
2003 )
2004 {
2005 
2006   if(app) {
2007     dk3app_log_5(
2008       app, ll, ((app->msg) ? app->msg : dk3app_kw), i1, i2, i3, st1, st2
2009     );
2010   }
2011 }
2012 
2013 
2014 
2015 void
dk3app_set_source_file(dk3_app_t * app,dkChar const * fn)2016 dk3app_set_source_file(dk3_app_t *app, dkChar const *fn)
2017 {
2018   if(app) {
2019     app->n_sourcefile = fn;
2020   }
2021 }
2022 
2023 
2024 
2025 void
dk3app_set_source_line(dk3_app_t * app,unsigned long li)2026 dk3app_set_source_line(dk3_app_t *app, unsigned long li)
2027 {
2028   if(app) {
2029     app->sourceline = li;
2030   }
2031 }
2032 
2033 
2034 
2035 dkChar const *
dk3app_get_source_file(dk3_app_t const * app)2036 dk3app_get_source_file(dk3_app_t const *app)
2037 {
2038   dkChar const *back = NULL;
2039   if(app) {
2040     back = app->n_sourcefile;
2041   }
2042   return back;
2043 }
2044 
2045 
2046 
2047 unsigned long
dk3app_get_source_line(dk3_app_t const * app)2048 dk3app_get_source_line(dk3_app_t const *app)
2049 {
2050   unsigned long back = 0UL;
2051   if(app) {
2052     back = app->sourceline;
2053   }
2054   return back;
2055 }
2056 
2057 
2058 
2059 /**	Find data (resource) file.
2060 	String tables are resources too, so we check language and
2061 	region subdirectories too.
2062 	@param	app	Application structure.
2063 	@param	fn	File name.
2064 	@param	db	Destination buffer.
2065 	@param	sz	Size of \a db (number of characters).
2066 	@param	verb	Flag: Diagnostic messages enabled.
2067 	@return	1 on success, 0 on error.
2068 */
2069 static
2070 int
dk3app_my_find_data_file(dk3_app_t * app,dkChar const * fn,dkChar * db,size_t sz,int verb)2071 dk3app_my_find_data_file(
2072   dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int verb
2073 )
2074 {
2075   int back = 0;
2076   dkChar const	*p1 = NULL;	/* dk3app, group or application name. */
2077   dkChar const	*p2 = NULL;	/* Language. */
2078   dkChar const	*p3 = NULL;	/* Region. */
2079   int		 cc = 1;	/* Flag: Can go. */
2080   size_t	 mysz = 0;	/* Size for calculation. */
2081   size_t	 sz1 = 0;	/* Length of /xxx/share directory name. */
2082   size_t	 sz2 = 0;	/* Length of short file name. */
2083   dk3_stat_t	 stb;		/* Stat buffer to test existance of files. */
2084   int		 i = 0;		/* Pass: 0=lang+region, 1=language, 0=share. */
2085   int		 j = 0;		/* Pass: 0=app, 1=appgroup, 2=dk3app, 3=base. */
2086 
2087   if((app) && (fn) && (db) && (sz)) {
2088     if(app->n_sharedir) {
2089       sz1 = dk3str_len(app->n_sharedir);
2090       sz2 = dk3str_len(fn);
2091       for(i = 0; ((back == 0) && (i < 4)); i++) {
2092         for(j = 0; ((back == 0) && (j < 4)); j++) {
2093 	  p1 = NULL; p2 = NULL; p3 = NULL; cc = 0;
2094 	  switch(i) {
2095 	    case 1: {
2096 	      if(app->n_language) {
2097 	        p2 = app->n_language; cc = 1;
2098 	      }
2099 	    } break;
2100 	    case 2: {
2101 	      p2 = dk3app_no_loc[47]; cc = 1;
2102 	    } break;
2103 	    case 3: {
2104 	      cc = 1;
2105 	    } break;
2106 	    default: {
2107 	      if(app->n_language) {
2108 	        p2 = app->n_language;
2109 		if(app->n_region) {
2110 		  p3 = app->n_region; cc = 1;
2111 		}
2112 	      }
2113 	    } break;
2114 	  }
2115 	  switch(j) {
2116 	    case 1: {
2117 	      if(app->n_appgroup) {
2118 	        p1 = app->n_appgroup;
2119 	      } else {
2120 	        cc = 0;
2121 	      }
2122 	    } break;
2123 	    case 2: {
2124 	      p1 = dk3app_no_loc[17];
2125 	    } break;
2126 	    case 3: {
2127 	      p1 = NULL;
2128 	    } break;
2129 	    default: {
2130 	      if(app->n_app) {
2131 	        p1 = app->n_app;
2132 	      } else {
2133 	        cc = 0;
2134 	      }
2135 	    } break;
2136 	  }
2137 	  if(cc) {
2138 	    mysz = sz1 + sz2 + 1;
2139 	    if(p1) { mysz += dk3str_len(p1); mysz++; }
2140 	    if(p2) { mysz += dk3str_len(p2); mysz++; }
2141 	    if(p3) { mysz += dk3str_len(p3); mysz++; }
2142 	    if(mysz < sz) {
2143 	      dk3str_cpy_not_overlapped(db, app->n_sharedir);
2144 	      if(p1) {
2145 	        dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p1);
2146 	      }
2147 	      if(p2) {
2148 	        dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p2);
2149 	      }
2150 	      if(p3) {
2151 	        dk3str_cat(db, dk3app_no_loc[20]); dk3str_cat(db, p3);
2152 	      }
2153 	      dk3str_cat(db, dk3app_no_loc[20]);
2154 	      dk3str_cat(db, fn);
2155 	      if(dk3sf_stat_app(&stb, db, NULL)) {
2156 		switch((stb.ft) & (~(DK3_FT_SYMLINK))) {
2157 		  case DK3_FT_REGULAR: {
2158 		    back = 1;
2159 		  } break;
2160 		}
2161 	      }
2162 	      if(back) {
2163 	        /* DEBUG: Resource file ... found. */
2164 		dk3app_log_i3(app, DK3_LL_DEBUG, 148, 149, db);
2165 	      } else {
2166 	        /* DEBUG: Resource file ... not found. */
2167 		dk3app_log_i3(app, DK3_LL_DEBUG, 150, 151, db);
2168 	      }
2169 	    }
2170 	  }
2171 	}
2172       }
2173     } else {
2174       if(verb) {
2175         /* Internal error, no /xxx/share directory! */
2176 	dk3app_log_i1(app, DK3_LL_ERROR, 55);
2177       }
2178     }
2179   }
2180   return back;
2181 }
2182 
2183 
2184 
2185 /**	Remove a file.
2186 	The difference to dk3sf_remove_file_app() is that this function
2187 	does not complain if the file does not exist.
2188 	@param	n	File name.
2189 	@param	app	Application structure for diagnostics, may be NULL.
2190 	@return	1 on success, 0 on error.
2191 */
2192 static
2193 int
dk3app_remove_file_app(dkChar * n,dk3_app_t * app)2194 dk3app_remove_file_app(dkChar *n, dk3_app_t *app)
2195 {
2196   int back = 0;
2197   dk3_stat_t	stb;	/* Stat buffer to test existance of file. */
2198 
2199   if(dk3sf_stat_app(&stb,n,app)) {
2200     back = dk3sf_remove_file_app(n, app);
2201   } else {
2202     back = 1;	/* File does not exist. */
2203   }
2204   return back;
2205 }
2206 
2207 
2208 
2209 /**	Delete one temporaray file.
2210 	@param	app	Application structure.
2211 	@param	n	Number to build the file name.
2212 	@param	s	Number to build the file suffix.
2213 	@param	f	Pointer to error code variable.
2214 */
2215 static
2216 void
dk3app_delete_one_temp_file(dk3_app_t * app,unsigned long n,unsigned s,int * f)2217 dk3app_delete_one_temp_file(dk3_app_t *app, unsigned long n, unsigned s, int *f)
2218 {
2219   dkChar buffer[DK3_MAX_PATH];	/* Buffer to construct complete file name. */
2220   dkChar fnb2[16];		/* Buffer for short file name. */
2221   char	 fnb[16];		/* Buffer for numeric conversion. */
2222   dk3_app_t *ra = NULL;		/* Application to use for diagnostics. */
2223   size_t sz = 0;		/* Length needed for complete file name. */
2224 
2225   sprintf(fnb, "/%08lx.%03x", n, s);
2226   ra = app;
2227   if((*f) & 1) { ra = NULL; }
2228   if(dk3str_cnv_c8_to_str_app(fnb2, 15, fnb, ra)) {
2229     sz = dk3str_len(app->n_tmpdir) + dk3str_len(fnb2);
2230     if(sz < DK3_SIZEOF(buffer,dkChar)) {
2231       dk3str_cpy_not_overlapped(buffer, app->n_tmpdir);
2232       dk3str_cat(buffer, fnb2);
2233       dk3str_correct_filename(buffer);
2234 #if VERSION_BEFORE_20150821
2235       ra = app;
2236       if((*f) & 4) { ra = NULL; }
2237 #endif
2238       if(!dk3app_remove_file_app(buffer, NULL)) {
2239         *f = ((*f) | 4);
2240       }
2241     } else {
2242       if(!((*f) & 2)) {
2243         dk3app_log_i1(app, DK3_LL_ERROR, 37);
2244 	*f = ((*f) | 2);
2245       }
2246     }
2247   } else {
2248     *f = ((*f) | 1);
2249   }
2250 }
2251 
2252 
2253 
2254 /**	Delete all temporary files of an application for a core name.
2255 	@param	app	Application structure.
2256 	@param	n	Number to build core file name.
2257 	@param	f	Pointer to error code variable.
2258 */
2259 static
2260 void
dk3app_delete_all_temp_files_for(dk3_app_t * app,unsigned long n,int * f)2261 dk3app_delete_all_temp_files_for(dk3_app_t *app, unsigned long n, int *f)
2262 {
2263   unsigned u;	/* Used for file name suffix. */
2264 
2265   for(u = 0; u < 0x1000U; u++) {
2266     dk3app_delete_one_temp_file(app, n, u, f);
2267   }
2268 }
2269 
2270 
2271 
2272 /**	Delete all temporary files of an application.
2273 	@param	app	Application structure.
2274 */
2275 static
2276 void
dk3app_remove_temporary_files(dk3_app_t * app)2277 dk3app_remove_temporary_files(dk3_app_t *app)
2278 {
2279   unsigned long	ul = 0UL;	/* Used for base file name. */
2280   unsigned	u = 0;		/* Used for suffixes of final base. */
2281   int		f = 0;		/* Error checking variable. */
2282 
2283   if(app->n_tmpdir) {
2284     f = 0;
2285     if(app->i_tmpcarry) {
2286       for(ul = 0UL; ul < 0xFFFFFFFFUL; ul++) {
2287         dk3app_delete_all_temp_files_for(app, ul, &f);
2288       }
2289       dk3app_delete_all_temp_files_for(app, 0xFFFFFFFFUL, &f);
2290     } else {
2291       for(ul = 0UL; ul < app->ul_tmpname; ul++) {
2292         dk3app_delete_all_temp_files_for(app, ul, &f);
2293       }
2294       for(u = 0; u < app->u_tmpsuffix; u++) {
2295         dk3app_delete_one_temp_file(app, app->ul_tmpname, u, &f);
2296       }
2297       dk3app_delete_one_temp_file(app, app->ul_tmpname, app->u_tmpsuffix, &f);
2298     }
2299     dk3sf_remove_dir_app(app->n_tmpdir, NULL);
2300   }
2301 }
2302 
2303 
2304 
2305 /**	Construct configuration file name candidate.
2306 	When searching for files (configuration or resource files) we
2307 	specify the sort file name without leading directory.
2308 	During the search process we do several tests prepending
2309 	directory names before the short file name.
2310 	This function is used to construct a file name.
2311 	@param	app	Application structure.
2312 	@param	fn	File name.
2313 	@param	db	Result buffer.
2314 	@param	sz	Size of \a db (number of characters).
2315 	@param	passno	Pass number (0-15).
2316 	@param	verb	Flag: Diagnostic messages enabled.
2317 	@return	1 on success, 0 on error.
2318 */
2319 static
2320 int
dk3app_config_name(dk3_app_t * app,dkChar const * fn,dkChar * db,size_t sz,int passno,int verb)2321 dk3app_config_name(
2322   dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int passno, int verb
2323 )
2324 {
2325   int back = 0;
2326   dkChar const *ptr1 = NULL;	/* Base directory (etc or share). */
2327   dkChar const *ptr2 = NULL;	/* Subdirectory (app, group, dk3app or none). */
2328   dkChar const *ptr3 = NULL;	/* Application or group name. */
2329   size_t	mysz = 0;	/* Buffer size needed for all components. */
2330 
2331   ptr1 = NULL; ptr2 = NULL; ptr3 = NULL;
2332   switch(passno) {
2333 
2334 #if VERSION_BEFORE_20110219
2335     case  0: { ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17]; } break;
2336     case  2: { ptr1 = app->n_sharedir; ptr2 = app->n_appgroup; } break;
2337     case  3: { ptr1 = app->n_etcdir; ptr2 = app->n_appgroup; } break;
2338     case  4: { ptr1 = app->n_sharedir; ptr2 = app->n_app; } break;
2339     case  5: { ptr1 = app->n_etcdir; ptr2 = app->n_app; } break;
2340     case  6: { ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; } break;
2341     case  7: {
2342       ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_appgroup;
2343     } break;
2344     case  8: {
2345       ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_app;
2346     } break;
2347     case  9: {
2348       ptr1 = dk3app_no_loc[19];
2349     } break;
2350     default: {	/* 1 */
2351       ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17];
2352     } break;
2353 #else
2354     case 0: {
2355       ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17];
2356     } break;
2357     case 1: {
2358       ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17];
2359     } break;
2360     case 2: {
2361       ptr1 = app->n_sharedir; ptr2 = dk3app_no_loc[17];
2362     } break;
2363     case 3: {
2364       ptr1 = app->n_etcdir; ptr2 = dk3app_no_loc[17];
2365     } break;
2366     case 4: {
2367       ptr1 = app->n_sharedir; ptr2 = app->n_appgroup;
2368     } break;
2369     case 5: {
2370       ptr1 = app->n_etcdir; ptr2 = app->n_appgroup;
2371     } break;
2372     case 6: {
2373       ptr1 = app->n_sharedir; ptr2 = app->n_appgroup;
2374     } break;
2375     case 7: {
2376       ptr1 = app->n_etcdir; ptr2 = app->n_appgroup;
2377     } break;
2378     case 8: {
2379       ptr1 = app->n_sharedir; ptr2 = app->n_app;
2380     } break;
2381     case 9: {
2382       ptr1 = app->n_etcdir; ptr2 = app->n_app;
2383     } break;
2384     case 10: {
2385       ptr1 = app->n_sharedir; ptr2 = app->n_app;
2386     } break;
2387     case 11: {
2388       ptr1 = app->n_etcdir; ptr2 = app->n_app;
2389     } break;
2390     case 12: {
2391       ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18];
2392     } break;
2393     case 13: {
2394       ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_appgroup;
2395     } break;
2396     case 14: {
2397       ptr1 = app->n_homedir; ptr2 = dk3app_no_loc[18]; ptr3 = app->n_app;
2398     } break;
2399     case 15: {
2400       ptr1 = dk3app_no_loc[19];
2401     } break;
2402 #endif
2403   }
2404   mysz = dk3str_len(fn);
2405   if(ptr1) {
2406     mysz += dk3str_len(ptr1);
2407     mysz++;
2408   }
2409   if(ptr2) {
2410     mysz += dk3str_len(ptr2);
2411     mysz++;
2412   }
2413   if(ptr3) {
2414     mysz += dk3str_len(ptr3);
2415     mysz++;
2416   }
2417   switch(passno) {
2418     case 2: case 3: case 6: case 7: case 10: case 11: {
2419       mysz += dk3str_len(dk3app_no_loc[32]);
2420     } break;
2421   }
2422   if(mysz < sz) {
2423     if(ptr1) {
2424       dk3str_cpy_not_overlapped(db, ptr1);
2425       if(ptr2) {
2426         dk3str_cat(db, dk3app_no_loc[20]);
2427 	dk3str_cat(db, ptr2);
2428       }
2429       if(ptr3) {
2430         dk3str_cat(db, dk3app_no_loc[20]);
2431 	dk3str_cat(db, ptr3);
2432       }
2433       switch(passno) {
2434         case 2: case 3: case 6: case 7: case 10: case 11: {
2435 	  dk3str_cat(db, dk3app_no_loc[32]);
2436 	} break;
2437       }
2438       dk3str_cat(db, dk3app_no_loc[20]);
2439       dk3str_cat(db, fn);
2440       back = 1;
2441     } else {
2442       if(verb) {
2443         /* Internal error, some directory not set! */
2444       }
2445     }
2446   } else {
2447     if(verb) {
2448       dk3app_log_i1(app, DK3_LL_ERROR, 38);
2449     }
2450   }
2451   return back;
2452 }
2453 
2454 
2455 
2456 /**	Unconfigure application (delete registry key or config file).
2457 	@param	app	Application to unconfigure.
2458 */
2459 static
2460 void
dk3app_do_unconfigure(dk3_app_t * app)2461 dk3app_do_unconfigure(dk3_app_t *app)
2462 {
2463   dkChar	fnb[DK3_MAX_PATH];	/* File name buffer for config file. */
2464 
2465   if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, 14, 0)) {
2466     (void)dk3sf_remove_file_app(fnb, app);
2467   }
2468 }
2469 
2470 
2471 
2472 /**	Save self-set preferences to registry or file.
2473 	@param	app	Application structure.
2474 */
2475 static
2476 void
dk3app_do_save_config(dk3_app_t * app)2477 dk3app_do_save_config(dk3_app_t *app)
2478 {
2479   dkChar	fnb[DK3_MAX_PATH];	/* File name buffer for conf file. */
2480   dkChar	*ptr = NULL;		/* Slash/backslash correction. */
2481   FILE		*fipo = NULL;		/* Used to write file. */
2482   dk3app_pref_t	*p1 = NULL;		/* Preference entry to process. */
2483   dk3app_pref_t	*p2 = NULL;		/* Check in higher priorized storage. */
2484 
2485   if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, 14, 0)) {
2486 
2487     ptr = dk3str_rchr(fnb, DK3_CHAR_SEP);
2488     if(ptr) {
2489       *ptr = dkT('\0');
2490 
2491       dk3sf_mkdir_app(fnb, 0700, NULL);
2492       *ptr = DK3_CHAR_SEP;
2493     }
2494     fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[24], app);	/* WRITE */
2495     if(fipo) {
2496 #if DK3_ON_WINDOWS && (DK3_CHAR_SIZE > 1)
2497       /* Switch to 16 bit characters. */
2498 #if defined(_MSC_VER)
2499       (void)_setmode(_fileno(fipo), _O_U16TEXT);
2500 #endif
2501       /* Write byte order marker. */
2502       fputwc(0xFEFF, fipo);
2503 #endif
2504       if((app->s_varprefs) && (app->i_varprefs)) {
2505         dk3sto_it_reset(app->i_varprefs);
2506 	while((p1 = (dk3app_pref_t *)dk3sto_it_next(app->i_varprefs)) != NULL) {
2507 	  p2 = NULL;
2508 	  if((app->s_selfprefs) && (app->i_selfprefs)) {
2509 	    p2 = (dk3app_pref_t *)dk3sto_it_find_like(app->i_selfprefs, p1, 0);
2510 	  }
2511 	  if(!(p2)) {
2512 	    dk3sf_fputs(p1->k, fipo);
2513 	    dk3sf_fputs(dk3app_no_loc[25], fipo);
2514 	    dk3sf_fputs(p1->v, fipo);
2515 	    dk3sf_fputs(dk3app_no_loc[26], fipo);
2516 	  }
2517 	}
2518       }
2519       if((app->s_selfprefs) && (app->i_selfprefs)) {
2520         dk3sto_it_reset(app->i_selfprefs);
2521 	while((p1 = (dk3app_pref_t *)dk3sto_it_next(app->i_selfprefs)) != NULL) {
2522 	  dk3sf_fputs(p1->k, fipo);
2523 	  dk3sf_fputs(dk3app_no_loc[25], fipo);
2524 	  dk3sf_fputs(p1->v, fipo);
2525 	  dk3sf_fputs(dk3app_no_loc[26], fipo);
2526 	}
2527       }
2528       fclose(fipo);
2529     } else {
2530     }
2531   } else {
2532   }
2533 }
2534 
2535 
2536 
2537 
2538 
2539 void
dk3app_close(dk3_app_t * app)2540 dk3app_close(dk3_app_t *app)
2541 {
2542   int		i = 0;		/* Used to release argv memory. */
2543   dk3app_pref_t	*pref = NULL;	/* Used to delete preference entries. */
2544   dk3app_mc_t	*mcptr = NULL;	/* Used to delete message catalogs. */
2545 
2546 
2547   if(app) {
2548     if(app->f_unconfigure) {
2549       dk3app_do_unconfigure(app);
2550     } else {
2551       if(app->f_prefschanged) {
2552         dk3app_do_save_config(app);
2553       }
2554     }
2555     /* Clean up preferences system. */
2556     if(app->s_selfprefs) {
2557       if(app->i_selfprefs) {
2558         dk3sto_it_reset(app->i_selfprefs);
2559 	while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_selfprefs)) != NULL) {
2560 	  dk3app_pref_delete(pref);
2561 	}
2562 	dk3sto_it_close(app->i_selfprefs);
2563       }
2564       dk3sto_close(app->s_selfprefs);
2565     } app->s_selfprefs = NULL; app->i_selfprefs = NULL;
2566     if(app->s_cmdprefs) {
2567       if(app->i_cmdprefs) {
2568         dk3sto_it_reset(app->i_cmdprefs);
2569 	while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_cmdprefs)) != NULL) {
2570 	  dk3app_pref_delete(pref);
2571 	}
2572         dk3sto_it_close(app->i_cmdprefs);
2573       }
2574       dk3sto_close(app->s_cmdprefs);
2575     } app->s_cmdprefs = NULL; app->i_cmdprefs = NULL;
2576     if(app->s_sysprefs) {
2577       if(app->i_sysprefs) {
2578         dk3sto_it_reset(app->i_sysprefs);
2579 	while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_sysprefs)) != NULL)
2580 	{
2581 	  dk3app_pref_delete(pref);
2582 	}
2583         dk3sto_it_close(app->i_sysprefs);
2584       }
2585       dk3sto_close(app->s_sysprefs);
2586     } app->s_sysprefs = NULL; app->i_sysprefs = NULL;
2587     if(app->s_constprefs) {
2588       if(app->i_constprefs) {
2589         dk3sto_it_reset(app->i_constprefs);
2590 	while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_constprefs)) != NULL)
2591 	{
2592 	  dk3app_pref_delete(pref);
2593 	}
2594         dk3sto_it_close(app->i_constprefs);
2595       }
2596       dk3sto_close(app->s_constprefs);
2597     } app->s_constprefs = NULL; app->i_constprefs = NULL;
2598     if(app->s_varprefs) {
2599       if(app->i_varprefs) {
2600         dk3sto_it_reset(app->i_varprefs);
2601 	while((pref = (dk3app_pref_t *)dk3sto_it_next(app->i_varprefs)) != NULL)
2602 	{
2603 	  dk3app_pref_delete(pref);
2604 	}
2605         dk3sto_it_close(app->i_varprefs);
2606       }
2607       dk3sto_close(app->s_varprefs);
2608     } app->s_varprefs = NULL; app->i_varprefs = NULL;
2609     /* Clean up temporary directory. */
2610     if(app->ll_highest > app->ll_tmp_keep) {
2611       dk3app_remove_temporary_files(app);
2612     }
2613     /* Remove log file if no longer needed. */
2614     if(DK3_APP_TYPE_DAEMON != app->app_type) {
2615       dk3app_log_i3(app, DK3_LL_DEBUG, 21, 22, app->n_app);
2616       if(app->ll_highest > app->ll_file_keep) {
2617         dk3sf_remove_file_app(app->n_logfilename, NULL);
2618       }
2619     }
2620     /* Unset resources, release resources. */
2621     app->ll_file = app->ll_stderr = app->ll_file_keep = app->ll_highest = 0;
2622     app->app_type	= 0;
2623     app->msg		= NULL;
2624     app->n_sourcefile	= NULL;
2625     app->sourceline 	= 0UL;
2626     if(app->s_mc) {
2627       if(app->i_mc) {
2628         dk3sto_it_reset(app->i_mc);
2629 	while((mcptr = (dk3app_mc_t *)dk3sto_it_next(app->i_mc)) != NULL)
2630 	{
2631 	  dk3app_mc_delete(mcptr);
2632 	}
2633         dk3sto_it_close(app->i_mc);
2634       }
2635       dk3sto_close(app->s_mc);
2636     } app->s_mc = NULL; app->i_mc = NULL;
2637     if(app->argv) {
2638       dkChar const **ptr;
2639       ptr = (dkChar const **)(app->argv);
2640       for(i = 0; i < app->argc; i++) {
2641 	dk3_release(*ptr);
2642         ptr++;
2643       }
2644     }
2645     dk3_release(app->n_app);
2646     dk3_release(app->n_execfile);
2647     dk3_release(app->n_bindir);
2648     dk3_release(app->n_etcdir);
2649     dk3_release(app->n_sharedir);
2650     dk3_release(app->n_vardir);
2651     dk3_release(app->n_logname);
2652     dk3_release(app->n_homedir);
2653     dk3_release(app->n_appgroup);
2654     dk3_release(app->n_logfilename);
2655     dk3_release(app->n_tmpdir);
2656     dk3_release(app->n_language);
2657     dk3_release(app->n_region);
2658     dk3_release(app->n_langstr);
2659     dk3_release(app->n_hostname);
2660     dk3_delete(app);
2661   }
2662 }
2663 
2664 
2665 
2666 int
dk3app_get_default_stdin_encoding(dk3_app_t const * app)2667 dk3app_get_default_stdin_encoding(dk3_app_t const *app)
2668 {
2669   int  back = 0;
2670   if(app) {
2671     back = app->i_output_encoding;
2672 #if DK3_CHAR_SIZE > 1
2673 #if DK3_ON_WINDOWS
2674     back = DK3_FILE_ENCODING_ASCII;
2675 #endif
2676 #endif
2677   }
2678   return back;
2679 }
2680 
2681 
2682 
2683 int
dk3app_get_default_file_encoding(dk3_app_t const * app)2684 dk3app_get_default_file_encoding(dk3_app_t const *app)
2685 {
2686   int  back = 0;
2687   if(app) {
2688     back = app->i_output_encoding;
2689 #if DK3_CHAR_SIZE > 1
2690 #if DK3_ON_WINDOWS
2691     back = DK3_FILE_ENCODING_ASCII;
2692 #endif
2693 #endif
2694   }
2695   return back;
2696 }
2697 
2698 
2699 
2700 
2701 /**	Initialize application structure.
2702 	@param	app	Application to initialize.
2703 */
2704 static
2705 void
dk3app_init(dk3_app_t * app)2706 dk3app_init(dk3_app_t *app)
2707 {
2708 
2709   app->app_type 	= 0;
2710   app->msg		= NULL;
2711   app->n_sourcefile	= NULL;
2712   app->sourceline	= 0UL;
2713   app->ll_file		= DK3_LL_NONE;
2714   app->ll_stderr	= DK3_LL_INFO;
2715   app->ll_file_keep	= DK3_LL_NONE;
2716   app->ll_tmp_keep	= DK3_LL_NONE;
2717   app->ll_highest	= DK3_LL_IGNORE;
2718   app->argv		= NULL;
2719   app->argc		= 0;
2720   app->n_app		= NULL;
2721   app->n_execfile	= NULL;
2722   app->n_bindir		= NULL;
2723   app->n_etcdir		= NULL;
2724   app->n_sharedir	= NULL;
2725   app->n_vardir		= NULL;
2726   app->n_logname	= NULL;
2727   app->n_homedir	= NULL;
2728   app->n_appgroup	= NULL;
2729   app->n_logfilename	= NULL;
2730   app->n_tmpdir		= NULL;
2731   app->n_language	= NULL;
2732   app->n_region		= NULL;
2733   app->n_langstr	= NULL;
2734   app->ul_tmpname	= 0UL;
2735   app->u_tmpsuffix	= 0U;
2736   app->i_tmpcarry	= 0;
2737   app->n_hostname	= NULL;
2738 #if DK3_CHAR_SIZE > 1
2739   app->i_encoding	= DK3_ENCODING_UTF16;
2740 #if DK3_BIGENDIAN
2741   app->i_output_encoding = DK3_FILE_ENCODING_UTF16_MSB_FIRST;
2742 #else
2743   app->i_output_encoding = DK3_FILE_ENCODING_UTF16_LSB_FIRST;
2744 #endif
2745 #else
2746   app->i_encoding	= DK3_ENCODING_PLAIN;
2747   app->i_output_encoding = DK3_FILE_ENCODING_ASCII;
2748 #endif
2749   app->i_stdin_input_encoding = dk3app_get_default_stdin_encoding(app);
2750 
2751   app->i_file_input_encoding = dk3app_get_default_file_encoding(app);
2752   app->de		= 0;	/* No error found yet. */
2753   app->s_mc		= NULL;
2754   app->i_mc		= NULL;
2755   app->s_cmdprefs	= NULL;
2756   app->i_cmdprefs	= NULL;
2757   app->s_selfprefs	= NULL;
2758   app->i_selfprefs	= NULL;
2759   app->f_unconfigure	= 0;
2760   app->f_prefschanged	= 0;
2761   app->f_readytolog	= 0;
2762   app->s_sysprefs	= NULL;
2763   app->i_sysprefs	= NULL;
2764   app->s_constprefs	= NULL;
2765   app->i_constprefs	= NULL;
2766   app->s_varprefs	= NULL;
2767   app->i_varprefs	= NULL;
2768   app->f_first_file_log	= 1;
2769   app->f_rand_initialized = 0;
2770   app->f_rand_success = 0;
2771   app->rand_type = 0;
2772   app->cr_log = 0;
2773   app->cr_tmp = 0;
2774   app->t_last_log_stderr = (dk3_time_t)0UL;
2775   app->t_last_log_file = (dk3_time_t)0UL;
2776 }
2777 
2778 
2779 
2780 /**	Copy binary directory name to other directory names.
2781 	@param	app	Application structure.
2782 */
2783 static
2784 void
dk3app_copy_bin_to_others(dk3_app_t * app)2785 dk3app_copy_bin_to_others(dk3_app_t *app)
2786 {
2787 
2788   app->n_etcdir = dk3str_dup_app(app->n_bindir, NULL);
2789   if(app->n_etcdir) {
2790     app->n_sharedir = dk3str_dup_app(app->n_bindir, NULL);
2791     if(app->n_sharedir) {
2792       app->n_vardir = dk3str_dup_app(app->n_bindir, NULL);
2793       if(!(app->n_vardir)) {
2794 	app->de = 9;
2795       }
2796     } else {
2797       app->de = 8;
2798     }
2799   } else {
2800     app->de = 7;
2801   }
2802 }
2803 
2804 
2805 #if DK3_ON_WINDOWS
2806 
2807 #if VERSION_BEFORE_20131022
2808 
2809 /**	Open a registry key.
2810 	@param	k	Parent key (HKLM or HKCU).
2811 	@param	n	Key name.
2812 	@param	p	Permissions needed.
2813 	@param	kp	Pointer to result key variable.
2814 	@return	ERROR_SUCCESS on success, other values indicate an error.
2815 */
2816 static
2817 long
dk3app_reg_open_key(HKEY k,dkChar const * n,int p,HKEY * kp)2818 dk3app_reg_open_key(HKEY k, dkChar const *n, int p, HKEY *kp)
2819 {
2820   long back = 0L;
2821 #if DK3_CHAR_SIZE > 1
2822   back = RegOpenKeyExW(k, n, (DWORD)0, p, kp);
2823 #else
2824   back = RegOpenKeyExA(k, n, (DWORD)0, p, kp);
2825 #endif
2826   return back;
2827 }
2828 
2829 
2830 
2831 /**	Retrieve a value from the registry.
2832 	@param	k	Registry key.
2833 	@param	n	Entry name.
2834 	@param	tp	Entry type.
2835 	@param	b	Result buffer address.
2836 	@param	len	In: size of buffer, out: number of bytes used.
2837 	@return	ERROR_SUCCESS on success, any other value indicates an error.
2838 */
2839 static
2840 long
dk3app_reg_query(HKEY k,dkChar const * n,DWORD * tp,LPBYTE b,DWORD * len)2841 dk3app_reg_query(HKEY k, dkChar const *n, DWORD *tp, LPBYTE b, DWORD *len)
2842 {
2843   long back = 0L;
2844 #if DK3_CHAR_SIZE > 1
2845   back = RegQueryValueExW(k, n, NULL, tp, b, len);
2846 #else
2847   back = RegQueryValueExA(k, n, NULL, tp, b, len);
2848 #endif
2849   return back;
2850 }
2851 
2852 
2853 
2854 /**	Retrieve string value from registry.
2855 	@param	k	Key.
2856 	@param	n	Entry name.
2857 	@param	b	Result buffer.
2858 	@param	sz	Size of \a b (number of characters).
2859 	@return	1 on success, 0 on error.
2860 */
2861 static
2862 int
dk3app_reg_query_str(HKEY k,dkChar const * n,dkChar * b,size_t sz)2863 dk3app_reg_query_str(HKEY k, dkChar const *n, dkChar *b, size_t sz)
2864 {
2865   int		back = 0;
2866   DWORD		tp = REG_SZ;	/* Registry entry type. */
2867   DWORD		len = 0L;	/* Length of arguments and results. */
2868   LONG		res = 0L;	/* Registry operation result. */
2869   tp = REG_SZ;
2870   len = (DWORD)(sz * DK3_CHAR_SIZE);
2871   res = dk3app_reg_query(k, n, &tp, (LPBYTE)b, &len);
2872   if(ERROR_SUCCESS == res) {
2873     if((REG_SZ == tp) || (REG_EXPAND_SZ == tp)) {
2874       if(len > 0) {
2875 #if DK3_CHAR_SIZE > 1
2876         len = len / DK3_CHAR_SIZE;
2877 #endif
2878 	b[(((size_t)len) < sz) ? len : (sz - 1)] = dkT('\0');
2879 	back = 1;
2880       }
2881     }
2882   }
2883   return back;
2884 }
2885 
2886 #endif
2887 
2888 #endif
2889 
2890 
2891 
2892 /**	Get users language/region/encoding setting.
2893 	@param	app	Application structure.
2894 	@param	db	Result buffer.
2895 	@param	sz	Size of \a db (number of characters).
2896 	@return	1 on success, 0 on error.
2897 */
2898 static
2899 int
dk3app_get_language_string(dk3_app_t * app,dkChar * db,size_t sz)2900 dk3app_get_language_string(
2901 #if (!(DK3_ON_WINDOWS)) && (DK3_CHAR_SIZE == 1)
2902 	dk3_app_t *app,
2903 #else
2904 	dk3_app_t * DK3_ARG_UNUSED(app),
2905 #endif
2906 	dkChar *db,
2907 	size_t sz
2908 )
2909 {
2910   int back = 0;
2911 
2912 #if DK3_ON_WINDOWS
2913   DK3_UNUSED_ARG(app)
2914 #if VERSION_BEFORE_20131022
2915   {
2916   LONG		res = 0L;	/* Registry operation result. */
2917   HKEY		key;		/* Registry key. */
2918   res = dk3app_reg_open_key(
2919     HKEY_CURRENT_USER,
2920     dk3app_no_loc[12],
2921     KEY_READ,
2922     &key
2923   );
2924   if(ERROR_SUCCESS == res) {
2925     back = dk3app_reg_query_str(key, dk3app_no_loc[13], db, sz);
2926     if(back == 0) {
2927       back = dk3app_reg_query_str(key, dk3app_no_loc[14], db, sz);
2928       if(back) {
2929         db[2] = dkT('\0');
2930       }
2931     }
2932     RegCloseKey(key);
2933   }
2934   }
2935 #else
2936   {
2937     HKEY		hk;	/* Registry key. */
2938     if(dk3wreg_key_open_read(HKEY_CURRENT_USER, dk3app_no_loc[12], &hk, NULL)) {
2939       if(dk3wreg_get_sz(hk, dk3app_no_loc[13],db,sz,NULL)) {
2940         back = 1;
2941       } else {
2942         if(dk3wreg_get_sz(hk, dk3app_no_loc[14],db,sz,NULL)) {
2943 	  back = 1;
2944 	  db[2] = dkT('\0');
2945 	}
2946       }
2947       dk3wreg_key_close(hk, dk3app_no_loc[12], NULL);
2948     }
2949   }
2950 #endif
2951 
2952 #else
2953 #if DK3_CHAR_SIZE == 1
2954   {
2955   char *ptr;		/* Pointer to environment variable contents. */
2956   ptr = getenv(dk3app_no_loc[11]);
2957   if(ptr) {
2958     if(dk3str_c8_len(ptr) < sz) {
2959       dk3str_c8_cpy_not_overlapped(db, ptr);
2960       back = 1;
2961     } else {
2962       dk3app_log_i1(app, DK3_LL_ERROR, 39);
2963     }
2964   }
2965   }
2966 #else
2967   DK3_UNUSED_ARG(app)
2968 #endif
2969 #endif
2970 
2971   return back;
2972 }
2973 
2974 
2975 
2976 /**	Find language, region and encoding.
2977 	@param	app	Application structure.
2978 */
2979 static
2980 void
dk3app_language_and_region(dk3_app_t * app)2981 dk3app_language_and_region(dk3_app_t *app)
2982 {
2983   dkChar buffer[DK3_MAX_PATH];	/* Buffer to store language/region name. */
2984   dkChar *ptr;			/* Used to find region. */
2985   dkChar *p2;			/* Used to convert to lower characters. */
2986 
2987   if(dk3app_get_language_string(app, buffer, DK3_SIZEOF(buffer,dkChar))) {
2988     app->n_langstr = dk3str_dup_app(buffer, NULL);
2989     if(app->n_langstr) {
2990       ptr = dk3str_chr(buffer, dkT('.'));
2991       if(ptr) {
2992         *(ptr++) = dkT('\0');
2993 #if DK3_CHAR_SIZE == 1
2994 	if(dk3str_casecmp(ptr, dk3app_no_loc[15]) == 0) {
2995 	  app->i_encoding = DK3_ENCODING_UTF8;
2996 	  app->i_output_encoding = DK3_FILE_ENCODING_UTF8;
2997 	}
2998 	if(dk3str_casecmp(ptr, dk3app_no_loc[16]) == 0) {
2999 	  app->i_encoding = DK3_ENCODING_UTF8;
3000 	  app->i_output_encoding = DK3_FILE_ENCODING_UTF8;
3001 	}
3002 #endif
3003       }
3004       ptr = dk3str_chr(buffer, dkT('_'));
3005 #if DK3_ON_WINDOWS
3006       if(!(ptr)) { ptr = dk3str_chr(buffer, dkT('-')); }
3007 #endif
3008       if(ptr) {
3009         *(ptr++) = dkT('\0');
3010 	p2 = ptr; while(*p2) { *p2 = dk3str_tolower(*p2); p2++; }
3011 	app->n_region = dk3str_dup_app(ptr, NULL);
3012 	if(!(app->n_region)) {
3013 	  app->de = 29;
3014 	}
3015       }
3016       if(!(app->de)) {
3017         p2 = buffer; while(*p2) { *p2 = dk3str_tolower(*p2); p2++; }
3018 	app->n_language = dk3str_dup_app(buffer, NULL);
3019 	if(!(app->n_language)) {
3020 	  app->de = 30;
3021 	}
3022       }
3023     } else {
3024       app->de = 28;
3025     }
3026   }
3027 }
3028 
3029 
3030 
3031 /**	Check whether a directory name is a root directory.
3032 	@param	dirname	Directory name to check.
3033 	@return	1 for root directory, 0 for others.
3034 */
3035 static
3036 int
dk3app_is_root_directory(dkChar const * dirname)3037 dk3app_is_root_directory(dkChar const *dirname)
3038 {
3039   int	back = 0;
3040 #if DK3_ON_WINDOWS
3041   size_t sz;
3042   sz = dk3str_len(dirname);
3043   if(1 == sz) {
3044     if(dkT('\\') == dirname[0]) {
3045       back = 1;
3046     }
3047   } else {
3048     if(3 == sz) {
3049       if((dkT('a') <= dirname[0]) && (dkT('z') >= dirname[0])) {
3050         back = 1;
3051       } else {
3052         if((dkT('A') <= dirname[0]) && (dkT('Z') >= dirname[0])) {
3053 	  back = 1;
3054 	}
3055       }
3056       if(back) {
3057         back = 0;
3058 	if(dkT(':') == dirname[1]) {
3059 	  if(dkT('\\') == dirname[2]) {
3060 	    back = 1;
3061 	  }
3062 	}
3063       }
3064     }
3065   }
3066 #else
3067   if(dk3str_len(dirname) == 1) {
3068     if(dkT('/') == dirname[0]) {
3069       back = 1;
3070     }
3071   }
3072 #endif
3073   return back;
3074 }
3075 
3076 
3077 
3078 /**	Reduce a directory name referring to a bin (or sbin or libexec/xxx
3079 	directory.
3080 	@param	dirname	Directory name to modify.
3081 	@return	1 on success, 0 on error.
3082 */
3083 static
3084 int
dk3app_reduce_bindir_name(dkChar * dirname)3085 dk3app_reduce_bindir_name(dkChar *dirname)
3086 {
3087   dkChar buffer[DK3_MAX_PATH];
3088   dkChar		*pCurrent;	/* Current path component. */
3089   dkChar		*pPrevious;	/* Previous path component. */
3090   size_t		 sz;
3091   int			 ai;		/* Array index. */
3092   int			 cc;		/* Flag: Can continue. */
3093   int			 back = 0;
3094 
3095   if(dk3str_len(dirname) < DK3_SIZEOF(buffer,dkChar)) {
3096     dk3str_cpy_not_overlapped(buffer, dirname);
3097     pCurrent = NULL; pPrevious = NULL;
3098     cc = 1;
3099     while(cc) {
3100       cc = 0;
3101       if(dk3str_len(buffer) > 1) {
3102         if(!dk3app_is_root_directory(buffer)) {
3103 	  pCurrent = dk3str_rchr(buffer, DK3_CHAR_SEP);
3104 	  if(pCurrent) {
3105 	    cc = 1;
3106 #if DK3_ON_WINDOWS
3107 	    ai = dk3str_array_index(dk3app_bindir_candidates,&(pCurrent[1]),0);
3108 #else
3109 	    ai = dk3str_array_index(dk3app_bindir_candidates,&(pCurrent[1]),1);
3110 #endif
3111 	    if(-1 < ai) {
3112 	      cc = 0;
3113 	      sz = dk3str_len(buffer);
3114 	      dirname[sz] = dkT('\0');
3115 	      back = 1;
3116 	    } else {
3117 	      if(pPrevious) { *pPrevious = DK3_CHAR_SEP; }
3118 	      pPrevious = pCurrent;
3119 	      *pCurrent = dkT('\0');
3120 	    }
3121 	  }
3122 	}
3123       }
3124     }
3125   }
3126   return back;
3127 }
3128 
3129 
3130 
3131 /**	Find all the names. Set app->de on errors, don't report directly.
3132 	@param	app	Application to configure.
3133 	@param	wd	Current working directory.
3134 	@param	argv	Command line arguments array.
3135 */
3136 static
3137 void
dk3app_find_names(dk3_app_t * app,dkChar const * wd,dkChar const * const * argv)3138 dk3app_find_names(
3139   dk3_app_t *app, dkChar const *wd,
3140   dkChar const * const *argv
3141 )
3142 {
3143   int		must_relocate = 0;	/* Flag: Must relocate. */
3144   int		redres;			/* Result from reduce directory. */
3145 #if DK3_HAVE_UMASK
3146   mode_t	oldumask;		/* Umask before mkdir. */
3147 #endif
3148   dkChar	*n_app = NULL;		/* Application name. */
3149   dkChar	*p = NULL;		/* Modify application name. */
3150   dkChar const	*q = NULL;		/* Installation bin directory. */
3151   dkChar	*x = NULL;		/* Deal with executable name. */
3152   dkChar	buffer[DK3_MAX_PATH];	/* Used to construct file names. */
3153   char		pidbuffer[128];		/* Buffer for PID number (8-bit). */
3154   dkChar	dkpidbuffer[128];	/* Buffer for PID number. */
3155   size_t	tsl = 0;		/* Buffer size needed. */
3156 
3157   p = dk3str_rchr(argv[0], DK3_CHAR_SEP);
3158   if(p) { p++; } else { p = (dkChar *)(argv[0]); }
3159   n_app = dk3str_dup_app(p, NULL);
3160   if(n_app) {
3161     app->n_app = (dkChar const *)n_app;
3162     p = dk3str_chr(n_app, DK3_CHAR_DOT);
3163     if(p) { *p = DK3_CHAR_0; }
3164     if(dk3sf_find_exec_app(buffer,DK3_SIZEOF(buffer,dkChar),wd,argv[0], NULL)) {
3165       x = dk3str_dup_app(buffer, NULL);
3166       app->n_execfile = x;
3167       if(app->n_execfile) {
3168         p = dk3str_rchr(buffer, DK3_CHAR_SEP);
3169 	if(p) {
3170 	  *p = DK3_CHAR_0;
3171 	  app->n_bindir = dk3str_dup_app(buffer, NULL);
3172 	  if(app->n_bindir) {
3173 	    redres = dk3app_reduce_bindir_name(buffer);
3174 	    q = dk3inst_get_directory(DK3_INST_BIN);
3175 	    if(dk3str_fncmp(buffer, q)) {
3176 	      q = dk3inst_get_directory(DK3_INST_SBIN);
3177 	      if(dk3str_fncmp(buffer, q)) {
3178 	        q = dk3inst_get_directory(DK3_INST_LIB);
3179 		if(dk3str_fncmp(buffer, q)) {
3180 		  q = dk3inst_get_directory(DK3_INST_LIBEXEC);
3181 		  if(dk3str_fncmp(buffer, q)) {
3182 	            must_relocate = 1;
3183 		  }
3184 		}
3185 	      }
3186 	    }
3187 	    if(must_relocate) {
3188 	      p = dk3str_rchr(buffer, DK3_CHAR_SEP);
3189 	      if(p) {
3190 	        p++;
3191 		if(redres) {
3192 		  *p = DK3_CHAR_0;
3193 		  tsl =  dk3str_len(buffer);
3194 		  tsl += dk3str_len(dk3app_no_loc[1]);
3195 		  if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3196 		    dk3str_cpy_not_overlapped(p, dk3app_no_loc[1]);
3197 		    app->n_etcdir = dk3str_dup_app(buffer, NULL);
3198 		    if(app->n_etcdir) {
3199 		      *p = DK3_CHAR_0;
3200 		      tsl  = dk3str_len(buffer);
3201 		      tsl += dk3str_len(dk3app_no_loc[2]);
3202 		      if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3203 		        dk3str_cpy_not_overlapped(p, dk3app_no_loc[2]);
3204 			app->n_sharedir = dk3str_dup_app(buffer, NULL);
3205 			if(app->n_sharedir) {
3206 			  *p = DK3_CHAR_0;
3207 			  tsl =  dk3str_len(buffer);
3208 			  tsl += dk3str_len(dk3app_no_loc[3]);
3209 			  if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3210 			    dk3str_cpy_not_overlapped(p, dk3app_no_loc[3]);
3211 			    app->n_vardir = dk3str_dup_app(buffer, NULL);
3212 			    if(!(app->n_vardir)) {
3213 			      app->de = 9;
3214 			    }
3215 			  } else {
3216 			    app->de = 13;
3217 			  }
3218 			} else {
3219 			  app->de = 8;
3220 			}
3221 		      } else {
3222 		        app->de = 12;
3223 		      }
3224 		    } else {
3225 		      app->de = 7;
3226 		    }
3227 		  } else {
3228 		    app->de = 11;
3229 		  }
3230 		} else {
3231 		  dk3app_copy_bin_to_others(app);
3232 		}
3233 	      } else {
3234 	        dk3app_copy_bin_to_others(app);
3235 	      }
3236 	    } else {
3237 	      q = dk3inst_get_directory(DK3_INST_SYSCONF);
3238 	      app->n_etcdir = dk3str_dup_app(q, NULL);
3239 	      if(app->n_etcdir) {
3240 	        q = dk3inst_get_directory(DK3_INST_DATAROOT);
3241 		app->n_sharedir = dk3str_dup_app(q, NULL);
3242 		if(app->n_sharedir) {
3243 	          q = dk3inst_get_directory(DK3_INST_LOCALSTATE);
3244 		  app->n_vardir = dk3str_dup_app(q, NULL);
3245 		  if(!(app->n_vardir)) {
3246 		    app->de = 9;
3247 		  }
3248 		} else {
3249 		  app->de = 8;
3250 		}
3251 	      } else {
3252 	        app->de = 7;
3253 	      }
3254 	    }
3255 	    if(!(app->de)) {
3256 	      if(dk3sf_get_logname_app(buffer,DK3_SIZEOF(buffer,dkChar),NULL)) {
3257 	        app->n_logname = dk3str_dup_app(buffer,NULL);
3258 		if(!(app->n_logname)) {
3259 		  app->de = 15;
3260 		}
3261 	      } else {
3262 	        app->de = 14;
3263 	      }
3264 	    }
3265 	    if(!(app->de)) {
3266 	      if(dk3sf_get_hostname_app(buffer,DK3_SIZEOF(buffer,dkChar),NULL))
3267 	      {
3268 	        app->n_hostname = dk3str_dup_app(buffer, NULL);
3269 		if(!(app->n_hostname)) {
3270 		  app->de = 37;
3271 		}
3272 	      } else {
3273 	        app->de = 38;
3274 	      }
3275 	    }
3276 	    if(!(app->de)) {
3277 	      if(dk3sf_get_home_app(buffer,DK3_SIZEOF(buffer,dkChar), NULL)) {
3278 	        app->n_homedir = dk3str_dup_app(buffer,NULL);
3279 		if(!(app->n_homedir)) {
3280 		  app->de = 17;
3281 		}
3282 	      } else {
3283 	        app->de = 16;
3284 	      }
3285 	    }
3286 	    if(!(app->de)) {
3287 	      switch(app->app_type) {
3288 	        case DK3_APP_TYPE_COMMAND:
3289 		case DK3_APP_TYPE_GUI: {
3290 		  tsl =  dk3str_len(app->n_homedir);
3291 		  tsl += dk3str_len(dk3app_no_loc[4]);
3292 		  tsl += dk3str_len(dk3app_no_loc[20]);
3293 		  tsl += dk3str_len(app->n_app);
3294 		  tsl += dk3str_len(dk3app_no_loc[5]);
3295 		  (void)dk3ma_um_to_c8_string(
3296 		    pidbuffer, sizeof(pidbuffer), dk3sf_getpid()
3297 		  );
3298 		  if(dk3str_cnv_c8_to_str_app(
3299 		       dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar),
3300 		       pidbuffer, NULL
3301 		     )
3302 		    )
3303 		  {
3304 		    tsl += dk3str_len(dkpidbuffer);
3305 		    tsl += dk3str_len(dk3app_no_loc[6]);
3306 		    if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3307 		      dk3str_cpy_not_overlapped(buffer, app->n_homedir);
3308 		      dk3str_cat(buffer, dk3app_no_loc[4]);
3309 		      dk3str_correct_filename(buffer);
3310 
3311 #if VERSION_BEFORE_20160128
3312 		      if(dk3sf_mkdir_app(buffer, 0700, NULL)) {
3313 		        dk3str_cat(buffer, dk3app_no_loc[20]);
3314 		        dk3str_cat(buffer, app->n_app);
3315 		        dk3str_cat(buffer, dk3app_no_loc[5]);
3316 		        dk3str_cat(buffer, dkpidbuffer);
3317 		        dk3str_cat(buffer, dk3app_no_loc[6]);
3318 		        dk3str_correct_filename(buffer);
3319 		        app->n_logfilename = dk3str_dup_app(buffer,NULL);
3320 		        if(!(app->n_logfilename)) {
3321 		          app->de = 21;
3322 		        }
3323 		      } else {
3324 		        app->de = 20;
3325 		      }
3326 #else
3327 		      /*	2016-01-28
3328 				Do not immediately create the log directory
3329 				for non-daemon programs.
3330 		      */
3331 		      dk3str_cat(buffer, dk3app_no_loc[20]);
3332 		      dk3str_cat(buffer, app->n_app);
3333 		      dk3str_cat(buffer, dk3app_no_loc[5]);
3334 		      dk3str_cat(buffer, dkpidbuffer);
3335 		      dk3str_cat(buffer, dk3app_no_loc[6]);
3336 		      dk3str_correct_filename(buffer);
3337 		      app->n_logfilename = dk3str_dup_app(buffer,NULL);
3338 		      if(!(app->n_logfilename)) {
3339 		        app->de = 21;
3340 		      }
3341 #endif
3342 		    } else {
3343 		      app->de = 19;
3344 		    }
3345 		  } else {
3346 		    app->de = 22;
3347 		  }
3348 		} break;
3349 		case DK3_APP_TYPE_DAEMON: {
3350 		  tsl =  dk3str_len(app->n_vardir);
3351 		  tsl += dk3str_len(dk3app_no_loc[4]);
3352 		  tsl += dk3str_len(dk3app_no_loc[20]);
3353 		  tsl += dk3str_len(app->n_app);
3354 		  tsl += dk3str_len(dk3app_no_loc[20]);
3355 		  tsl += dk3str_len(app->n_app);
3356 		  tsl += dk3str_len(dk3app_no_loc[6]);
3357 #if DK3_HAVE_UMASK
3358 		  oldumask = umask(0);
3359 #endif
3360 		  if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3361 		    dk3str_cpy_not_overlapped(buffer, app->n_vardir);
3362 		    dk3str_cat(buffer, dk3app_no_loc[4]);
3363 
3364 		    if(dk3sf_mkdir_app(buffer, 0755, NULL)) {
3365 		      dk3str_cat(buffer, dk3app_no_loc[20]);
3366 		      dk3str_cat(buffer, app->n_app);
3367 
3368 		      if(dk3sf_mkdir_app(buffer, 0755, NULL)) {
3369 		        app->cr_log = 1;
3370 		        dk3str_cat(buffer, dk3app_no_loc[20]);
3371 			dk3str_cat(buffer, app->n_app);
3372 			dk3str_cat(buffer, dk3app_no_loc[6]);
3373 			app->n_logfilename = dk3str_dup_app(buffer, NULL);
3374 			if(!(app->n_logfilename)) {
3375 			  app->de = 21;
3376 			}
3377 		      } else {
3378 		        app->de = 20;
3379 		      }
3380 		    } else {
3381 		      app->de = 20;
3382 		    }
3383 		  } else {
3384 		    app->de = 19;
3385 		  }
3386 #if DK3_HAVE_UMASK
3387 		  umask(oldumask);
3388 #endif
3389 		} break;
3390 	      }
3391 	    }
3392 	    if(!(app->de)) {
3393 	      switch(app->app_type) {
3394 	        case DK3_APP_TYPE_DAEMON: {
3395 		  if(app->n_vardir) {
3396 		    if(app->n_app) {
3397 
3398 		      (void)dk3ma_um_to_c8_string(
3399 		        pidbuffer, sizeof(pidbuffer), dk3sf_getpid()
3400 		      );
3401 		      if(dk3str_cnv_c8_to_str_app(
3402 		           dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar),
3403 			   pidbuffer, NULL
3404 		         )
3405 		        )
3406 		      {
3407 		        tsl =  dk3str_len(app->n_vardir);
3408 			tsl += dk3str_len(dk3app_no_loc[10]);
3409 			tsl += dk3str_len(dk3app_no_loc[20]);
3410 			tsl += dk3str_len(app->n_app);
3411 			tsl += dk3str_len(dk3app_no_loc[20]);
3412 			tsl += dk3str_len(dkpidbuffer);
3413 			if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3414 			  dk3str_cpy_not_overlapped(buffer, app->n_vardir);
3415 			  dk3str_cat(buffer, dk3app_no_loc[10]);
3416 			  dk3str_correct_filename(buffer);
3417 
3418 			  (void)dk3sf_mkdir_app(buffer,0700,NULL);
3419 			  dk3str_cat(buffer, dk3app_no_loc[20]);
3420 			  dk3str_cat(buffer, app->n_app);
3421 			  dk3str_correct_filename(buffer);
3422 
3423 			  (void)dk3sf_mkdir_app(buffer,0700,NULL);
3424 			  dk3str_cat(buffer, dk3app_no_loc[20]);
3425 			  dk3str_cat(buffer, dkpidbuffer);
3426 
3427 
3428 			  if(dk3sf_mkdir_app(buffer,0700,NULL)) {
3429 			    app->cr_tmp = 1;
3430 			    app->n_tmpdir = dk3str_dup_app(buffer, NULL);
3431 			    if(!(app->n_tmpdir)) {
3432 			      app->de = 25;
3433 			      dk3sf_remove_dir_app(buffer, NULL);
3434 			    }
3435 			  } else {
3436 			    app->de = 26;
3437 			  }
3438 			} else {
3439 			  app->de = 19;
3440 			}
3441 		      } else {
3442 		        app->de = 22;
3443 		      }
3444 		    } else {
3445 		      app->de = 24;
3446 		    }
3447 		  } else {
3448 		    app->de = 27;
3449 		  }
3450 		} break;
3451 		default: {
3452 		  if(app->n_homedir) {
3453 		    if(app->n_app) {
3454 		      (void)dk3ma_um_to_c8_string(
3455 		        pidbuffer, sizeof(pidbuffer), dk3sf_getpid()
3456 		      );
3457 		      if(dk3str_cnv_c8_to_str_app(
3458 		           dkpidbuffer, DK3_SIZEOF(dkpidbuffer,dkChar),
3459 			   pidbuffer, NULL
3460 		         )
3461 		        )
3462 		      {
3463 		        tsl =  dk3str_len(app->n_homedir);
3464 			tsl += dk3str_len(dk3app_no_loc[9]);
3465 			tsl += dk3str_len(dk3app_no_loc[20]);
3466 			tsl += dk3str_len(app->n_app);
3467 			tsl += dk3str_len(dk3app_no_loc[5]);
3468 			tsl += dk3str_len(dkpidbuffer);
3469 			if(tsl < DK3_SIZEOF(buffer,dkChar)) {
3470 			  dk3str_cpy_not_overlapped(buffer, app->n_homedir);
3471 			  dk3str_cat(buffer, dk3app_no_loc[9]);
3472 			  dk3str_correct_filename(buffer);
3473 #if VERSION_BEFORE_20160128
3474 
3475 			  if(dk3sf_mkdir_app(buffer,0700,NULL)) {
3476 			    dk3str_cat(buffer, dk3app_no_loc[20]);
3477 			    dk3str_cat(buffer, app->n_app);
3478 			    dk3str_cat(buffer, dk3app_no_loc[5]);
3479 			    dk3str_cat(buffer, dkpidbuffer);
3480 			    dk3str_correct_filename(buffer);
3481 #if VERSION_BEFORE_20150318
3482 
3483 			    if(dk3sf_mkdir_app(buffer,0700,NULL)) {
3484 			      app->n_tmpdir = dk3str_dup_app(buffer, NULL);
3485 			      if(!(app->n_tmpdir)) {
3486 			        app->de = 25;
3487 				dk3sf_remove_dir_app(buffer, NULL);
3488 			      }
3489 			    } else {
3490 			      app->de = 26;
3491 			    }
3492 #else
3493 			    app->n_tmpdir = dk3str_dup_app(buffer, NULL);
3494 			    if(!(app->n_tmpdir)) {
3495 			      app->de = 25;
3496 			    }
3497 #endif
3498 			  } else {
3499 			    app->de = 26;
3500 			  }
3501 #else
3502 /* if VERSION_BEFORE_20160128 */
3503 			  dk3str_cat(buffer, dk3app_no_loc[20]);
3504 			  dk3str_cat(buffer, app->n_app);
3505 			  dk3str_cat(buffer, dk3app_no_loc[5]);
3506 			  dk3str_cat(buffer, dkpidbuffer);
3507 			  dk3str_correct_filename(buffer);
3508 			  app->n_tmpdir = dk3str_dup_app(buffer, NULL);
3509 			  if(!(app->n_tmpdir)) {
3510 			    app->de = 25;
3511 			  }
3512 #endif
3513 /* if VERSION_BEFORE_20160128 */
3514 			} else {
3515 			  app->de = 19;
3516 			}
3517 		      } else {
3518 		        app->de = 22;
3519 		      }
3520 		    } else {
3521 		      app->de = 24;
3522 		    }
3523 		  } else {
3524 		    app->de = 23;
3525 		  }
3526 		} break;
3527 	      }
3528 	    }
3529 	  } else {
3530 	    app->de = 6;
3531 	  }
3532 	} else {
3533 	  app->de = 5;
3534 	}
3535       } else {
3536         app->de = 4;
3537       }
3538     } else {
3539       app->de = 3;
3540     }
3541   } else {
3542     app->de = 2;
3543   }
3544 }
3545 
3546 
3547 
3548 /**	Test whether a configuration file name candidate is valid.
3549 	@param	app	Application structure.
3550 	@param	fn	File name.
3551 	@param	db	Destination buffer.
3552 	@param	sz	Size of \a db (number of characters).
3553 	@param	passno	Pass number.
3554 	@param	verb	Flag: Diagnostic messages enabled.
3555 	@return	1 on success, 0 on error.
3556 */
3557 static
3558 int
dk3app_check_config_file(dk3_app_t * app,dkChar const * fn,dkChar * db,size_t sz,int passno,int verb)3559 dk3app_check_config_file(
3560   dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz, int passno, int verb
3561 )
3562 {
3563   int back = 0;
3564   dk3_stat_t stb;	/* Stat buffer used to check existance of files. */
3565 
3566   if(dk3app_config_name(app, fn, db, sz, passno, verb)) {
3567     if(dk3sf_stat_app(&stb, db, NULL)) {
3568       switch((stb.ft) & (~(DK3_FT_SYMLINK))) {
3569         case DK3_FT_REGULAR: { back = 1; } break;
3570       }
3571     }
3572     if(back) {
3573       /* DEBUG Config file ... found. */
3574       dk3app_log_i3(app, DK3_LL_DEBUG, 152, 153, db);
3575     } else {
3576       /* DEBUG Config file ... not found. */
3577       dk3app_log_i3(app, DK3_LL_DEBUG, 154, 155, db);
3578     }
3579   }
3580   return back;
3581 }
3582 
3583 
3584 
3585 /**	Add preference key/value entry to storage.
3586 	Check whether an entry for the key already exists.
3587 	@param	app	Application structure for diagnostics, may be NULL.
3588 	@param	s	Storage.
3589 	@param	i	Storage iterator.
3590 	@param	k	Preference key.
3591 	@param	v	Preference value.
3592 */
3593 static
3594 int
dk3app_add_pref(dk3_app_t * app,dk3_sto_t * s,dk3_sto_it_t * i,dkChar const * k,dkChar const * v)3595 dk3app_add_pref(
3596   dk3_app_t *app, dk3_sto_t *s, dk3_sto_it_t *i,
3597   dkChar const *k, dkChar const *v
3598 )
3599 {
3600   int back = 0;
3601   dk3app_pref_t	p;		/* Preference search. */
3602   dk3app_pref_t	*pref = NULL;	/* Existing preference for name. */
3603   dkChar	*nv = NULL;	/* New value string for preference. */
3604 
3605   p.k = k; p.v = v;
3606   pref = (dk3app_pref_t *)dk3sto_it_find_like(i, &p, 0);
3607   if(pref) {
3608     nv = dk3str_dup_app(v, NULL);
3609     if(nv) {
3610       dk3_delete(pref->v);
3611       pref->v = nv;
3612       back = 1;
3613     } else {
3614       if(app) {
3615         dk3app_log_i1(app, DK3_LL_ERROR, 9);
3616       }
3617     }
3618   } else {
3619     pref = dk3app_pref_new(k, v);
3620     if(pref) {
3621       if(dk3sto_add(s, pref)) {
3622         back = 1;
3623       } else {
3624         if(app) {
3625           dk3app_log_i1(app, DK3_LL_ERROR, 9);
3626 	}
3627 	dk3app_pref_delete(pref); pref = NULL;
3628       }
3629     } else {
3630       if(app) {
3631         dk3app_log_i1(app, DK3_LL_ERROR, 9);
3632       }
3633     }
3634   }
3635   return back;
3636 }
3637 
3638 
3639 
3640 /**	Save one preference entry.
3641 	Do not report problems directly, set app->de instead.
3642 	@param	app	Application structure.
3643 	@param	pt	Preference text.
3644 */
3645 static
3646 void
dk3app_save_one_preference(dk3_app_t * app,dkChar const * pt)3647 dk3app_save_one_preference(dk3_app_t *app, dkChar const *pt)
3648 {
3649   dkChar	b[DK3_MAX_PATH];	/* Buffer for input line. */
3650   dkChar	*p1 = NULL;		/* Value position. */
3651 
3652   if(dk3str_len(pt) < DK3_SIZEOF(b,dkChar)) {
3653     dk3str_cpy_not_overlapped(b, pt);
3654     p1 = dk3str_chr(b, dkT('='));
3655     if(p1) {
3656       *(p1++) = dkT('\0');
3657       p1 = dk3str_start(p1, NULL);
3658       if(p1) {
3659         dk3str_chomp(b, NULL);
3660 	dk3str_chomp(p1, NULL);
3661 	if(!(app->s_cmdprefs)) {
3662 	  app->s_cmdprefs = dk3sto_open_app(NULL);
3663 	  if(app->s_cmdprefs) {
3664 	    dk3sto_set_comp(app->s_cmdprefs, dk3app_compare_pref, 0);
3665 	  } else {
3666 	    app->de = 36;
3667 	  }
3668 	}
3669 	if(!(app->i_cmdprefs)) {
3670 	  if(app->s_cmdprefs) {
3671 	    app->i_cmdprefs = dk3sto_it_open(app->s_cmdprefs);
3672 	  } else {
3673 	    app->de = 35;
3674 	  }
3675 	}
3676 	if((app->s_cmdprefs) && (app->i_cmdprefs)) {
3677           if(!dk3app_add_pref(NULL,app->s_cmdprefs,app->i_cmdprefs,b,p1)) {
3678 	    app->de = 33;
3679 	  }
3680 	}
3681       } else {
3682 	app->de = 32;
3683       }
3684     } else {
3685       app->de = 32;
3686     }
3687   } else {
3688     app->de = 31;
3689   }
3690 }
3691 
3692 
3693 
3694 /**	Set application to silent mode if --/silent=yes was
3695 	provided as command line argument.
3696 	@param	app	Application structure.
3697 */
3698 static
3699 void
dk3app_first_set_silent(dk3_app_t * app)3700 dk3app_first_set_silent(dk3_app_t *app)
3701 {
3702   app->ll_stderr = DK3_LL_NONE;
3703   switch(app->app_type) {
3704     case DK3_APP_TYPE_COMMAND: {
3705       app->app_type = DK3_APP_TYPE_SILENT;
3706     } break;
3707   }
3708 }
3709 
3710 
3711 
3712 int
dk3app_first_silence_check(dk3_app_t * app,int argc,dkChar const * const * argv)3713 dk3app_first_silence_check(dk3_app_t *app, int argc, dkChar const * const *argv)
3714 {
3715   int			back = 0;
3716   int			i;		/* Index of current argument. */
3717   dkChar const * const	*lfdptr;	/* Pointer to traverse arguments. */
3718   dkChar const		*ptr;		/* Current argument. */
3719   dkChar		buffer[2 * DK3_MAX_PATH];	/* Local copy. */
3720   dkChar		*p1;		/* Option keyword. */
3721   dkChar		*p2;		/* Option argument. */
3722 
3723   lfdptr = argv; lfdptr++; i = 1;
3724   while(i < argc) {
3725     ptr = *lfdptr;
3726     if(*ptr == dkT('-')) {
3727       ptr++;
3728       if(*ptr == dkT('-')) {
3729         ptr++;
3730 	if(dk3str_len(ptr) < DK3_SIZEOF(buffer,dkChar)) {
3731 	  dk3str_cpy_not_overlapped(buffer, ptr);
3732 	  p1 = dk3str_start(buffer, NULL);
3733 	  if(p1) {
3734 	    p2 = dk3str_chr(p1, dkT('='));
3735 	    if(p2) {
3736 	      *(p2++) = dkT('\0');
3737 	      p2 = dk3str_start(p2, NULL);
3738 	    }
3739 	    if(dk3str_cmp(dk3app_no_loc[50], p1) == 0) {
3740 	      if(p2) {
3741 	        if(dk3str_is_on(p2)) {
3742 		  back = 1;
3743 		  if(app) { dk3app_first_set_silent(app); }
3744 		}
3745 	      } else {
3746 	        back = 1;
3747 	        if(app) { dk3app_first_set_silent(app); }
3748 	      }
3749 	    }
3750 	  }
3751 	} else {
3752 	  /* ERROR: Too long! */
3753 	}
3754       }
3755     }
3756     lfdptr++; i++;
3757   }
3758   return back;
3759 }
3760 
3761 
3762 
3763 /**	Save command line arguments for later use.
3764 	Don't report errors directly, set app->de instead.
3765 	@param	app	Application structure.
3766 	@param	argc	Number of command line arguments.
3767 	@param	argv	Command line arguments array.
3768 */
3769 static
3770 void
dk3app_save_arguments(dk3_app_t * app,int argc,dkChar const * const * argv)3771 dk3app_save_arguments(dk3_app_t *app, int argc, dkChar const * const *argv)
3772 {
3773   int			myargc = 0;		/* Number of options used. */
3774   dkChar const 		**myargv = NULL;	/* Private copy of options. */
3775   dkChar const 		**ptr = NULL;		/* Traverse myargv. */
3776   dkChar const * const	*sptr = NULL;		/* Traverse original argv. */
3777   dkChar const		*tptr = NULL;		/* String tests in sptr. */
3778   int	 		ispref = 0;		/* Flag: Is a preference. */
3779   int			i = 0;			/* Index of current argv. */
3780 
3781   myargv = dk3_new_app(DK3_PCDKCHAR,(argc+1),app);
3782   if(myargv) {
3783     ptr = myargv;
3784     for(i = 0; i < (argc + 1); i++) { *(ptr++) = NULL; }
3785     ptr = myargv; myargc = 0; sptr = argv;
3786     for(i = 0; i < argc; i++) {
3787       tptr = *(sptr++);
3788       ispref = 0;
3789       if(*tptr == DK3_CHAR_MINUS) {
3790         if(tptr[1] == DK3_CHAR_MINUS) {
3791 	  if(tptr[2] == DK3_CHAR_SLASH) {
3792 	    ispref = 1;
3793 	  }
3794 	}
3795       }
3796       if(ispref) {
3797         dk3app_save_one_preference(app, &(tptr[2]));
3798       } else {
3799         *ptr = dk3str_dup_app(tptr, NULL);
3800 	if(*ptr) {
3801 	  myargc++;
3802 	  ptr++;
3803 	} else {
3804 	  app->de = 1;
3805 	}
3806       }
3807     }
3808     app->argc = myargc; app->argv = myargv;
3809   }
3810 }
3811 
3812 
3813 
3814 /**	Save application group name.
3815 	@param	app	Application structure.
3816 	@param	gn	Group name to save.
3817 */
3818 static
3819 void
dk3app_save_group_name(dk3_app_t * app,dkChar const * gn)3820 dk3app_save_group_name(dk3_app_t *app, dkChar const *gn)
3821 {
3822 
3823   app->n_appgroup = dk3str_dup_app(gn,NULL);
3824   if(!(app->n_appgroup)) {
3825     app->de = 18;
3826   }
3827 }
3828 
3829 
3830 
3831 /**	Retrieve preferences from a storage.
3832 	@param	app	Application structure for diagnostics, may be NULL.
3833 	@param	p	Storage iterator.
3834 	@param	k	Key (preference name).
3835 	@param	d	Destination buffer.
3836 	@param	s	Size of \a d (number of characters).
3837 	@return	1 on success, 0 on error.
3838 */
3839 static
3840 int
dk3app_sto_pref(dk3_app_t * app,dk3_sto_it_t * p,dkChar const * k,dkChar * d,size_t s)3841 dk3app_sto_pref(
3842   dk3_app_t *app, dk3_sto_it_t *p, dkChar const *k, dkChar *d, size_t s)
3843 {
3844   int back = 0;
3845   dk3app_pref_t	pr;		/* Used for comparisons in search. */
3846   dk3app_pref_t	*pref = NULL;	/* Entry found. */
3847 
3848   if(p) {
3849     pr.k = k; pr.v = NULL;
3850     pref = (dk3app_pref_t *)dk3sto_it_find_like(p, &pr, 0);
3851     if(pref) {
3852       if(pref->v) {
3853         if(dk3str_len(pref->v) < s) {
3854 	  dk3str_cpy_not_overlapped(d, pref->v);
3855 	  back = 1;
3856 	} else {
3857 	  if(app) {
3858 	    /* Destination buffer too short! */
3859             dk3app_log_i1(app, DK3_LL_ERROR, 38);
3860 	  }
3861 	}
3862       }
3863     }
3864   }
3865   return back;
3866 }
3867 
3868 
3869 
3870 /**	Find number of entries for a string table file.
3871 	@param	dv	String table value array.
3872 	@return	Number of entries in array, including final NULL entry.
3873 */
3874 static
3875 size_t
dk3app_mc_array_size(dkChar const * const * dv)3876 dk3app_mc_array_size(dkChar const * const *dv)
3877 {
3878   size_t		back = 0;
3879   dkChar const	* const *ptr = NULL;	/* Traverse the dv array. */
3880 
3881   if(dv) {
3882     ptr = dv;
3883     while(*(ptr++)) { back++; }
3884     back++;
3885   }
3886   return back;
3887 }
3888 
3889 
3890 
3891 void
dk3app_squeeze_line(char * lb)3892 dk3app_squeeze_line(char *lb)
3893 {
3894   char *pd = NULL;	/* Destination in copy operations. */
3895   char *ps = NULL;	/* Source in copy operations. */
3896   char *px = NULL;	/* Position to continue. */
3897   ps = lb;
3898 
3899   /* Remove trailing newline. */
3900   while(*ps) {
3901     if((*ps == '\r') || (*ps == '\n')) {
3902       *ps = '\0';
3903     } else {
3904       ps++;
3905     }
3906   }
3907   /* Correct escape sequences */
3908   ps = lb;
3909   while(*ps) {
3910     if(*ps == '\\') {
3911       px = pd = ps; ps++;
3912       if(*ps) {
3913         switch(*ps) {
3914 	  case 't': {
3915 	    *(pd++) = '\t'; ps++;
3916 	    dk3str_c8_cpy(pd, ps);
3917 	  } break;
3918 	  case 'n': {
3919 	    *(pd++) = '\n'; ps++;
3920 	    dk3str_c8_cpy(pd, ps);
3921 	  } break;
3922 	  case 'r': {
3923 	    *(pd++) = '\r'; ps++;
3924 	    dk3str_c8_cpy(pd, ps);
3925 	  } break;
3926 	  default: {
3927 	    dk3str_c8_cpy(pd, ps);
3928 	  } break;
3929 	}
3930         ps = px; ps++;
3931       }
3932     } else {
3933       ps++;
3934     }
3935   }
3936 }
3937 
3938 
3939 
3940 /**	Get message catalog contents.
3941 	@param	app	Application structure.
3942 	@param	fn	File name for message catalog.
3943 	@param	dv	Default values.
3944 	@param	verb	Flag: Diagnostics enabled.
3945 	@return	Pointer to message array.
3946 */
3947 static
3948 dkChar const * const *
dk3app_my_messages(dk3_app_t * app,dkChar const * fn,dkChar const * const * dv,int verb)3949 dk3app_my_messages(
3950   dk3_app_t *app, dkChar const *fn, dkChar const * const *dv, int verb
3951 )
3952 {
3953   dkChar const	* const *back = NULL;
3954   dkChar const	*source_file = NULL;	/* File name for source file. */
3955   dk3app_mc_t	mc;			/* Used for comparisons. */
3956   dk3app_mc_t	*mcptr = NULL;		/* Message catalog. */
3957   int		errors_occured = 0;	/* Flag: We had errors. */
3958   unsigned long	source_line = 0UL;	/* Number of source line. */
3959   unsigned long line_number = 0UL;	/* NUmber of current line. */
3960   size_t	sz_defaults = 0;	/* Number entries in default table. */
3961   size_t	i = 0;			/* Walk through table. */
3962   size_t	current_index = 0;	/* Index of current entry to process. */
3963   dkChar	fnb[DK3_MAX_PATH];	/* File name buffer. */
3964   char		lb[4096];		/* Input line (8-bit characters). */
3965   dkChar const	**rb = NULL;		/* Array of strings to return. */
3966   FILE		*fipo;			/* Input file. */
3967 
3968   if((app) && (fn) && (dv)) {
3969     /* Find array size. */
3970     sz_defaults = dk3app_mc_array_size(dv);
3971     if(sz_defaults) {
3972       if((app->s_mc) && (app->i_mc)) {
3973         mc.n = fn; mc.msg = NULL; mc.f = 0; mc.nmsg = sz_defaults;
3974         mcptr = (dk3app_mc_t *)dk3sto_it_find_like(app->i_mc, &mc, 0);
3975         if(mcptr) {
3976           if(mcptr->nmsg >= sz_defaults) {
3977 	    back = mcptr->msg;
3978 	  } else {
3979 	    errors_occured = 1;	/* Too short */
3980 	  }
3981         } else {
3982 	}
3983       } else {
3984       }
3985       if((!(back)) && (errors_occured == 0)) {
3986         if(dk3app_my_find_data_file(app, fn, fnb, DK3_MAX_PATH, verb)) {
3987 	  source_file = dk3app_get_source_file(app);
3988 	  source_line = dk3app_get_source_line(app);
3989 	  dk3app_set_source_file(app, fnb);
3990 	  dk3app_set_source_line(app, 0UL);
3991 /* UTF8 */ fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[22], (verb ? app : NULL));
3992 	  if(fipo) {
3993 	    rb = dk3_new_app(DK3_PCDKCHAR,sz_defaults,(verb ? app : NULL));
3994 	    if(rb) {
3995 	      for(i = 0; i < sz_defaults; i++) { rb[i] = NULL; }
3996 	      current_index = 0;
3997 	      /* We explicitly used 8-bit characters, the file is UTF-8 */
3998 	      while(fgets(lb, sizeof(lb), fipo)) {
3999 	        line_number++;
4000 		dk3app_set_source_line(app, line_number);
4001 	        if(lb[0] != '#') {
4002 	          dk3app_squeeze_line(lb);
4003 	          if(current_index < (sz_defaults - 1)) {
4004 #if DK3_CHAR_SIZE > 1
4005 #if DK3_CHAR_SIZE > 2
4006 #error	"Can not handle 4-byte characters here!"
4007 #else
4008 		        rb[current_index] =
4009 			(dkChar const *)dk3str_cnvnew_c8u_to_c16_app(
4010 			  lb, (verb ? app : NULL)
4011 			);
4012 			if(rb[current_index]) {
4013 			  current_index++;
4014 			} else {
4015 			  errors_occured = 2;
4016 			}
4017 #endif
4018 #else
4019 
4020 		        switch(app->i_encoding) {
4021 		          case DK3_ENCODING_PLAIN: {
4022 			  rb[current_index] =
4023 			  dk3str_cnvnew_c8u_to_c8p_app(lb, (verb ? app : NULL));
4024 			  if(rb[current_index]) {
4025 			    current_index++;
4026 			  } else {
4027 			    errors_occured = 2;
4028 			  }
4029 			  } break;
4030 			  default: {
4031 			  rb[current_index] =
4032 			  dk3str_dup_app(lb, (verb ? app : NULL));
4033 			  if(rb[current_index]) {
4034 			    current_index++;
4035 			  } else {
4036 			    errors_occured = 2;
4037 			  }
4038 			  } break;
4039 		        }
4040 #endif
4041 		  }
4042 	          /* current_index++; */
4043 	        }
4044 	      }
4045 	      dk3app_set_source_line(app, 0UL);
4046 	      if((current_index >= (sz_defaults - 1)) && (!(errors_occured))) {
4047 	        if(!(app->s_mc)) {
4048 		  app->s_mc = dk3sto_open_app(verb ? app : NULL);
4049 		  if(app->s_mc) {
4050 		    dk3sto_set_comp(app->s_mc, dk3app_mc_compare, 0);
4051 		  } else {
4052 		  }
4053 		}
4054 		if(!(app->i_mc)) {
4055 		  if(app->s_mc) {
4056 		    app->i_mc = dk3sto_it_open(app->s_mc);
4057 		  } else {
4058 		  }
4059 		}
4060 		if((app->s_mc) && (app->i_mc)) {
4061 		  mcptr =
4062 		  dk3app_mc_new(fn, rb, sz_defaults, 1, (verb ? app: NULL));
4063 		  if(mcptr) {
4064 		    if(dk3sto_add(app->s_mc, mcptr)) {
4065 		      back = rb;
4066 		    } else {
4067 		      dk3app_mc_table_delete(rb, sz_defaults); rb = NULL;
4068 		    }
4069 		  } else {
4070 		    dk3app_mc_table_delete(rb, sz_defaults); rb = NULL;
4071 		  }
4072 		} else {
4073 		  dk3app_mc_table_delete(rb, sz_defaults); rb = NULL;
4074 		}
4075 	      } else {	/* Error occured or not enough strings. */
4076 	        if(errors_occured) {
4077 		  if(verb) {
4078 		    /* Errors while reading file! */
4079 		  }
4080 		} else {
4081 		  if(verb) {
4082 		    /* Too few entries in file! */
4083 		  }
4084 		}
4085 	        dk3app_mc_table_delete(rb, sz_defaults);
4086 		rb = NULL;
4087 	      }
4088 	    } else {
4089 	    }
4090 	    fclose(fipo);
4091 	  } else {
4092 	  }
4093           dk3app_set_source_file(app, source_file);
4094 	  dk3app_set_source_line(app, source_line);
4095         } else {
4096 	}
4097       } else {
4098       }
4099     } else {
4100     }
4101     if(!(back)) {
4102       back = dv;
4103     }
4104   } else {
4105   }
4106   return back;
4107 }
4108 
4109 
4110 
4111 /**	Read one preferences file.
4112 	@param	app	Application structure.
4113 	@param	fn	File name to process.
4114 	@param	s	Storage to save preference entries.
4115 	@param	i	Iterator through storage.
4116 */
4117 static
4118 void
dk3app_rd_pref_file(dk3_app_t * app,dkChar const * fn,dk3_sto_t * s,dk3_sto_it_t * i)4119 dk3app_rd_pref_file(
4120   dk3_app_t *app, dkChar const *fn, dk3_sto_t *s, dk3_sto_it_t *i
4121 )
4122 {
4123   dkChar	buffer[4096];
4124   char		bombuf[4];
4125   dkChar	*p1 = NULL;		/* Preference key (name). */
4126   dkChar	*p2 = NULL;		/* Preference value. */
4127   dkChar	*p3 = NULL;		/* Scope attribute value. */
4128   dkChar const	*oldsourcename;		/* Old source file name. */
4129   FILE		*fipo = NULL;		/* Input file. */
4130   unsigned long	lineno = 0UL;		/* Current line number. */
4131   unsigned long	oldsourceline;		/* Old source line number. */
4132   size_t	skb;			/* Bytes to skip at start. */
4133   int		scope_valid = 1;	/* Flag: In a valid scope. */
4134   int		last_was_scope = 0;	/* Flag: Previous line was scope. */
4135   int		scope_action = 0;	/* 0=yes, 1=no */
4136   int		conditions_ok;		/* Flag: All conditions ok. */
4137   int		ie = DK3_FILE_ENCODING_ASCII;	/* Input encoding. */
4138 
4139   skb = 0;
4140   ie = dk3sf_inspect_bom_skip_app(fn, DK3_FILE_ENCODING_ASCII, &skb, NULL);
4141   dk3app_log_i3(app, DK3_LL_DEBUG, 230, 231, fn);
4142   fipo = dk3sf_fopen_app(fn, dk3app_no_loc[22], NULL);	/* READ */
4143   if(fipo) {
4144     oldsourcename = dk3app_get_source_file(app);
4145     oldsourceline = dk3app_get_source_line(app);
4146     dk3app_set_source_file(app, fn);
4147     dk3app_set_source_line(app, 0UL);
4148     (void)dk3sf_apply_bom_to_file_app(fipo, ie, NULL);
4149     lineno = 0UL;
4150     if((skb > 0) && (skb <= 4)) { dk3sf_fread_app(bombuf, 1, skb, fipo, NULL); }
4151     while(dk3sf_fgets(buffer, DK3_SIZEOF(buffer,dkChar), fipo)) {
4152       lineno++;
4153       dk3app_set_source_line(app, lineno);
4154       p1 = dk3str_start(buffer, NULL);
4155       if(p1) {
4156         if(*p1 != dkT('#')) {
4157 	  if(*p1 == dkT('[')) {
4158 	    if(!last_was_scope) { scope_valid = 0; }
4159 	    scope_action = 0;
4160 	    p2 = dk3str_chr(p1, dkT(']'));
4161 	    if(p2) { *p2 = dkT('\0'); }
4162 	    p1++;
4163 	    dk3str_chomp(p1, NULL);
4164 	    if(*p1 == dkT('-')) { scope_action = 1; p1++; }
4165 	    p1 = dk3str_start(p1, NULL);
4166 	    conditions_ok = 1;
4167 	    while(p1) {
4168 	      p2 = dk3str_chr(p1, dkT(','));
4169 	      if(p2) {
4170 	        *(p2++) = dkT('\0');
4171 		p2 = dk3str_start(p2, NULL);
4172 	      }
4173 	      p3 = dk3str_chr(p1, dkT('='));
4174 	      if(p3) {
4175 	        *(p3++) = dkT('\0');
4176 		p3 = dk3str_start(p3, NULL);
4177 		if(p3) {
4178 		  dk3str_chomp(p1, NULL);
4179 		  dk3str_chomp(p3, NULL);
4180 		  switch(dk3str_array_index(dk3app_scope_attributes, p1, 0))
4181 		  {
4182 		    case 0: {	/* user */
4183 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4184 		        if(app->n_logname) {
4185 #if DK3_ON_WINDOWS || DK3_HAVE_USER_NAMES_CASE_INSENSITIVE
4186 			  if(dk3str_casecmp(p3, app->n_logname)) {
4187 			    conditions_ok = 0;
4188 			  }
4189 #else
4190 			  if(dk3str_cmp(p3, app->n_logname)) {
4191 			    conditions_ok = 0;
4192 			  }
4193 #endif
4194 			} else {
4195 			  conditions_ok = 0;
4196 			}
4197 		      }
4198 		    } break;
4199 		    case 1: {	/* application */
4200 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4201 		        if(app->n_app) {
4202 #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS
4203 			  if(dk3str_casecmp(p3, app->n_app)) {
4204 			    conditions_ok = 0;
4205 			  }
4206 #else
4207 			  if(dk3str_cmp(p3, app->n_app)) { conditions_ok = 0; }
4208 #endif
4209 			} else { conditions_ok = 0; }
4210 		      }
4211 		    } break;
4212 		    case 2: {	/* application-group */
4213 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4214 		        if(app->n_appgroup) {
4215 
4216 #if DK3_ON_WINDOWS || DK3_HAVE_FNCASEINS
4217 			  if(dk3str_casecmp(p3, app->n_appgroup)) {
4218 			    conditions_ok = 0;
4219 			  }
4220 #else
4221 			  if(dk3str_cmp(p3, app->n_appgroup)) {
4222 			    conditions_ok = 0;
4223 			  }
4224 #endif
4225 			} else { conditions_ok = 0; }
4226 		      }
4227 		    } break;
4228 		    case 3: {	/* host */
4229 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4230 		        if(app->n_hostname) {
4231 			  if(dk3str_casecmp(p3, app->n_hostname)) {
4232 			    conditions_ok = 0;
4233 			  }
4234 			} else { conditions_ok = 0; }
4235 		      }
4236 		    } break;
4237 		    case 4: {	/* language */
4238 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4239 		        if(app->n_language) {
4240 			  if(dk3str_cmp(p3, app->n_language)) {
4241 			    conditions_ok = 0;
4242 			  }
4243 			} else { conditions_ok = 0; }
4244 		      }
4245 		    } break;
4246 		    case 5: {	/* region */
4247 		      if(dk3str_cmp(p3, dk3app_no_loc[33])) {
4248 		        if(app->n_region) {
4249 			  if(dk3str_cmp(p3, app->n_region)) {
4250 			    conditions_ok = 0;
4251 			  }
4252 			} else { conditions_ok = 0; }
4253 		      }
4254 		    } break;
4255 		  }
4256 		}
4257 	      }
4258 	      p1 = p2;
4259 	    }
4260 	    last_was_scope = 1;
4261 	    if(conditions_ok) {
4262 	      if(scope_action) {
4263 	        scope_valid = 0;
4264 	      } else {
4265 	        scope_valid = 1;
4266 	      }
4267 	    }
4268 	  } else {
4269 	    last_was_scope = 0;
4270 	    if(scope_valid) {
4271 	      dk3str_chomp(p1, NULL);
4272 	      p2 = dk3str_chr(p1, dkT('='));
4273 	      if(p2) {
4274 	        *(p2++) = dkT('\0');
4275 	        p2 = dk3str_start(p2, NULL);
4276 	        if(p2) {
4277 	          dk3str_chomp(p1, NULL);
4278 	          dk3str_chomp(p2, NULL);
4279 	          if(!dk3app_add_pref(NULL, s, i, p1, p2)) {
4280 	            app->de = 33;
4281 	          }
4282 	        }
4283 	      }
4284 	    }
4285 	  }
4286 	}
4287       }
4288     }
4289     fclose(fipo);
4290     dk3app_set_source_file(app, oldsourcename);
4291     dk3app_set_source_line(app, oldsourceline);
4292   } else {
4293     dk3app_log_i3(app, DK3_LL_DEBUG, 152, 153, fn);
4294   }
4295 }
4296 
4297 
4298 
4299 /**	Read all preference files for an application.
4300 	@param	app	Application structure.
4301 */
4302 static
4303 void
dk3app_read_preference_files(dk3_app_t * app)4304 dk3app_read_preference_files(dk3_app_t *app)
4305 {
4306   dkChar	fnb[DK3_MAX_PATH];	/* File name buffer. */
4307   int		i = 0;			/* Pass. */
4308 
4309   for(i = 0; i < 16; i++) {
4310     if(dk3app_config_name(app, dk3app_no_loc[21], fnb, DK3_MAX_PATH, i, 0)) {
4311       switch(i) {
4312         case 14: {
4313 	  if(!(app->s_varprefs)) {
4314 	    app->s_varprefs = dk3sto_open_app(NULL);
4315 	    if(app->s_varprefs) {
4316 	      dk3sto_set_comp(app->s_varprefs, dk3app_compare_pref, 0);
4317 	    } else {
4318 	      app->de = 36;
4319 	    }
4320 	  }
4321 	  if(!(app->i_varprefs)) {
4322 	    if(app->s_varprefs) {
4323 	      app->i_varprefs = dk3sto_it_open(app->s_varprefs);
4324 	      if(!(app->i_varprefs)) { app->de = 36; }
4325 	    }
4326 	  }
4327 	  if((app->s_varprefs) && (app->i_varprefs)) {
4328 	    dk3app_rd_pref_file(app, fnb, app->s_varprefs, app->i_varprefs);
4329 	  }
4330 	} break;
4331 	case 12: case 13: case 15: {
4332 	  if(!(app->s_constprefs)) {
4333 	    app->s_constprefs = dk3sto_open_app(NULL);
4334 	    if(app->s_constprefs) {
4335 	      dk3sto_set_comp(app->s_constprefs, dk3app_compare_pref, 0);
4336 	    } else {
4337 	      app->de = 36;
4338 	    }
4339 	  }
4340 	  if(!(app->i_constprefs)) {
4341 	    if(app->s_constprefs) {
4342 	      app->i_constprefs = dk3sto_it_open(app->s_constprefs);
4343 	      if(!(app->i_constprefs)) { app->de = 36; }
4344 	    }
4345 	  }
4346 	  if((app->s_constprefs) && (app->i_constprefs)) {
4347 	    dk3app_rd_pref_file(app,fnb,app->s_constprefs,app->i_constprefs);
4348 	  }
4349 	} break;
4350 	default: {
4351 	  if(!(app->s_sysprefs)) {
4352 	    app->s_sysprefs = dk3sto_open_app(NULL);
4353 	    if(app->s_sysprefs) {
4354 	      dk3sto_set_comp(app->s_sysprefs, dk3app_compare_pref, 0);
4355 	    } else { app->de = 36; }
4356 	  }
4357 	  if(!(app->i_sysprefs)) {
4358 	    if(app->s_sysprefs) {
4359 	      app->i_sysprefs = dk3sto_it_open(app->s_sysprefs);
4360 	      if(!(app->i_sysprefs)) { app->de = 36; }
4361 	    }
4362 	  }
4363 	  if((app->s_sysprefs) && (app->i_sysprefs)) {
4364 	    dk3app_rd_pref_file(app, fnb, app->s_sysprefs, app->i_sysprefs);
4365 	  }
4366 	} break;
4367       }
4368     }
4369   }
4370 }
4371 
4372 
4373 
4374 /**	Find log level.
4375 	@param	app	Application structure.
4376 	@param	ind	Index of preference name in \a dk3app_no_loc.
4377 	@param	buffer	Buffer for preference value.
4378 	@param	sz	Size of \a buffer (number of characters).
4379 	@param	dv	Default value to use if preference is not set.
4380 	@return	Log level found in preference or default value.
4381 */
4382 static
4383 int
dk3app_find_ll(dk3_app_t * app,int ind,dkChar * buffer,size_t sz,int dv)4384 dk3app_find_ll(dk3_app_t *app, int ind, dkChar *buffer, size_t sz, int dv)
4385 {
4386   int		back = 0;
4387   dkChar	*p1 = NULL;	/* Value string. */
4388   int		i = 0;		/* Index search result. */
4389   back = dv;
4390 
4391   if(dk3app_get_pref(app, dk3app_no_loc[ind], buffer, sz)) {
4392     p1 = dk3str_start(buffer, NULL);
4393     if(p1) {
4394 
4395       dk3str_chomp(p1, NULL);
4396 
4397       i = dk3str_array_abbr(dk3app_log_levels, p1, dkT('$'), 0);
4398       if(i >= 0) {
4399         if(i <= DK3_LL_IGNORE) {
4400 	  back = i;
4401 	}
4402       } else {
4403       }
4404     } else {
4405     }
4406   } else {
4407   }
4408   return back;
4409 }
4410 
4411 
4412 
4413 /**	Preferences processing at application startup.
4414 	@param	app	Application structure.
4415 */
4416 static
4417 void
dk3app_process_preferences(dk3_app_t * app)4418 dk3app_process_preferences(dk3_app_t *app)
4419 {
4420   dkChar	buffer[4096];
4421   dkChar	*p1 = NULL;	/* Start of language/region/encoding string. */
4422   dkChar	*p2 = NULL;	/* Encoding, later region. */
4423   dkChar	*p3 = NULL;	/* Used to convert to lower case. */
4424   dkChar	*p4 = NULL;	/* New string for region. */
4425   int		i;		/* Input encoding. */
4426   if(dk3app_get_pref(app,dk3app_no_loc[27],buffer,DK3_SIZEOF(buffer,dkChar)))
4427   {
4428     p1 = dk3str_start(buffer, NULL);
4429     if(p1) {
4430       p2 = dk3str_chr(buffer, dkT('.'));
4431       if(p2) { *p2 = dkT('\0'); }
4432       p2 = dk3str_chr(buffer, dkT('_'));
4433       if(p2) {
4434         *(p2++) = dkT('\0');
4435 	p2 = dk3str_start(p2, NULL);
4436 	if(p2) {
4437 	  dk3str_chomp(p2, NULL);
4438 	  p3 = p2; while(*p3) { *p3 = dk3str_tolower(*p3); p3++; }
4439 	}
4440       }
4441       p3 = p1; while(*p3) { *p3 = dk3str_tolower(*p3); p3++; }
4442       dk3str_chomp(p1, NULL);
4443       p3 = dk3str_dup_app(p1, NULL);
4444       p4 = NULL;
4445       if(p2) { p4 = dk3str_dup_app(p2, NULL); }
4446       if(p3) {
4447         dk3_delete(app->n_language);
4448 	app->n_language = p3;
4449       }
4450       if(p4) {
4451         dk3_delete(app->n_region);
4452 	app->n_region = p4;
4453       }
4454     }
4455   }
4456   app->ll_file = dk3app_find_ll(
4457     app, 28, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_file
4458   );
4459   app->ll_file_keep = dk3app_find_ll(
4460     app, 29, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_file_keep
4461   );
4462   app->ll_stderr = dk3app_find_ll(
4463     app, 30, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_stderr
4464   );
4465   app->ll_tmp_keep = dk3app_find_ll(
4466     app, 31, buffer, DK3_SIZEOF(buffer,dkChar), app->ll_tmp_keep
4467   );
4468   app->i_stdin_input_encoding = dk3app_get_default_stdin_encoding(app);
4469 
4470   app->i_file_input_encoding = dk3app_get_default_file_encoding(app);
4471   if(dk3app_get_pref(app,dk3app_no_loc[51],buffer,DK3_SIZEOF(buffer,dkChar)))
4472   {
4473     p1 = dk3str_start(buffer, NULL);
4474     if(p1) {
4475       dk3str_chomp(p1, NULL);
4476       i = dk3enc_get_text_encoding_app(buffer, NULL);
4477       if(i >= 0) {
4478         app->i_file_input_encoding = i;
4479       }
4480     }
4481   }
4482   if(dk3app_get_pref(app,dk3app_no_loc[52],buffer,DK3_SIZEOF(buffer,dkChar)))
4483   {
4484     p1 = dk3str_start(buffer, NULL);
4485     if(p1) {
4486       dk3str_chomp(p1, NULL);
4487       i = dk3enc_get_text_encoding_app(buffer, NULL);
4488       if(i >= 0) {
4489         app->i_stdin_input_encoding = i;
4490 
4491       }
4492     }
4493   }
4494 
4495 }
4496 
4497 
4498 
4499 /**	Create new application.
4500 	@param	wd	Current working directory.
4501 	@param	argc	Number of command line arguments.
4502 	@param	argv	Command line arguments array.
4503 	@param	gn	Application group name.
4504 	@param	tp	Application type.
4505 	@return	Pointer to new application on success, NULL on error.
4506 */
4507 static
4508 dk3_app_t *
dk3app_open(dkChar const * wd,int argc,dkChar const * const * argv,dkChar const * gn,int tp)4509 dk3app_open(
4510   dkChar const * wd,
4511   int argc, dkChar const * const * argv,
4512   dkChar const *gn,
4513   int tp
4514 )
4515 {
4516   dk3_app_t *back = NULL;
4517 
4518   back = dk3_new(dk3_app_t,1);
4519   if(back) {
4520     dk3app_init(back);
4521     switch(tp) {
4522       case DK3_APP_TYPE_DAEMON: {
4523         back->ll_file = DK3_LL_INFO;
4524       } break;
4525     }
4526     back->app_type = tp;
4527     if(!(back->de)) { dk3app_save_group_name(back, gn); }
4528     if(!(back->de)) { dk3app_first_silence_check(back, argc, argv); }
4529     if(!(back->de)) { dk3app_language_and_region(back); }
4530     if(!(back->de)) { dk3app_find_names(back, wd, argv); }
4531     if(!(back->de)) { dk3app_save_arguments(back, argc, argv); }
4532     if(!(back->de)) { dk3app_read_preference_files(back); }
4533     if(!(back->de)) { dk3app_process_preferences(back); }
4534     if(!(back->de)) {
4535       back->msg = dk3app_my_messages(back, dk3app_no_loc[23], dk3app_kw, 0);
4536     }
4537     back->f_readytolog = 1;
4538     if(back->de) {
4539       /* Delayed error occured. Report error, destroy structure. */
4540       switch(back->de) {
4541         case 1:		/* Error while saving command line arguments. */
4542 	case 2:		/* Error while saving application name. */
4543 	case 4:		/* Error while saving exec file name. */
4544 	case 6:		/* Error while saving bin directory. */
4545 	case 7:		/* Error while saving etc directory. */
4546 	case 8:		/* Error while saving share directory. */
4547 	case 9:		/* Error while saving var directory. */
4548 	case 15:	/* Error while saving logname. */
4549 	case 17:	/* Error while saving home directory. */
4550 	case 18:	/* Error while saving application group name. */
4551 	case 21:	/* Error while saving log file name. */
4552 	case 25:	/* Error while saving temp dir name. */
4553 	case 28:	/* Error while saving language string. */
4554 	case 29:	/* Failed to save region! */
4555 	case 30:	/* Failed to save language! */
4556 	case 33:	/* Pref */
4557 	case 34:	/* Pref storage */
4558 	case 35:	/* Cmd prefs iterator */
4559 	case 36:	/* Cmd prefs storage */
4560 	case 37:	/* Store host name */
4561 	{
4562 	  dk3app_log_i1(back, DK3_LL_ERROR, 9);
4563 	} break;
4564 	case 3:		/* Failed to find executable file name. */
4565 	{
4566 	  /* Failed to find executable file name. */
4567 	  dk3app_log_i1(back, DK3_LL_ERROR, 40);
4568 	} break;
4569 	case 5:		/* Incomplete exec file name. */
4570 	{
4571 	  /* No separator in executable file name! */
4572 	  dk3app_log_i1(back, DK3_LL_ERROR, 40);
4573 	} break;
4574 	case 10:	/* Program is started from root directory. */
4575 	{
4576 	  /* Too few directories in hierarchy! */
4577 	  dk3app_log_i1(back, DK3_LL_ERROR, 41);
4578 	} break;
4579 	case 11:	/* Error while creating etc directory name! */
4580 	case 12:	/* Error while creating share directory name! */
4581 	case 13:	/* Error while creating var directory name! */
4582 	{
4583 	  /* Name of executable file too long! */
4584 	  dk3app_log_i1(back, DK3_LL_ERROR, 42);
4585 	} break;
4586 	case 14: {	/* Failed to retrieve log name! */
4587 	  /* Failed to retrieve log name! */
4588 	  dk3app_log_i1(back, DK3_LL_ERROR, 43);
4589 	} break;
4590 	case 16: {	/* Failed to retrieve home directory! */
4591 	  /* Failed to retrieve home directory! */
4592 	  dk3app_log_i1(back, DK3_LL_ERROR, 44);
4593 	} break;
4594 	case 19: {	/* Log file name too long. */
4595 	  /* Log file name gets too long! */
4596 	  dk3app_log_i1(back, DK3_LL_ERROR, 45);
4597 	} break;
4598 	case 20: {
4599 	  /* Failed to create log directory! */
4600 	  dk3app_log_i1(back, DK3_LL_ERROR, 46);
4601 	} break;
4602 	case 22: {
4603 	  /* Failed to convert PID to dkChar! */
4604 	  dk3app_log_i1(back, DK3_LL_ERROR, 47);
4605 	} break;
4606 	case 23: {
4607 	  /* Home directory name missing! */
4608 	  dk3app_log_i1(back, DK3_LL_ERROR, 44);
4609 	} break;
4610 	case 24: {
4611 	  /* Application name missing! */
4612 	  dk3app_log_i1(back, DK3_LL_ERROR, 48);
4613 	} break;
4614 	case 26: {
4615 	  /* Name of tmp dir gets too long! */
4616 	  dk3app_log_i1(back, DK3_LL_ERROR, 49);
4617 	} break;
4618 	case 27: {
4619 	  /* var dir name missing! */
4620 	  dk3app_log_i1(back, DK3_LL_ERROR, 50);
4621 	} break;
4622 	case 31: {
4623 	  /* Preference name too long! */
4624 	  dk3app_log_i1(back, DK3_LL_ERROR, 51);
4625 	} break;
4626 	case 32: {
4627 	  /* Not a preference entry! */
4628 	  dk3app_log_i1(back, DK3_LL_ERROR, 52);
4629 	} break;
4630 	case 38: {
4631 	  dk3app_log_i1(back, DK3_LL_ERROR, 131);
4632 	} break;
4633       }
4634       dk3app_close(back);
4635       back = NULL;
4636     } else {
4637       dk3app_log_i3(back, DK3_LL_DEBUG, 19, 20, back->n_app);
4638       dk3app_log_i2(
4639         back, DK3_LL_DEBUG, 23,
4640 	((back->n_app) ? back->n_app: ((back->msg) ? back->msg : dk3app_kw)[36])
4641       );
4642       dk3app_log_i2(
4643         back, DK3_LL_DEBUG, 24,
4644 	((back->n_appgroup) ? back->n_appgroup: ((back->msg) ? back->msg : dk3app_kw)[36])
4645       );
4646       dk3app_log_i2(
4647         back, DK3_LL_DEBUG, 25,
4648 	((back->n_execfile) ? back->n_execfile: ((back->msg) ? back->msg : dk3app_kw)[36])
4649       );
4650       dk3app_log_i2(
4651         back, DK3_LL_DEBUG, 26,
4652 	((back->n_bindir) ? back->n_bindir: ((back->msg) ? back->msg : dk3app_kw)[36])
4653       );
4654       dk3app_log_i2(
4655         back, DK3_LL_DEBUG, 27,
4656 	((back->n_etcdir) ? back->n_etcdir: ((back->msg) ? back->msg : dk3app_kw)[36])
4657       );
4658       dk3app_log_i2(
4659         back, DK3_LL_DEBUG, 28,
4660 	((back->n_sharedir) ? back->n_sharedir: ((back->msg) ? back->msg : dk3app_kw)[36])
4661       );
4662       dk3app_log_i2(
4663         back, DK3_LL_DEBUG, 29,
4664 	((back->n_vardir) ? back->n_vardir: ((back->msg) ? back->msg : dk3app_kw)[36])
4665       );
4666       dk3app_log_i2(
4667         back, DK3_LL_DEBUG, 30,
4668 	((back->n_homedir) ? back->n_homedir: ((back->msg) ? back->msg : dk3app_kw)[36])
4669       );
4670       dk3app_log_i2(
4671         back, DK3_LL_DEBUG, 31,
4672 	((back->n_tmpdir) ? back->n_tmpdir: ((back->msg) ? back->msg : dk3app_kw)[36])
4673       );
4674       dk3app_log_i2(
4675         back, DK3_LL_DEBUG, 32,
4676 	((back->n_logname) ? back->n_logname: ((back->msg) ? back->msg : dk3app_kw)[36])
4677       );
4678       dk3app_log_i2(
4679         back, DK3_LL_DEBUG, 132,
4680 	((back->n_hostname) ? back->n_hostname: ((back->msg) ? back->msg : dk3app_kw)[36])
4681       );
4682       dk3app_log_i2(
4683         back, DK3_LL_DEBUG, 33,
4684 	((back->n_logfilename) ? back->n_logfilename: ((back->msg) ? back->msg : dk3app_kw)[36])
4685       );
4686       dk3app_log_i2(
4687         back, DK3_LL_DEBUG, 34,
4688 	((back->n_language) ? back->n_language: ((back->msg) ? back->msg : dk3app_kw)[36])
4689       );
4690       dk3app_log_i2(
4691         back, DK3_LL_DEBUG, 35,
4692 	((back->n_region) ? back->n_region: ((back->msg) ? back->msg : dk3app_kw)[36])
4693       );
4694     }
4695   } else {
4696     if(tp == DK3_APP_TYPE_COMMAND) {
4697       /* ERROR: Not enough memory */
4698       dk3sf_initialize_stderr();
4699       dk3sf_fputs(dk3app_kw[9], stderr);
4700       dk3sf_fputs(dk3app_kw[0], stderr);
4701       fflush(stderr);
4702     }
4703   }
4704   return back;
4705 }
4706 
4707 
4708 
4709 dk3_app_t *
dk3app_open_command(int argc,dkChar const * const * argv,dkChar const * gn)4710 dk3app_open_command(int argc, dkChar const * const * argv, dkChar const *gn)
4711 {
4712   dk3_app_t	*back = NULL;
4713   dkChar	wd[DK3_MAX_PATH];	/* Current working directory. */
4714   if((argc) && (argv) && (gn)) {
4715     if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar), NULL)) {
4716       back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_COMMAND);
4717     } else {
4718       /* ERROR: Failed to find current working directory. */
4719       if(!dk3app_first_silence_check(NULL, argc, argv)) {
4720         dk3sf_initialize_stderr();
4721 	dk3sf_fputs(dk3app_kw[3], stderr);
4722 	dk3sf_fputs(dk3app_kw[11], stderr);
4723 	dk3sf_fputs(dk3app_kw[8], stderr);
4724 	dk3sf_fputs(dk3app_kw[53], stderr);
4725 	dk3sf_fputs(dk3app_kw[0],  stderr);
4726 	fflush(stderr);
4727       }
4728     }
4729   }
4730   return back;
4731 }
4732 
4733 
4734 
4735 dk3_app_t *
dk3app_open_gui(int argc,dkChar const * const * argv,dkChar const * gn)4736 dk3app_open_gui(int argc, dkChar const * const * argv, dkChar const *gn)
4737 {
4738   dk3_app_t	*back = NULL;
4739   dkChar	wd[DK3_MAX_PATH];	/* Current working directory. */
4740   if((argc) && (argv) && (gn)) {
4741     if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar),NULL)) {
4742       back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_GUI);
4743     } else {
4744       /* ERROR: Failed to find current working directory. */
4745     }
4746   }
4747   return back;
4748 }
4749 
4750 
4751 
4752 dk3_app_t *
dk3app_open_daemon(dkChar const * wd,int argc,dkChar const * const * argv,dkChar const * gn)4753 dk3app_open_daemon(
4754   dkChar const *wd, int argc, dkChar const * const * argv, dkChar const *gn
4755 )
4756 {
4757   dk3_app_t	*back = NULL;
4758   if((wd) && (argc) && (argv) && (gn)) {
4759     back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_DAEMON);
4760   }
4761   return back;
4762 }
4763 
4764 
4765 
4766 dk3_app_t *
dk3app_open_silent(int argc,dkChar const * const * argv,dkChar const * gn)4767 dk3app_open_silent(int argc, dkChar const * const * argv, dkChar const *gn)
4768 {
4769   dk3_app_t	*back = NULL;
4770   dkChar	wd[DK3_MAX_PATH];	/* Current working directory. */
4771   if((argc) && (argv) && (gn)) {
4772     if(dk3sf_getcwd_app(wd, DK3_SIZEOF(wd,dkChar),NULL)) {
4773       back = dk3app_open(wd, argc, argv, gn, DK3_APP_TYPE_SILENT);
4774     } else {
4775       /* ERROR: Failed to find current working directory. */
4776     }
4777   }
4778   return back;
4779 }
4780 
4781 
4782 
4783 dkChar const * const *
dk3app_get_argv(dk3_app_t const * app)4784 dk3app_get_argv(dk3_app_t const *app)
4785 {
4786   dkChar const * const *back = NULL;
4787   if(app) { back = (dkChar const * const *)(app->argv); }
4788   return back;
4789 }
4790 
4791 
4792 
4793 int
dk3app_get_argc(dk3_app_t const * app)4794 dk3app_get_argc(dk3_app_t const *app)
4795 {
4796   int back = 0;
4797   if(app) { back = app->argc; }
4798   return back;
4799 }
4800 
4801 
4802 
4803 dkChar const *
dk3app_get_appname(dk3_app_t const * app)4804 dk3app_get_appname(dk3_app_t const *app)
4805 {
4806   dkChar const *back = NULL;
4807   if(app) {
4808     back = app->n_app;
4809   }
4810   return back;
4811 }
4812 
4813 
4814 
4815 dkChar const *
dk3app_get_execfilename(dk3_app_t const * app)4816 dk3app_get_execfilename(dk3_app_t const *app)
4817 {
4818   dkChar const *back = NULL;
4819   if(app) {
4820     back = app->n_execfile;
4821   }
4822   return  back;
4823 }
4824 
4825 
4826 
4827 dkChar const *
dk3app_get_bindir(dk3_app_t const * app)4828 dk3app_get_bindir(dk3_app_t const *app)
4829 {
4830   dkChar const *back = NULL;
4831   if(app) {
4832     back = app->n_bindir;
4833   }
4834   return back;
4835 }
4836 
4837 
4838 
4839 dkChar const *
dk3app_get_etcdir(dk3_app_t const * app)4840 dk3app_get_etcdir(dk3_app_t const *app)
4841 {
4842   dkChar const *back = NULL;
4843   if(app) {
4844     back = app->n_etcdir;
4845   }
4846   return back;
4847 }
4848 
4849 
4850 
4851 dkChar const *
dk3app_get_sharedir(dk3_app_t const * app)4852 dk3app_get_sharedir(dk3_app_t const *app)
4853 {
4854   dkChar const *back = NULL;
4855   if(app) {
4856     back = app->n_sharedir;
4857   }
4858   return back;
4859 }
4860 
4861 
4862 
4863 dkChar const *
dk3app_get_vardir(dk3_app_t const * app)4864 dk3app_get_vardir(dk3_app_t const *app)
4865 {
4866   dkChar const *back = NULL;
4867   if(app) {
4868     back = app->n_vardir;
4869   }
4870   return back;
4871 }
4872 
4873 
4874 
4875 dkChar const *
dk3app_get_logname(dk3_app_t const * app)4876 dk3app_get_logname(dk3_app_t const *app)
4877 {
4878   dkChar const *back = NULL;
4879   if(app) {
4880     back = app->n_logname;
4881   }
4882   return back;
4883 }
4884 
4885 
4886 
4887 dkChar const *
dk3app_get_hostname(dk3_app_t const * app)4888 dk3app_get_hostname(dk3_app_t const *app)
4889 {
4890   dkChar const *back = NULL;
4891   if(app) {
4892     back = app->n_hostname;
4893   }
4894   return back;
4895 }
4896 
4897 
4898 
4899 dkChar const *
dk3app_get_homedir(dk3_app_t const * app)4900 dk3app_get_homedir(dk3_app_t const *app)
4901 {
4902   dkChar const *back = NULL;
4903   if(app) {
4904     back = app->n_homedir;
4905   }
4906   return back;
4907 }
4908 
4909 
4910 
4911 dkChar const *
dk3app_get_appgroup(dk3_app_t const * app)4912 dk3app_get_appgroup(dk3_app_t const *app)
4913 {
4914   dkChar const *back = NULL;
4915   if(app) {
4916     back = app->n_appgroup;
4917   }
4918   return back;
4919 }
4920 
4921 
4922 
4923 int
dk3app_get_temp_file_name(dk3_app_t * app,dkChar * db,size_t sz)4924 dk3app_get_temp_file_name(dk3_app_t *app, dkChar *db, size_t sz)
4925 {
4926   int		back = 0;
4927   char		fn[16];		/* BUffer for sprintf(). */
4928   dkChar	fn2[16];	/* Short file name buffer. */
4929   size_t	s = 0;		/* Buffer length needed. */
4930 
4931   if((app) && (db) && (sz)) {
4932     if(app->n_tmpdir) {
4933       if ((DK3_APP_TYPE_DAEMON != app->app_type) && (0 == app->cr_tmp)) {
4934         dk3app_create_tmp_directory(app);
4935 	app->cr_tmp = 1;
4936       }
4937       if(!(app->i_tmpcarry)) {
4938         sprintf(fn, "/%08lx.%03x", app->ul_tmpname, app->u_tmpsuffix);
4939         back = 1;
4940         if ((0UL == app->ul_tmpname) && (0 == app->u_tmpsuffix)) {
4941 	  if (DK3_APP_TYPE_DAEMON != app->app_type) {
4942 
4943 
4944 	    if (0 == dk3sf_mkdir_app(app->n_tmpdir, 0700, NULL)) {
4945 	      back = 0;
4946 	    }
4947 	  }
4948 	}
4949         app->u_tmpsuffix += 1U;
4950         if(app->u_tmpsuffix >= 0x1000U) {
4951           app->u_tmpsuffix = 0U;
4952 #if VERSION_BEFORE_20150318
4953 	  app->ul_tmpname += 1UL;
4954 	  if(app->ul_tmpname == 0UL) {
4955 	    app->i_tmpcarry = 1;
4956 	    back = 0;
4957 	    /* Too many temporary file names asked! */
4958 	    dk3app_log_i1(app, DK3_LL_ERROR, 54);
4959 	  }
4960 #else
4961 	  /*	2015-03-18	We better check the variable before adding 1.
4962 				Unsigned long may be larger than 32 bits.
4963 	  */
4964 	  if (0xFFFFFFFFUL > app->ul_tmpname) {
4965 	    app->ul_tmpname += 1UL;
4966 	  } else {
4967 	    app->i_tmpcarry = 1;
4968 	    back = 0;
4969 	    /* Too many temporary file names asked! */
4970 	    dk3app_log_i1(app, DK3_LL_ERROR, 54);
4971 	  }
4972 #endif
4973         }
4974         if(back) {
4975           back = 0;
4976 	  if(dk3str_cnv_c8_to_str_app(fn2, 15, fn, app)) {
4977 	    s = dk3str_len(app->n_tmpdir) + dk3str_len(fn2);
4978 	    if(s < sz) {
4979 	      dk3str_cpy_not_overlapped(db, app->n_tmpdir);
4980 	      dk3str_cat(db, fn2);
4981 	      dk3str_correct_filename(db);
4982 	      back = 1;
4983 	    } else {
4984 	      /* Destination buffer too small! */
4985 	      dk3app_log_i1(app, DK3_LL_ERROR, 38);
4986 	    }
4987 	  }
4988         }
4989       }
4990     } else {
4991       /* Not directory for temporary files available! */
4992       dk3app_log_i1(app, DK3_LL_ERROR, 55);
4993     }
4994   }
4995   return back;
4996 }
4997 
4998 
4999 
5000 dkChar const *
dk3app_get_language(dk3_app_t const * app)5001 dk3app_get_language(dk3_app_t const *app)
5002 {
5003   dkChar const *back = NULL;
5004   if(app) { back = app->n_language; }
5005   return back;
5006 }
5007 
5008 
5009 
5010 dkChar const *
dk3app_get_region(dk3_app_t const * app)5011 dk3app_get_region(dk3_app_t const *app)
5012 {
5013   dkChar const *back = NULL;
5014   if(app) { back = app->n_region; }
5015   return back;
5016 }
5017 
5018 
5019 
5020 int
dk3app_get_encoding(dk3_app_t const * app)5021 dk3app_get_encoding(dk3_app_t const *app)
5022 {
5023   int back = 0;
5024   if(app) { back = app->i_encoding; }
5025   return back;
5026 }
5027 
5028 
5029 
5030 int
dk3app_get_output_encoding(dk3_app_t const * app)5031 dk3app_get_output_encoding(dk3_app_t const *app)
5032 {
5033   int back = 0;
5034   if(app) { back = app->i_output_encoding; }
5035   return back;
5036 }
5037 
5038 
5039 
5040 int
dk3app_get_input_stdin_encoding(dk3_app_t const * app)5041 dk3app_get_input_stdin_encoding(dk3_app_t const *app)
5042 {
5043   int back = 0;
5044   if(app) { back = app->i_stdin_input_encoding; }
5045   return back;
5046 }
5047 
5048 
5049 
5050 int
dk3app_get_input_file_encoding(dk3_app_t const * app)5051 dk3app_get_input_file_encoding(dk3_app_t const *app)
5052 {
5053   int back = 0;
5054   if(app) { back = app->i_file_input_encoding; }
5055   return back;
5056 }
5057 
5058 
5059 
5060 int
dk3app_set_pref(dk3_app_t * app,dkChar const * k,dkChar const * v)5061 dk3app_set_pref(dk3_app_t *app, dkChar const *k, dkChar const *v)
5062 {
5063   int back = 0;
5064   if((app) && (k) && (v)) {
5065     if(!(app->s_selfprefs)) {
5066       app->s_selfprefs = dk3sto_open_app(app);
5067       if(app->s_selfprefs) {
5068         dk3sto_set_comp(app->s_selfprefs, dk3app_compare_pref, 0);
5069       }
5070     }
5071     if(!(app->i_selfprefs)) {
5072       if(app->s_selfprefs) {
5073         app->i_selfprefs = dk3sto_it_open(app->s_selfprefs);
5074       }
5075     }
5076     if((app->s_selfprefs) && (app->i_selfprefs)) {
5077       back = dk3app_add_pref(app, app->s_selfprefs, app->i_selfprefs, k, v);
5078       app->f_prefschanged = 1;
5079     }
5080     if(!back) {
5081       /* Failed to save preference value! */
5082       dk3app_log_i5(app, DK3_LL_ERROR, 56, 57, 58, k, v);
5083     }
5084   }
5085   return back;
5086 }
5087 
5088 
5089 
5090 int
dk3app_get_pref(dk3_app_t * app,dkChar const * k,dkChar * d,size_t s)5091 dk3app_get_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s)
5092 {
5093   int back = 0;
5094 
5095   if((app) && (k) && (d) && (s)) {
5096 
5097     back = dk3app_sto_pref(app, app->i_selfprefs, k, d, s);
5098     if(back == 0) {
5099       back = dk3app_sto_pref(app, app->i_cmdprefs, k, d, s);
5100       if(back == 0) {
5101         back = dk3app_sto_pref(app, app->i_varprefs, k, d, s);
5102 	if(back == 0) {
5103 	  back = dk3app_sto_pref(app, app->i_constprefs, k, d, s);
5104 	  if(back == 0) {
5105 	    back = dk3app_sto_pref(app, app->i_sysprefs, k, d, s);
5106 	  }
5107 	}
5108       }
5109     }
5110 
5111 
5112 
5113   }
5114   return back;
5115 }
5116 
5117 
5118 
5119 int
dk3app_get_sys_pref(dk3_app_t * app,dkChar const * k,dkChar * d,size_t s)5120 dk3app_get_sys_pref(dk3_app_t *app, dkChar const *k, dkChar *d, size_t s)
5121 {
5122   int back = 0;
5123   if((app) && (k) && (d) && (s)) {
5124     back = dk3app_sto_pref(app, app->i_selfprefs, k, d, s);
5125     if(back == 0) {
5126       back = dk3app_sto_pref(app, app->i_sysprefs, k, d, s);
5127     }
5128   }
5129   return back;
5130 }
5131 
5132 
5133 
5134 /**	Check whether the use of system configuration files
5135 	is allowed for a file name.
5136 	@param	app	Application structure.
5137 	@param	fn	Short file name.
5138 	@return	1 for system config files allowed, 0 for user files only.
5139 */
5140 static
5141 int
dk3app_allow_system_config_files(dk3_app_t * app,dkChar const * fn)5142 dk3app_allow_system_config_files(dk3_app_t *app, dkChar const *fn)
5143 {
5144   int back = 1;
5145   dkChar	fnb[DK3_MAX_PATH];		/* File name buffer. */
5146   dkChar	il[1024 + DK3_MAX_PATH];	/* Input line buffer. */
5147   char		bombuf[4];			/* Buffer to skip BOM. */
5148   dkChar	*p1 = NULL;			/* Key (entry name). */
5149   dkChar	*p2 = NULL;			/* Value. */
5150   FILE		*fipo = NULL;			/* Input file. */
5151   int		ie = DK3_FILE_ENCODING_ASCII;	/* Input encoding for file. */
5152   int		cc = 1;				/* Flag: Can continue. */
5153   size_t	sz = 0;				/* Buffer size needed. */
5154   size_t	skb;				/* Number of bytes to skip. */
5155   if(app->n_homedir) {
5156     sz = dk3str_len(app->n_homedir);
5157     sz += (2 * dk3str_len(dk3app_no_loc[20]));
5158     sz += dk3str_len(dk3app_no_loc[18]);
5159     sz += dk3str_len(dk3app_no_loc[34]);
5160     if(sz < DK3_SIZEOF(fnb,dkChar)) {
5161       dk3str_cpy_not_overlapped(fnb, app->n_homedir);
5162       dk3str_cat(fnb, dk3app_no_loc[20]);
5163       dk3str_cat(fnb, dk3app_no_loc[18]);
5164       dk3str_cat(fnb, dk3app_no_loc[20]);
5165       dk3str_cat(fnb, dk3app_no_loc[34]);
5166       skb = 0;
5167       ie = dk3sf_inspect_bom_skip_app(fnb, DK3_FILE_ENCODING_ASCII, &skb, NULL);
5168       fipo = dk3sf_fopen_app(fnb, dk3app_no_loc[22], NULL);	/* READ */
5169       if(fipo) {
5170         (void)dk3sf_apply_bom_to_file_app(fipo, ie, NULL);
5171         cc = 1;
5172 	if((skb > 0) && (skb <= 4)) {
5173 	  dk3sf_fread_app(bombuf, 1, skb, fipo, NULL);
5174 	}
5175         while(cc) {
5176 	  if(dk3sf_fgets(il, DK3_SIZEOF(il,dkChar), fipo)) {
5177 	    p1 = dk3str_start(il, NULL);
5178 	    if(p1) {
5179 	      if(*p1 != dkT('#')) {
5180 	        p2 = dk3str_chr(p1, dkT('='));
5181 		if(p2) {
5182 		  *(p2++) = dkT('\0');
5183 		  p2 = dk3str_start(p2, NULL);
5184 		  if(p2) {
5185 		    dk3str_chomp(p2, NULL);
5186 		    dk3str_normalize(p1, NULL, dkT('-'));
5187 		    switch(dk3str_array_index(dk3app_conf_file, p1, 0)) {
5188 		      case 0: {	/* use system config files */
5189 		        if(dk3str_cmp(p2, dk3app_no_loc[33]) == 0) {
5190 			  back = 1; cc = 0;
5191 			} else {
5192 			  if(dk3str_cmp(p2, fn) == 0) {
5193 			    back = 1; cc = 0;
5194 			  }
5195 			}
5196 		      } break;
5197 		      case 1: {	/* ignore system config files */
5198 		        if(dk3str_cmp(p2, dk3app_no_loc[33]) == 0) {
5199 			  back = 0; cc = 0;
5200 			} else {
5201 			  if(dk3str_cmp(p2, fn) == 0) {
5202 			    back = 0; cc = 0;
5203 			  }
5204 			}
5205 		      } break;
5206 		    }
5207 		  }
5208 		}
5209 	      }
5210 	    }
5211 	  } else { cc = 0;}
5212 	}
5213         fclose(fipo);
5214       }
5215     } else {
5216       /* ERROR: Home directory name too long! */
5217       dk3app_log_i1(app, DK3_LL_ERROR, 194);
5218     }
5219   }
5220   return back;
5221 }
5222 
5223 
5224 
5225 /**	Find configuration files for a given name.
5226 	@param	app	Application structure.
5227 	@param	fn	File name.
5228 	@param	res	Flag: Reverse search order.
5229 	@param	exclu	Flag: Exclude user files.
5230 	@return	Pointer to search result collection on success, NULL on error.
5231 */
5232 static
5233 dk3_search_t *
dk3app_my_find_config_file(dk3_app_t * app,dkChar const * fn,int res,int exclu)5234 dk3app_my_find_config_file(dk3_app_t *app, dkChar const *fn, int res, int exclu)
5235 {
5236   dk3_search_t *back = NULL;
5237   unsigned long	items_found = 0;	/* Number of items found. */
5238   int		error_occured = 0;	/* Flag: Error occured. */
5239   int		i = 0;			/* Current pass number. */
5240   int		r = 0;			/* Result from check for conf file. */
5241   int		max = 0;		/* Maximum pass number. */
5242   int		min = 0;		/* Minimum pass number. */
5243   dkChar	buffer[DK3_MAX_PATH];	/* File name buffer. */
5244   if((app) && (fn)) {
5245     back = dk3search_open_app(res, app);
5246     if(back) {
5247       min = 0; max = 16;
5248       if(app->app_type == DK3_APP_TYPE_DAEMON) {
5249         max = 6;
5250       } else {
5251         if(exclu) {
5252 	  max = 12;
5253 	} else {
5254           if(!dk3app_allow_system_config_files(app, fn)) {
5255 	    min = 12;
5256 	    /* DEBUG: System config files skipped by user. */
5257 	    dk3app_log_i1(app, DK3_LL_DEBUG, 195);
5258 	  }
5259 	}
5260       }
5261       for(i = min; i < max; i++) {
5262         r = dk3app_check_config_file(app, fn, buffer, DK3_MAX_PATH, i, 1);
5263 	if(r) {
5264 	  if(dk3search_add(back, buffer)) {
5265 	    items_found++;
5266 	  } else {
5267 	    error_occured = 1;
5268 	  }
5269 	}
5270       }
5271       if(error_occured) {
5272         dk3search_close(back); back = NULL;
5273       } else {
5274         if(items_found == 0UL) {
5275 	  dk3search_close(back); back = NULL;
5276 	}
5277       }
5278     }
5279   }
5280   return back;
5281 }
5282 
5283 
5284 
5285 dk3_search_t *
dk3app_find_config_file(dk3_app_t * app,dkChar const * fn,int exclu)5286 dk3app_find_config_file(dk3_app_t *app, dkChar const *fn, int exclu)
5287 {
5288   dk3_search_t *back = NULL;
5289   if((app) && (fn)) {
5290     back = dk3app_my_find_config_file(app, fn, 0, exclu);
5291   }
5292   return back;
5293 }
5294 
5295 
5296 
5297 dk3_search_t *
dk3app_find_config_file_revers(dk3_app_t * app,dkChar const * fn,int exclu)5298 dk3app_find_config_file_revers(dk3_app_t *app, dkChar const *fn, int exclu)
5299 {
5300   dk3_search_t *back = NULL;
5301   if((app) && (fn)) {
5302     back = dk3app_my_find_config_file(app, fn, 1, exclu);
5303   }
5304   return back;
5305 }
5306 
5307 
5308 
5309 int
dk3app_find_data_file(dk3_app_t * app,dkChar const * fn,dkChar * db,size_t sz)5310 dk3app_find_data_file(dk3_app_t *app, dkChar const *fn, dkChar *db, size_t sz)
5311 {
5312   int back = 0;
5313   if((app) && (fn) && (db) && (sz)) {
5314     back = dk3app_my_find_data_file(app, fn, db, sz, 1);
5315   }
5316   return back;
5317 }
5318 
5319 
5320 
5321 void
dk3app_unconfigure(dk3_app_t * app)5322 dk3app_unconfigure(dk3_app_t *app)
5323 {
5324   if(app) { app->f_unconfigure = 1; }
5325 }
5326 
5327 
5328 
5329 dkChar const * const *
dk3app_messages(dk3_app_t * app,dkChar const * fn,dkChar const * const * dv)5330 dk3app_messages(dk3_app_t *app, dkChar const *fn, dkChar const * const *dv)
5331 {
5332   dkChar const * const *back;
5333 
5334   back = dk3app_my_messages(app, fn, dv, 0);
5335 
5336   return back;
5337 }
5338 
5339 
5340 
5341 void
dk3app_help(dk3_app_t * app,dkChar const * fn,dkChar const * const * dt)5342 dk3app_help(dk3_app_t *app, dkChar const *fn, dkChar const * const *dt)
5343 {
5344   int			had_success = 0;	/* Flag: Success. */
5345   dkChar		buffer[DK3_MAX_PATH];	/* File name buffer. */
5346   char			lb[1024];		/* Input line buffer. */
5347   dkChar		db[1024];		/* Output line buffer. */
5348   FILE			*fipo = NULL;		/* Input file. */
5349   dkChar const * const	*ptr = NULL;		/* Help text line. */
5350 
5351   if((app) && (fn) && (dt)) {
5352     dk3sf_initialize_stdout();
5353     if(dk3app_my_find_data_file(app, fn, buffer, DK3_SIZEOF(buffer,dkChar), 0))
5354     {
5355       fipo = dk3sf_fopen_app(buffer, dk3app_no_loc[22], app);	/* UTF-8 */
5356       if(fipo) {
5357         had_success = 1;
5358 	while(fgets(lb, sizeof(lb), fipo)) {
5359 #if DK3_CHAR_SIZE == 2
5360 	  if(dk3str_cnv_c8u_to_c16_app(db, DK3_SIZEOF(db,dkChar), lb, app)) {
5361 	        dk3sf_fputs(db, stdout);
5362 	  }
5363 #else
5364 	  switch(app->i_encoding) {
5365 	    case DK3_ENCODING_PLAIN: {
5366 	      if(dk3str_cnv_c8u_to_c8p_app(db, DK3_SIZEOF(db,dkChar), lb, app))
5367 	      {
5368 		fputs(db, stdout);
5369 	      }
5370 	    } break;
5371 	    default: {
5372 	      fputs(lb, stdout);
5373 	    } break;
5374 	  }
5375 #endif
5376 	}
5377         fclose(fipo);
5378       }
5379     }
5380     if(!had_success) {
5381       ptr = dt;
5382       while(*ptr) {
5383         dk3sf_fputs(*(ptr++), stdout);
5384 	dk3sf_fputc(dkT('\n'), stdout);
5385       }
5386     }
5387   }
5388 }
5389 
5390 
5391 
5392 int
dk3app_get_stderr_log_level(dk3_app_t const * app)5393 dk3app_get_stderr_log_level(dk3_app_t const *app)
5394 {
5395   int back = DK3_LL_ERROR;
5396   if(app) {
5397     back = app->ll_stderr;
5398   }
5399   return back;
5400 }
5401 
5402 
5403 
5404 void
dk3app_set_stderr_log_level(dk3_app_t * app,int ll)5405 dk3app_set_stderr_log_level(dk3_app_t *app, int ll)
5406 {
5407   if(app) {
5408     app->ll_stderr = ll;
5409   }
5410 }
5411 
5412 
5413 
5414 void
dk3app_log_write_error(dk3_app_t * app,int ll,size_t wished,size_t written)5415 dk3app_log_write_error(dk3_app_t *app, int ll, size_t wished, size_t written)
5416 {
5417   dkChar	b1[128];	/* Number of bytes wished to write. */
5418   dkChar	b2[128];	/* Number of bytes really written. */
5419 
5420   if (dk3ma_um_to_string(b1, DK3_SIZEOF(b1,dkChar), (dk3_um_t)wished)) {
5421     if (dk3ma_um_to_string(b2, DK3_SIZEOF(b2,dkChar), (dk3_um_t)written)) {
5422       dk3app_log_i5(app, ll, 170, 171, 172, b2, b1);
5423     }
5424   }
5425 }
5426 
5427 
5428 
5429 void
dk3app_log_fwrite_error(dk3_app_t * app,int ll,size_t wished,size_t written)5430 dk3app_log_fwrite_error(dk3_app_t *app, int ll, size_t wished, size_t written)
5431 {
5432   dkChar	b1[128];	/* Number of bytes wished to write. */
5433   dkChar	b2[128];	/* Number of bytes really written. */
5434   if (dk3ma_um_to_string(b1, DK3_SIZEOF(b1,dkChar), (dk3_um_t)wished)) {
5435     if (dk3ma_um_to_string(b2, DK3_SIZEOF(b2,dkChar), (dk3_um_t)written)) {
5436       dk3app_log_i5(app, ll, 174, 175, 176, b2, b1);
5437     }
5438   }
5439 }
5440 
5441 
5442 
5443 dkChar const *
dk3app_localized(dk3_app_t const * app,size_t num)5444 dk3app_localized(dk3_app_t const *app, size_t num)
5445 {
5446   dkChar const *back = NULL;
5447   if(app) {
5448     if(app->msg) {
5449       back = (app->msg)[num];
5450     } else {
5451       back = dk3app_kw[num];
5452     }
5453   }
5454   return back;
5455 }
5456 
5457 
5458 
5459 dkChar const *
dk3app_not_localized(size_t num)5460 dk3app_not_localized(size_t num)
5461 {
5462   dkChar const *back = NULL;
5463   back = dk3app_no_loc[num];
5464   return back;
5465 }
5466 
5467 
5468 
5469 int
dk3app_get_pref_bool(dk3_app_t * app,dkChar const * name,int dv)5470 dk3app_get_pref_bool(dk3_app_t *app, dkChar const *name, int dv)
5471 {
5472   int back;
5473   dkChar buffer[256];	/* Buffer for preference value. */
5474   dkChar *p1;		/* Start of text. */
5475   back = dv;
5476   if(app) {
5477     if(dk3app_get_pref(app, name, buffer, DK3_SIZEOF(buffer,dkChar))) {
5478       p1 = dk3str_start(buffer, NULL);
5479       if(p1) {
5480         dk3str_chomp(p1, NULL);
5481 	if(dk3str_is_bool(p1)) {
5482 	  back = ((dk3str_is_on(p1)) ? 1 : 0);
5483 	}
5484       }
5485     }
5486   }
5487   return back;
5488 }
5489 
5490 
5491 
5492 int
dk3app_get_pref_int(dk3_app_t * app,dkChar const * name,int dv)5493 dk3app_get_pref_int(dk3_app_t *app, dkChar const * name, int dv)
5494 {
5495   int back;
5496   int x;
5497   dkChar buffer[256];
5498   dkChar *p1;
5499 
5500   back = dv;
5501   if(app) {
5502     if(dk3app_get_pref(app, name, buffer, DK3_SIZEOF(buffer,dkChar))) {
5503       p1 = dk3str_start(buffer, NULL);
5504       if(p1) {
5505 #if VERSION_BEFORE_20140716
5506         if(dk3sf_sscanf3(p1, dkT("%d"), &x) == 1)
5507 #else
5508 	if (0 != dk3ma_i_from_string(&x, p1, NULL))
5509 #endif
5510 	{
5511           back = x;
5512         }
5513       }
5514     }
5515   }
5516   return back;
5517 }
5518 
5519 
5520 
5521 #if 0
5522 
5523 
5524 int
5525 dk3app_get_allowed_prng_types(dk3_app_t *app, dkChar const *il)
5526 {
5527   int back = 0;
5528   dkChar buffer[256];
5529   dkChar	*p1 = NULL;
5530   dkChar	*p2 = NULL;
5531   int		 i = 0;
5532   if((app) && (il)) {
5533     if(dk3str_len(il) < DK3_SIZEOF(buffer,dkChar)) {
5534       dk3str_cpy_not_overlapped(buffer, il);
5535       p1 = dk3str_start(buffer, NULL);
5536       while(p1) {
5537         p2 = dk3str_chr(p1, dkT(','));
5538 	if(p2) {
5539 	  *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL);
5540 	}
5541 	i = dk3str_array_index(dk3app_prng_type_names, p1, 0);
5542 	switch(i) {
5543 	  case 0: {
5544 #if DK3_HAVE_OPENSSL_RAND_H
5545 	    back |= DK3_PRNG_OPENSSL;
5546 #else
5547             /* ERROR: Openssl PRNG not available! */
5548 	    dk3app_log_i1(app, DK3_LL_ERROR, 192);
5549 #endif
5550 	  } break;
5551 	  case 1: {
5552 #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM
5553 	    back |= DK3_PRNG_STATE;
5554 #else
5555 	    /* ERROR: initstate()/setstate()/random() not available. */
5556 	    dk3app_log_i1(app, DK3_LL_ERROR, 191);
5557 #endif
5558 	  } break;
5559 	  case 2: {
5560 #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48
5561 	    back |= DK3_PRNG_RAND48;
5562 #else
5563 	    /* ERROR: lrand48()/lrand48() not available. */
5564 	    dk3app_log_i1(app, DK3_LL_ERROR, 190);
5565 #endif
5566 	  } break;
5567 	  case 3: {
5568 #if DK3_HAVE_RAND && DK3_HAVE_SRAND
5569 	    back |= DK3_PRNG_SIMPLE;
5570 #else
5571             /* ERROR: srand()/rand() not available! */
5572 	    dk3app_log_i1(app, DK3_LL_ERROR, 189);
5573 #endif
5574 	  } break;
5575 	  default: {
5576 	    /* Unknown PRNG type name! */
5577 	    dk3app_log_i3(app, DK3_LL_ERROR, 187, 188, p1);
5578 	  } break;
5579 	}
5580 	p1 = p2;
5581       }
5582     } else {
5583       /* ERROR: Line too long for buffer! */
5584       dk3app_log_i1(app, DK3_LL_ERROR, 38);
5585     }
5586   }
5587   return back;
5588 }
5589 
5590 
5591 
5592 /**	Find allowed PRNG types using preferences.
5593 	@param	app	Application structure.
5594 	@return	Or-combination of DK3_PRNG_xxx.
5595 */
5596 static
5597 int
5598 dk3app_rand_find_allowed_types(dk3_app_t *app)
5599 {
5600    int back = DK3_PRNG_ALL;
5601    dkChar	buffer[256];
5602 
5603    if(dk3app_get_pref(app,dk3app_no_loc[37],buffer,DK3_SIZEOF(buffer,dkChar)))
5604    {
5605      back = dk3app_get_allowed_prng_types(app, buffer);
5606    }
5607 
5608    return back;
5609 }
5610 
5611 
5612 
5613 /**	Get bytes to seed random number generator.
5614 	@param	app	Application structure.
5615 	@param	dp	Destination buffer pointer.
5616 	@param	sz	Number of bytes required.
5617 	@param	fn	File name for seed file.
5618 	@return	Number of bytes found.
5619 */
5620 static
5621 size_t
5622 dk3app_read_bytes_from_file(
5623   dk3_app_t *app,
5624   void *dp,
5625   size_t sz,
5626   dkChar const *fn
5627 )
5628 {
5629   size_t back = 0;
5630   FILE *fipo;
5631   fipo = dk3sf_fopen_app(fn, dk3app_no_loc[36], app);
5632   if(fipo) {
5633     back = dk3sf_fread_app(dp, 1, sz, fipo, app);
5634     fclose(fipo);
5635   }
5636   return back;
5637 }
5638 
5639 
5640 
5641 
5642 /**	Get bytes to seed random number generator.
5643 	@param	app	Application structure.
5644 	@param	dp	Destination buffer pointer.
5645 	@param	sz	Number of bytes required.
5646 	@param	fn	File name for seed file.
5647 	@return	Number of bytes found.
5648 */
5649 static
5650 size_t
5651 dk3app_get_seed_from_source(dk3_app_t *app,void *dp,size_t sz,dkChar const *fn)
5652 {
5653   size_t back = 0;
5654   dk3_stat_t	stb;
5655   int	can_use_file = 1;
5656   int	mode_denied;
5657 
5658   /* DEBUG: Attempting to get seed data from ... */
5659   dk3app_log_i3(app, DK3_LL_DEBUG, 196, 197, fn);
5660   if(dk3sf_stat_app(&stb, fn, NULL)) {
5661     switch((stb.ft) & (~(DK3_FT_SYMLINK))) {
5662       case DK3_FT_DIRECTORY: {
5663         /* Ignore it. */
5664       } break;
5665       case DK3_FT_REGULAR: {
5666         /* Security checks before using the file. */
5667 	mode_denied = DK3_FPERM_G_READ
5668 		    | DK3_FPERM_G_WRITE
5669 		    | DK3_FPERM_O_READ
5670 		    | DK3_FPERM_O_WRITE;
5671 	if((stb.ft) & DK3_FT_SYMLINK) {
5672 	  if((stb.ai) & DK3_STAT_AI_USER_DIFFERS) {
5673 	    can_use_file = 0;
5674 	    /* WARNING: Symlink owner is not file owner. */
5675 	    dk3app_log_i3(app, DK3_LL_ERROR, 185, 186, fn);
5676 	  }
5677 	  if((stb.perm) & mode_denied) {
5678 	    can_use_file = 0;
5679 	    /* WARNING: File not used (permissions). */
5680 	    dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn);
5681 	  } else {
5682 	    if((stb.lperm) & mode_denied) {
5683 	      can_use_file = 0;
5684 	      /* WARNING: File not used (permissions). */
5685 	      dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn);
5686 	    }
5687 	  }
5688 	} else {
5689 	  if((stb.perm) & mode_denied) {
5690 	    can_use_file = 0;
5691 	    /* WARNING: File not used (permissions). */
5692 	    dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn);
5693 	  }
5694 	}
5695 	if(can_use_file) {
5696 	  back = dk3app_read_bytes_from_file(app, dp, sz, fn);
5697 	}
5698       } break;
5699       default: {
5700         /* Use file. */
5701 	back = dk3app_read_bytes_from_file(app, dp, sz, fn);
5702       } break;
5703     }
5704   }
5705   /* DEBUG: Seed data: ... bytes. */
5706   {
5707     char b1[64];
5708     dkChar b2[64];
5709     sprintf(b1, "%lu", (unsigned long)back);
5710     if(dk3str_cnv_c8_to_str_app(b2, DK3_SIZEOF(b2,dkChar), b1, app)) {
5711       dk3app_log_i3(app, DK3_LL_DEBUG, 198, 199, b2);
5712     }
5713   }
5714   return back;
5715 }
5716 
5717 
5718 
5719 /**	Get bytes to seed random number generator.
5720 	@param	app	Application structure.
5721 	@param	dp	Destination buffer pointer.
5722 	@param	sz	Number of bytes required.
5723 	@param	fn	File name for seed file.
5724 	@param	passno	Pass number (only 0 uses files).
5725 	@return	Number of bytes found.
5726 */
5727 static
5728 size_t
5729 dk3app_get_seed_bytes(
5730   dk3_app_t *app,
5731   void *dp,
5732   size_t sz,
5733   dkChar const *fn,
5734   int passno
5735 )
5736 {
5737   size_t back = 0;
5738   dkChar const *p1;
5739   dkChar const *p2;
5740   dkChar const *p3;
5741   dkChar const *p4;
5742   dkChar const *p5;
5743   dkChar       *p6;
5744   size_t	s;
5745   dkChar fnb[DK3_MAX_PATH];	/* File name buffer. */
5746   if((app) && (dp) && (sz)) {
5747     /* $HOME/.rnd-xxx-application */
5748     if(passno == 0) {
5749       if(dk3app_get_pref_bool(app, dk3app_no_loc[46], 1)) {
5750         p1 = dk3app_get_homedir(app);
5751         p2 = dk3app_no_loc[20];
5752         p3 = fn;
5753         p4 = dk3app_no_loc[5];
5754         p5 = dk3app_get_appname(app);
5755         if((p1) && (p2) && (p3) && (p4) && (p5)) {
5756           s =  dk3str_len(p1);
5757 	  s += dk3str_len(p2);
5758 	  s += dk3str_len(p3);
5759 	  s += dk3str_len(p4);
5760 	  s += dk3str_len(p5);
5761 	  if(s < DK3_SIZEOF(fnb,dkChar)) {
5762 	    dk3str_cpy_not_overlapped(fnb, p1);
5763 	    dk3str_cat(fnb, p2);
5764 	    dk3str_cat(fnb, p3);
5765 	    dk3str_cat(fnb, p4);
5766 	    dk3str_cat(fnb, p5);
5767 	    back = dk3app_get_seed_from_source(app, dp, sz, fnb);
5768 	  }
5769         }
5770       }
5771     }
5772     /* EGD socket from environment. */
5773     if(back == 0) {
5774       p1 = dk3sf_getenv(dk3app_no_loc[43]);
5775       if(p1) {
5776         back = dk3app_get_seed_from_source(app, dp, sz, p1);
5777       }
5778     }
5779     /* EGD socket from preferences. */
5780     if(back == 0) {
5781       if(dk3app_get_pref(app, dk3app_no_loc[42], fnb, DK3_SIZEOF(fnb,dkChar)))
5782       {
5783         p6 = dk3str_start(fnb, NULL);
5784 	if(p6) {
5785 	  dk3str_chomp(p6, NULL);
5786 	  back = dk3app_get_seed_from_source(app, dp, sz, p6);
5787 	}
5788       }
5789     }
5790 #if !DK3_ON_WINDOWS
5791     /* /dev/urandom */
5792     if(back == 0) {
5793       back = dk3app_get_seed_from_source(app, dp, sz, dk3app_no_loc[44]);
5794     }
5795     /* /dev/random */
5796     if(back == 0) {
5797       back = dk3app_get_seed_from_source(app, dp, sz, dk3app_no_loc[45]);
5798     }
5799 #endif
5800   }
5801   return back;
5802 }
5803 
5804 
5805 
5806 #if DK3_HAVE_OPENSSL_H
5807 /**	Initialize OpenSSL PRNG.
5808 	@param	app	Application structure.
5809 	@return	1 on success, 0 on error.
5810 */
5811 static
5812 int
5813 dk3app_init_prng_openssl(dk3_app_t *app)
5814 {
5815   int back = 0;
5816   int cc = 0;
5817   int passno = 0;
5818   size_t sz;
5819   char seedval[DK3_SEED_OPENSSL_BYTES];
5820   do {
5821     cc = 0;
5822     sz =
5823     dk3app_get_seed_bytes(app,seedval,sizeof(seedval),dk3app_no_loc[41],passno);
5824     if(sz > 0) {
5825       cc = 1;
5826       RAND_seed(seedval, sz);
5827       if(RAND_status() == 1) {
5828         cc = 0; back = 1;
5829       }
5830 #if DK3_ON_WINDOWS
5831       if(back == 0) {
5832         RAND_screen();
5833 	if(RAND_status() == 1) {
5834 	  cc = 0; back = 1;
5835 	}
5836       }
5837 #endif
5838       passno++;
5839     }
5840   } while(cc);
5841   if(!back) {
5842     /* Warning: Failed to seed OpenSSL PRNG! */
5843     dk3app_log_i1(app, DK3_LL_ERROR, 182);
5844   }
5845   return back;
5846 }
5847 #endif
5848 
5849 #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM
5850 /**	Initialize state PRNG.
5851 	@param	app	Application structure.
5852 	@return	1 on success, 0 on error.
5853 */
5854 static
5855 int
5856 dk3app_init_prng_state(dk3_app_t *app)
5857 {
5858   int back = 0;
5859   unsigned int seedval = 0;
5860   if(dk3app_get_seed_bytes(
5861     app, (void *)(&seedval), sizeof(unsigned int), dk3app_no_loc[40], 0
5862     )
5863   )
5864   {
5865     srandom(seedval);
5866     back = 1;
5867   }
5868   if(!back) {
5869     /* Warning: Failed to seed random() PRNG! */
5870     dk3app_log_i1(app, DK3_LL_ERROR, 181);
5871   }
5872   return back;
5873 }
5874 #endif
5875 
5876 #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48
5877 /**	Initialize lrand48() PRNG.
5878 	@param	app	Application structure.
5879 	@return	1 on success, 0 on error.
5880 */
5881 static
5882 int
5883 dk3app_init_prng_rand48(dk3_app_t *app)
5884 {
5885   int back = 0;
5886   long int seedval = 0L;
5887   if(dk3app_get_seed_bytes(
5888       app, (void *)(&seedval), sizeof(long int), dk3app_no_loc[39], 0
5889     )
5890   )
5891   {
5892     srand48(seedval);
5893     back = 1;
5894   }
5895   if(!back) {
5896     /*Warning: Failed to seed lrand48() PRNG! */
5897     dk3app_log_i1(app, DK3_LL_ERROR, 180);
5898   }
5899   return back;
5900 }
5901 #endif
5902 
5903 #if DK3_HAVE_RAND && DK3_HAVE_SRAND
5904 /**	Initialize simple rand() PRNG.
5905 	@param	app	Application structure.
5906 	@return	1 on success, 0 on error.
5907 */
5908 static
5909 int
5910 dk3app_init_prng_simple(dk3_app_t *app)
5911 {
5912   int back = 0;
5913   unsigned int ui;
5914   if(
5915     dk3app_get_seed_bytes(
5916       app, (void *)(&ui), sizeof(unsigned int), dk3app_no_loc[38], 0
5917     )
5918   )
5919   {
5920     srand(ui);
5921     back = 1;
5922   }
5923   if(!back) {
5924     /* Warning: Failed to seed simple PRNG! */
5925     dk3app_log_i1(app, DK3_LL_ERROR, 179);
5926   }
5927   return back;
5928 }
5929 #endif
5930 
5931 
5932 
5933 /**	Attempt to initialize a PRNG.
5934 	@param	app	Application structure.
5935 	@param	il	Input line listing allowed PRNGs comma-separated.
5936 	@return	1 on success (at least one PRNG usable), 0 on error.
5937 */
5938 int
5939 dk3app_rand_init(dk3_app_t *app, dkChar const *il)
5940 {
5941   int back = 0;
5942   int allowed_types;
5943   if(app) {
5944     if(app->f_rand_initialized) {
5945       back = app->f_rand_success;
5946     } else {
5947       app->f_rand_initialized = 1;
5948       if(il) {
5949         allowed_types = dk3app_get_allowed_prng_types(app, il);
5950       } else {
5951         allowed_types = dk3app_rand_find_allowed_types(app);
5952       }
5953       if(!back) {
5954         if(allowed_types & DK3_PRNG_OPENSSL) {
5955 #if DK3_HAVE_OPENSSL_H
5956 	  back = dk3app_init_prng_openssl(app);
5957 	  if(back) {
5958 	    app->rand_type = DK3_PRNG_OPENSSL;
5959 	  }
5960 #endif
5961 	}
5962       }
5963       if(!back) {
5964         if(allowed_types & DK3_PRNG_STATE) {
5965 #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM
5966 	  back = dk3app_init_prng_state(app);
5967 	  if(back) {
5968 	    app->rand_type = DK3_PRNG_STATE;
5969 	  }
5970 #endif
5971 	}
5972       }
5973       if(!back) {
5974         if(allowed_types & DK3_PRNG_RAND48) {
5975 #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48
5976 	  back = dk3app_init_prng_rand48(app);
5977 	  if(back) {
5978 	    app->rand_type = DK3_PRNG_RAND48;
5979 	  }
5980 #endif
5981 	}
5982       }
5983       if(!back) {
5984         if(allowed_types & DK3_PRNG_SIMPLE) {
5985 #if DK3_HAVE_RAND && DK3_HAVE_SRAND
5986 	  back = dk3app_init_prng_simple(app);
5987 	  if(back) {
5988 	    app->rand_type = DK3_PRNG_SIMPLE;
5989 	  }
5990 #endif
5991 	}
5992       }
5993       if(back) {
5994         app->f_rand_success = 1;
5995       }
5996     }
5997   }
5998   if(!back) {
5999     /* ERROR: No PRNG usable! */
6000     dk3app_log_i1(app, DK3_LL_ERROR, 178);
6001   }
6002   return back;
6003 }
6004 
6005 
6006 
6007 /**	Get random bytes.
6008 	@param	app		Application structure.
6009 	@param	db		Destination buffer.
6010 	@param	sz		Size of \a db (number of bytes).
6011 	@param	f_crypto	Flag: For cryptographic purposes.
6012 	@return	Number of bytes written to \a db.
6013 */
6014 static
6015 size_t
6016 dk3app_rand_bytes_internal(dk3_app_t *app, void *db, size_t sz, int f_crypto)
6017 {
6018   size_t	back	= 0;
6019   unsigned char	*ucptr	= NULL;
6020   size_t	i	= 0;
6021   unsigned	u	= 0;
6022   if((app) && (db) && (sz)) {
6023     ucptr = (unsigned char *)db;
6024     if(!(app->f_rand_initialized)) {
6025       dk3app_rand_init(app, NULL);
6026     }
6027     if(app->f_rand_success) {
6028       switch(app->rand_type) {
6029         case DK3_PRNG_OPENSSL: {
6030 #if DK3_HAVE_OPENSSL_RAND_H
6031 	  if(f_crypto) {
6032 	    if(RAND_bytes(ucptr, (int)sz) == 1) {
6033 	      back = sz;
6034 	    }
6035 	  } else {
6036 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x1010000FL
6037 	    if(RAND_bytes(ucptr, (int)sz) == 1) {
6038 	      back = sz;
6039 	    }
6040 #else
6041 	    if(RAND_pseudo_bytes(ucptr, (int)sz) > -1) {
6042 	      back = sz;
6043 	    }
6044 #endif
6045 	  }
6046 #else
6047 	  /* BUG: Not available! */
6048 #endif
6049 	} break;
6050 	case DK3_PRNG_STATE: {
6051 #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM
6052 	  long lval;
6053 	  size_t position;
6054 
6055 	  lval = random() >> 8;
6056 	  position = 0;
6057 	  for(i = 0; i < sz; i++) {
6058 	    *(ucptr++) = (unsigned char)(lval & 0x000000FFL);
6059 	    position++;
6060 	    lval = lval >> 8;
6061 	    if(position >= (sizeof(long) - 1)) {
6062 	      lval = random() >> 8;
6063 	      position = 0;
6064 	    }
6065 	  }
6066 	  back = sz;
6067 #else
6068 	  /* BUG: Not available! */
6069 #endif
6070 	} break;
6071 	case DK3_PRNG_RAND48: {
6072 #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48
6073 	  long lval;
6074 	  size_t position;
6075 
6076 	  lval = lrand48() >> 8;
6077 	  position = 0;
6078 	  for(i = 0; i < sz; i++) {
6079 	    *(ucptr++) = (unsigned char)(lval & 0x000000FFL);
6080 	    position++;
6081 	    lval = lval >> 8;
6082 	    if(position >= (sizeof(long) - 1)) {
6083 	      lval = lrand48() >> 8;
6084 	      position = 0;
6085 	    }
6086 	  }
6087 	  back = sz;
6088 #else
6089 	  /* BUG: Not available! */
6090 #endif
6091 	} break;
6092 	default: {
6093 #if DK3_HAVE_RAND && DK3_HAVE_SRAND
6094 	  for(i = 0; i < sz; i++) {
6095 	    u = rand();
6096 #if DK3_SIZEOF_INT > 2
6097 #if DK3_SIZEOF_INT > 4
6098 	    u = u >> 28;
6099 #else
6100 	    u = u >> 12;
6101 #endif
6102 #else
6103 	    u = u >> 4;
6104 #endif
6105 	    u &= 0x00FFU;
6106 	    *(ucptr++) = (unsigned char)u;
6107 	  }
6108 	  back = sz;
6109 #else
6110 	  /* BUG: Not available! */
6111 #endif
6112 	} break;
6113       }
6114     }
6115   }
6116   if(back < sz) {
6117     /* ERROR: Failed to obtain enough random bytes! */
6118     dk3app_log_i1(app, DK3_LL_ERROR, 177);
6119   }
6120   return back;
6121 }
6122 
6123 
6124 size_t
6125 dk3app_rand_bytes(dk3_app_t *app, void *db, size_t sz)
6126 {
6127   size_t back;
6128   back = dk3app_rand_bytes_internal(app, db, sz, 1);
6129   return back;
6130 }
6131 
6132 
6133 size_t
6134 dk3app_rand_bytes_non_crypto(dk3_app_t *app, void *db, size_t sz)
6135 {
6136   size_t back;
6137   back = dk3app_rand_bytes_internal(app, db, sz, 0);
6138   return back;
6139 }
6140 
6141 #endif
6142 
6143 
6144 
6145 int
dk3app_process_stdin_lines(dk3_app_t * app,void * obj,dk3_line_handler_t * hf,dkChar * buffer,size_t szbuffer,int de)6146 dk3app_process_stdin_lines(
6147   dk3_app_t		*app,
6148   void			*obj,
6149   dk3_line_handler_t	*hf,
6150   dkChar		*buffer,
6151   size_t		 szbuffer,
6152   int			 de
6153 )
6154 {
6155   int		back = 0;
6156   int		must_run_directly = 0;
6157   int		ie;
6158   FILE		*fipo;
6159   dkChar	tfn[DK3_MAX_PATH];
6160   char		b[4096];
6161   size_t	sz;
6162 #if DK3_ON_WINDOWS
6163   int		oldmode;
6164 #endif
6165   if((app) && (hf) && (buffer) && (szbuffer)) {
6166     ie = de;
6167     if(ie < 0) { ie = app->i_stdin_input_encoding; }
6168     if(dk3app_get_temp_file_name(app, tfn, DK3_SIZEOF(tfn,dkChar))) {
6169       fipo = dk3sf_fopen_app(tfn, dk3app_no_loc[53], app);
6170       if(fipo) {
6171 #if DK3_ON_WINDOWS
6172       oldmode = _setmode(_fileno(stdin), _O_BINARY);
6173 #endif
6174         while((sz = dk3sf_fread_app(b, 1, sizeof(b), stdin, app)) > 0) {
6175 	  dk3sf_fwrite_app(b, 1, sz, fipo, app);
6176 	}
6177         fclose(fipo);
6178 #if DK3_ON_WINDOWS
6179 	_setmode(_fileno(stdin), oldmode);
6180 #endif
6181 /*	2015-08-21
6182 	Using ie instead of de.
6183 */
6184 	back = dk3stream_process_filename_lines_app(
6185 	  obj,
6186 	  hf,
6187 	  tfn,
6188 	  buffer,
6189 	  szbuffer,
6190 	  dk3app_get_encoding(app),
6191 	  ie,
6192 	  app
6193 	);
6194 	dk3sf_remove_file_app(tfn, app);
6195       } else {
6196         must_run_directly = 1;
6197       }
6198     } else {
6199       must_run_directly = 1;
6200     }
6201     if(must_run_directly) {
6202 #if DK3_ON_WINDOWS
6203       oldmode = _setmode(_fileno(stdin), _O_BINARY);
6204 #endif
6205       back = dk3stream_process_file_lines_app(
6206         obj,
6207 	hf,
6208 	stdin,
6209 	NULL,
6210 	buffer,
6211 	szbuffer,
6212 	dk3app_get_encoding(app),
6213 	de,
6214 	app
6215       );
6216 #if DK3_ON_WINDOWS
6217       _setmode(_fileno(stdin), oldmode);
6218 #endif
6219     }
6220   }
6221   return back;
6222 }
6223 
6224 
6225 
6226 int
dk3app_process_stdin_chars(dk3_app_t * app,void * obj,dk3_char_handler_t * hf,int de)6227 dk3app_process_stdin_chars(
6228   dk3_app_t		*app,
6229   void			*obj,
6230   dk3_char_handler_t	*hf,
6231   int			 de
6232 )
6233 {
6234   int		back = 0;
6235   int		must_run_directly = 0;
6236   int		ie;
6237   dkChar	tfn[DK3_MAX_PATH];
6238   char		b[4096];
6239   FILE		*fipo;
6240   size_t	sz;
6241 #if DK3_ON_WINDOWS
6242   int		oldmode;
6243 #endif
6244 
6245   if((app) && (hf)) {
6246     ie = de;
6247     if(ie < 0) {
6248       ie = app->i_stdin_input_encoding;
6249     }
6250     if(dk3app_get_temp_file_name(app, tfn, DK3_SIZEOF(tfn,dkChar))) {
6251       fipo = dk3sf_fopen_app(tfn, dk3app_no_loc[53], app);
6252       if(fipo) {
6253 #if DK3_ON_WINDOWS
6254 	oldmode = _setmode(_fileno(stdin), _O_BINARY);
6255 #endif
6256         while((sz = dk3sf_fread_app(b, 1, sizeof(b), stdin, app)) > 0) {
6257 	  dk3sf_fwrite_app(b, 1, sz, fipo, app);
6258 	}
6259         fclose(fipo);
6260 #if DK3_ON_WINDOWS
6261 	_setmode(_fileno(stdin), oldmode);
6262 #endif
6263 	back = dk3stream_process_filename_chars_app(obj, hf, tfn, ie, app);
6264 	dk3sf_remove_file_app(tfn, app);
6265       } else {
6266         must_run_directly = 1;
6267       }
6268     } else {
6269       must_run_directly = 1;
6270     }
6271     if(must_run_directly) {
6272 #if DK3_ON_WINDOWS
6273       oldmode = _setmode(_fileno(stdin), _O_BINARY);
6274 #endif
6275       back = dk3stream_process_file_chars_app(obj, hf, stdin, NULL, ie, app);
6276 #if DK3_ON_WINDOWS
6277       _setmode(_fileno(stdin), oldmode);
6278 #endif
6279     }
6280   }
6281   return back;
6282 }
6283 
6284 
6285 
6286 #if !DK3_ON_WINDOWS
6287 #if DK3_HAVE_SETUID && DK3_HAVE_SETGID && DK3_HAVE_CHOWN
6288 #if DK3_CHAR_SIZE == 1
6289 /**	Change owner for one file if the file exists.
6290 	@param	app	Application structure.
6291 	@param	ul1	File name.
6292 	@param	ul2	File name suffix.
6293 	@param	uid	New user ID for file ownership.
6294 	@param	gid	New group ID for file ownership.
6295 	@return	1 on success (owner modified or file does not exist).
6296 */
6297 static
6298 int
dk3app_change_owner_for_file(dk3_app_t * app,unsigned long ul1,unsigned ul2,uid_t uid,gid_t gid)6299 dk3app_change_owner_for_file(
6300   dk3_app_t	*app,
6301   unsigned long	 ul1,
6302   unsigned	 ul2,
6303   uid_t		 uid,
6304   gid_t		 gid
6305 )
6306 {
6307   dkChar		 fnb[DK3_MAX_PATH];	/* Full name buffer. */
6308   dkChar		 smb[32];		/* Small buffer. */
6309   char			 tmb[32];
6310   dk3_stat_t		 stb;
6311   int			 back = 1;
6312 
6313   sprintf(tmb, "/%08lx.%03x", ul1, ul2);
6314   if(dk3str_c8_to_str_simple_app(smb,DK3_SIZEOF(smb,dkChar),tmb,app)) {
6315     if(dk3str_len(app->n_tmpdir) < DK3_SIZEOF(fnb,dkChar)) {
6316       dk3str_cpy_not_overlapped(fnb, app->n_tmpdir);
6317       if((dk3str_len(fnb) + dk3str_len(smb)) < DK3_SIZEOF(fnb,dkChar)) {
6318         dk3str_cat(fnb, smb);
6319         dk3str_correct_filename(fnb);
6320         if(dk3sf_stat_app(&stb, fnb, NULL)) {
6321           if(0 != chown(fnb, uid, gid)) {
6322 	    back = 0;
6323 	  } else {
6324 	  }
6325         } else {
6326           /* If there is no such file, there is no need to change owner. */
6327         }
6328       } else {
6329         back = 0;
6330       }
6331     } else {
6332       back = 0;
6333     }
6334   } else {
6335   }
6336 
6337   return back;
6338 }
6339 
6340 int
dk3app_change_user(dk3_app_t * app,uid_t uid,gid_t gid)6341 dk3app_change_user(dk3_app_t *app, uid_t uid, gid_t gid)
6342 {
6343   FILE			*fipo;
6344   unsigned long		 ul1;
6345   unsigned 		 ul2;
6346   int			 back = 1;
6347 
6348   if((app) && ((uid) || (gid))) {
6349     if(app->n_logfilename) {
6350       if (0 == app->cr_log) {
6351         dk3app_create_log_directory(app);
6352 	app->cr_log = 1;
6353       }
6354       fipo = dk3sf_fopen_app(app->n_logfilename, dkT("a"), app);
6355       if(fipo) {
6356         fclose(fipo);
6357       }
6358       if(0 != chown(app->n_logfilename, uid, gid)) {
6359         back = 0;
6360       } else {
6361       }
6362     } else {
6363     }
6364     if(app->n_tmpdir) {
6365       if(0 != chown(app->n_tmpdir, uid, gid)) {
6366         back = 0;
6367       }
6368       if(app->i_tmpcarry) {
6369         for(ul1 = 0UL; ul1 < 0xFFFFFFFFUL; ul1++) {
6370 	  for(ul2 = 0U; ul2 < 0x00001000U; ul2++) {
6371 	    if(!dk3app_change_owner_for_file(app, ul1, ul2, uid, gid)) {
6372 	      back = 0;
6373 	    }
6374 	  }
6375 	}
6376 	for(ul2 = 0U; ul2 < 0x00001000U; ul2++) {
6377 	  if(!dk3app_change_owner_for_file(app, 0xFFFFFFFFUL, ul2, uid, gid)) {
6378 	    back = 0;
6379 	  }
6380 	}
6381       } else {
6382         for(ul1 = 0UL; ul1 < app->ul_tmpname; ul1++) {
6383 	  for(ul2 = 0U; ul2 < 0x00001000U; ul2++) {
6384 	    if(!dk3app_change_owner_for_file(app, ul1, ul2, uid, gid)) {
6385 	      back = 0;
6386 	    }
6387 	  }
6388 	}
6389 	for(ul2 = 0U; ul2 < app->u_tmpsuffix; ul2++) {
6390 	  if(!dk3app_change_owner_for_file(app,app->ul_tmpname,ul2,uid,gid)) {
6391 	    back = 0;
6392 	  }
6393 	}
6394       }
6395     } else {
6396     }
6397   } else {
6398   }
6399   return back;
6400 }
6401 #endif
6402 #endif
6403 #endif
6404 
6405 
6406 
6407 int
dk3app_get_dir_from_pref(dk3_app_t * app,dkChar const * pn,dkChar * buf,size_t bs,int ch)6408 dk3app_get_dir_from_pref(
6409   dk3_app_t	*app,
6410   dkChar const	*pn,
6411   dkChar	*buf,
6412   size_t	 bs,
6413   int		 ch
6414 )
6415 {
6416   int			 back = 0;
6417   if((app) && (pn) && (buf) && (bs)) {
6418     if(dk3app_get_pref(app, pn, buf, bs)) {
6419       if(ch) {
6420         if(dk3sf_is_dir_app(buf, NULL)) {
6421           back = 1;
6422         } else {
6423           /* ERROR: Directory does not exist! */
6424 	  dk3app_log_i3(app, DK3_LL_ERROR, 369, 370, pn);
6425         }
6426       } else {
6427         back = 1;
6428       }
6429     }
6430   }
6431   return back;
6432 }
6433 
6434 
6435 
6436 /* vim: set ai sw=2 : */
6437 
6438