1 /*
2 Copyright (C) 2017-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: dk-lines.ctr
12 */
13 
14 
15 /**	@file	dk-lines.c	The dk-lines program.
16 	The dk_lines_help_text array below shows details.
17 
18 */
19 
20 #ifndef	DK4CONF_H_INCLUDED
21 #include "dk4conf.h"
22 #endif
23 
24 #include <stdio.h>
25 
26 #if	DK4_HAVE_STDLIB_H
27 #ifndef	STDLIB_H_INCLUDED
28 #include <stdlib.h>
29 #define	STDLIB_H_INCLUDED 1
30 #endif
31 #endif
32 
33 #if DK4_HAVE_UNISTD_H
34 #ifndef UNISTD_H_INCLUDED
35 #include <unistd.h>
36 #define	UNISTD_H_INCLUDED 1
37 #endif
38 #endif
39 
40 #if DK4_HAVE_PROCESS_H
41 #ifndef PROCESS_H_INCLUDED
42 #include <process.h>
43 #define	PROCESS_H_INCLUDED 1
44 #endif
45 #endif
46 
47 #if DK4_HAVE_IO_H
48 #ifndef IO_H_INCLUDED
49 #include <io.h>
50 #define IO_H_INCLUDED 1
51 #endif
52 #endif
53 
54 #if DK4_HAVE_FCNTL_H
55 #ifndef FCNTL_H_INCLUDED
56 #include <fcntl.h>
57 #define FCNTL_H_INCLUDED 1
58 #endif
59 #endif
60 
61 #if DK4_HAVE_SYS_TYPES_H
62 #ifndef SYS_TYPES_H_INCLUDED
63 #include <sys/types.h>
64 #define SYS_TYPES_H_INCLUDED 1
65 #endif
66 #endif
67 
68 #if DK4_HAVE_SIGNAL_H
69 #ifndef SIGNAL_H_INCLUDED
70 #include <signal.h>
71 #define SIGNAL_H_INCLUDED 1
72 #endif
73 #endif
74 
75 #ifndef	DK4UNUSED_H_INCLUDED
76 #include <libdk4base/dk4unused.h>
77 #endif
78 
79 #ifndef	DK4TYPES_H_INCLUDED
80 #include <libdk4base/dk4types.h>
81 #endif
82 
83 #ifndef	DK4MEM_H_INCLUDED
84 #include <libdk4base/dk4mem.h>
85 #endif
86 
87 #ifndef	DK4ENC_H_INCLUDED
88 #include <libdk4c/dk4enc.h>
89 #endif
90 
91 #ifndef	DK4STRD_H_INCLUDED
92 #include <libdk4base/dk4strd.h>
93 #endif
94 
95 #ifndef	DK4STRDA_H_INCLUDED
96 #include <libdk4app/dk4strda.h>
97 #endif
98 
99 #ifndef	DK4DIR_H_INCLUDED
100 #include <libdk4c/dk4dir.h>
101 #endif
102 
103 #ifndef	DK4PATHD_H_INCLUDED
104 #include <libdk4c/dk4pathd.h>
105 #endif
106 
107 #ifndef	DK4APP_H_INCLUDED
108 #include <libdk4app/dk4app.h>
109 #endif
110 
111 #ifndef	DK4AOPT_H_INCLUDED
112 #include <libdk4app/dk4aopt.h>
113 #endif
114 
115 #ifndef	DK4MEMA_H_INCLUDED
116 #include <libdk4app/dk4mema.h>
117 #endif
118 
119 #ifndef	DK4VERS_H_INCLUDED
120 #include <libdk4base/dk4vers.h>
121 #endif
122 
123 #ifndef	DK4MAADU_H_INCLUDED
124 #include <libdk4ma/dk4maadu.h>
125 #endif
126 
127 #ifndef	DK4MAIDDDU_H_INCLUDED
128 #include <libdk4maiodd/dk4maidddu.h>
129 #endif
130 
131 #ifndef	DK4MAODD_H_INCLUDED
132 #include <libdk4maiodd/dk4maodd.h>
133 #endif
134 
135 #ifndef	DK4FPUT_H_INCLUDED
136 #include <libdk4c/dk4fput.h>
137 #endif
138 
139 #ifndef	DK4TSPDK_H_INCLUDED
140 #include <libdk4c/dk4tspdk.h>
141 #endif
142 
143 #ifndef	DK4FOPD_H_INCLUDED
144 #include <libdk4c/dk4fopd.h>
145 #endif
146 
147 #ifndef	DK4FOPDA_H_INCLUDED
148 #include <libdk4app/dk4fopda.h>
149 #endif
150 
151 #ifndef	DK4ISADM_H_INCLUDED
152 #include <libdk4c/dk4isadm.h>
153 #endif
154 
155 #ifndef	DK4TIME_H_INCLUDED
156 #include <libdk4c/dk4time.h>
157 #endif
158 
159 #ifndef	DK4TIMEDK_H_INCLUDED
160 #include <libdk4c/dk4timedk.h>
161 #endif
162 
163 #ifndef	DK4MPL_H_INCLUDED
164 #include <libdk4base/dk4mpl.h>
165 #endif
166 
167 #ifndef	DK4WMAIN_H_INCLUDED
168 #include <libdk4base/dk4wmain.h>
169 #endif
170 
171 
172 
173 
174 
175 
176 #ifndef	DK_LINES_BUFFER_SIZE
177 /**	Text buffer size.
178 */
179 #define	DK_LINES_BUFFER_SIZE	4096
180 #endif
181 
182 
183 
184 /**	Ring buffer element.
185 */
186 typedef struct {
187 	dkChar		*str;		/**< Line text. */
188 	dk4_um_t	 lineno;	/**< Line number. */
189 	size_t		 buflen;	/**< Length of str buffer (number of dkChar). */
190 } rbe_t;
191 
192 
193 
194 /**	Range specification types.
195 */
196 enum {
197 	RANGE_NONE_NONE		= 0 ,		/**< No ranges specified. */
198 	RANGE_NONE_POS ,				/**< No start, positive end. */
199 	RANGE_NONE_NEG ,				/**< No start, negative end. */
200 	RANGE_POS_NONE ,				/**< Positive start, no end. */
201 	RANGE_POS_POS ,					/**< Positive start, positive end. */
202 	RANGE_POS_NEG ,					/**< Positive start, negative end. */
203 	RANGE_NEG_NONE ,				/**< Negative start, no end. */
204 	RANGE_NEG_POS ,					/**< Negative start, positive end. */
205 	RANGE_NEG_NEG ,					/**< Negative start, negative end. */
206 };
207 
208 
209 
210 /**	Input line buffer.
211 */
212 static dkChar	default_input_line_buffer[DK_LINES_BUFFER_SIZE];
213 
214 
215 
216 /**	Buffer to store current date and time.
217 */
218 static dkChar	date_buffer[64];
219 
220 
221 
222 /**	Default text, used if help text file is not found.
223 */
224 static const dkChar * const	dk_lines_help_text[] = {
225 dkT(""),
226 dkT("Select lines from text"),
227 dkT(""),
228 dkT("dk-lines [<options>] [<files>]"),
229 dkT(""),
230 dkT("Options:"),
231 dkT("-i encoding Expected input encoding, one from: plain, ascii, ansi, utf-8,"),
232 dkT("            utf-16, utf-16le, utf-16be, c32, c32le, c32be."),
233 dkT("-f string   Show lines lexicographically equal or larger than string."),
234 dkT("-t string   Show lines lexicographically equal or smaller than string."),
235 dkT("-l spec     Specification of line numbers in format <start>/<end> (inclusive)"),
236 dkT("            to pass through, applied after -f and -t processing. Examples:"),
237 dkT("            5 (5 and following), 5/8 (5, 6, 7, 8), /8 (1...8), 5/-3 (5 and"),
238 dkT("            following except final 2 lines), -5 (final 5 lines), -5/-3 (3 lines"),
239 dkT("            before the final 2 lines), /-3 (all lines except the final 2),"),
240 dkT("            5/-3 (5 and following except final 2 lines),"),
241 dkT("            -5/8 (final 5 lines but not above line 8)."),
242 dkT("-v          Verbose mode: Error message on SIGPIPE."),
243 dkT("--help      Show this short help text.  --manual   *** SHOW FULL MANUAL. ***"),
244 dkT("--version   Show version information.   --license   Show license information."),
245 dkT(""),
246 dkT("http://sourceforge.net/p/dktools/wiki/dk-lines/"),
247 dkT(""),
248 NULL
249 
250 };
251 
252 
253 
254 /**	License conditions.
255 */
256 static const dkChar * const	dk_lines_license_text[] = {
257 dkT(""),
258 dkT("This software uses code from the following projects, either directly or as"),
259 dkT("a library:"),
260 dkT(""),
261 dkT("dktools\t\tDirk Krause's tools and libraries."),
262 dkT("\t\tSee http://sourceforge.net/p/dktools/wiki/Home/"),
263 dkT("\t\tfor more information."),
264 #if DK4_HAVE_ZLIB_H
265 dkT(""),
266 dkT("zlib\t\tData compression library."),
267 dkT("\t\tSee http://www.zlib.net/ for more information."),
268 #endif
269 #if DK4_HAVE_BZLIB_H
270 dkT(""),
271 dkT("bzip2\t\tData compression program and library."),
272 dkT("\t\tSee http://www.bzip.org/ for more information."),
273 #endif
274 dkT(""),
275 dkT("All the licenses below apply to the program."),
276 dkT("Licenses for used libraries are shown as found on my Scientific Linux 6.x"),
277 dkT("computer in the /usr/share/doc directory on 2015-04-01. Check the project"),
278 dkT("homepages of the used libraries for additional information and/or updated"),
279 dkT("license terms."),
280 dkT(""),
281 dkT(""),
282 dkT("DK tools and libraries license"),
283 dkT("=============================="),
284 dkT("Copyright (c) 2015-2016, Dirk Krause"),
285 dkT("All rights reserved."),
286 dkT(""),
287 dkT("Redistribution and use in source and binary forms, with or without"),
288 dkT("modification, are permitted provided that the following conditions are met:"),
289 dkT(""),
290 dkT("1. Redistributions of source code must retain the above copyright notice,"),
291 dkT("   this list of conditions and the following disclaimer."),
292 dkT("2. Redistributions in binary form must reproduce the above copyright"),
293 dkT("   notice, this list of conditions and the following disclaimer in the"),
294 dkT("   documentation and/or other materials provided with the distribution."),
295 dkT("3. Neither the name of the copyright holder nor the names of its"),
296 dkT("   contributors may be used to endorse or promote products derived from"),
297 dkT("   this software without specific prior written permission."),
298 dkT(""),
299 dkT("THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"),
300 dkT("``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT"),
301 dkT("LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR"),
302 dkT("A PARTICULAR PURPOSE ARE DISCLAIMED."),
303 dkT("IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY"),
304 dkT("DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES"),
305 dkT("(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR"),
306 dkT("SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER"),
307 dkT("CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT"),
308 dkT("LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY"),
309 dkT("OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF"),
310 dkT("SUCH DAMAGE."),
311 #if DK4_HAVE_ZLIB_H
312 dkT(""),
313 dkT(""),
314 dkT("Zlib license"),
315 dkT("============"),
316 dkT("(C) 1995-2004 Jean-loup Gailly and Mark Adler"),
317 dkT(""),
318 dkT("This software is provided 'as-is', without any express or implied"),
319 dkT("warranty.  In no event will the authors be held liable for any damages"),
320 dkT("arising from the use of this software."),
321 dkT(""),
322 dkT("Permission is granted to anyone to use this software for any purpose,"),
323 dkT("including commercial applications, and to alter it and redistribute it"),
324 dkT("freely, subject to the following restrictions:"),
325 dkT(""),
326 dkT("1. The origin of this software must not be misrepresented; you must not"),
327 dkT("   claim that you wrote the original software. If you use this software"),
328 dkT("   in a product, an acknowledgment in the product documentation would be"),
329 dkT("   appreciated but is not required."),
330 dkT("2. Altered source versions must be plainly marked as such, and must not be"),
331 dkT("   misrepresented as being the original software."),
332 dkT("3. This notice may not be removed or altered from any source distribution."),
333 dkT(""),
334 dkT("Jean-loup Gailly        Mark Adler"),
335 dkT("jloup@gzip.org          madler@alumni.caltech.edu"),
336 #endif
337 #if DK4_HAVE_BZLIB_H
338 dkT(""),
339 dkT(""),
340 dkT("Bzip2 and libbzip2 library license"),
341 dkT("=================================="),
342 dkT("This program, \"bzip2\", the associated library \"libbzip2\", and all"),
343 dkT("documentation, are copyright (C) 1996-2007 Julian R Seward.  All"),
344 dkT("rights reserved."),
345 dkT(""),
346 dkT("Redistribution and use in source and binary forms, with or without"),
347 dkT("modification, are permitted provided that the following conditions"),
348 dkT("are met:"),
349 dkT(""),
350 dkT("1. Redistributions of source code must retain the above copyright"),
351 dkT("   notice, this list of conditions and the following disclaimer."),
352 dkT(""),
353 dkT("2. The origin of this software must not be misrepresented; you must "),
354 dkT("   not claim that you wrote the original software.  If you use this "),
355 dkT("   software in a product, an acknowledgment in the product "),
356 dkT("   documentation would be appreciated but is not required."),
357 dkT(""),
358 dkT("3. Altered source versions must be plainly marked as such, and must"),
359 dkT("   not be misrepresented as being the original software."),
360 dkT(""),
361 dkT("4. The name of the author may not be used to endorse or promote "),
362 dkT("   products derived from this software without specific prior written "),
363 dkT("   permission."),
364 dkT(""),
365 dkT("THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS"),
366 dkT("OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED"),
367 dkT("WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE"),
368 dkT("ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY"),
369 dkT("DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL"),
370 dkT("DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE"),
371 dkT("GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS"),
372 dkT("INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,"),
373 dkT("WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING"),
374 dkT("NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS"),
375 dkT("SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."),
376 dkT(""),
377 dkT("Julian Seward, jseward@bzip.org"),
378 dkT("bzip2/libbzip2 version 1.0.5 of 10 December 2007"),
379 #endif
380 dkT(""),
381 NULL
382 
383 };
384 
385 
386 
387 /**	Constant texts used by program, not localized.
388 */
389 static const dkChar * const	dk_lines_kwnl[] = {
390 /* 0 */
391 dkT("dktools"),
392 
393 /* 1 */
394 dkT("dk-lines.txt"),
395 
396 /* 2 */
397 dkT("dk-lines.str"),
398 
399 /* 3 */
400 dkT("line-size"),
401 
402 /* 4 */
403 dkT("today"),
404 
405 /* 5 */
406 dkT("/"),
407 
408 /* 6 */
409 dkT("rb"),
410 
411 /* 7 */
412 dkT("<stdin>"),
413 
414 NULL
415 
416 };
417 
418 
419 
420 /**	Constant texts used by program, replaced by localized texts
421 	if available.
422 */
423 static const dkChar * const     dk_lines_kw_def[] = {
424 /* 0 */
425 dkT("Failed to set up masked signal set for SIGPIPE!"),
426 
427 /* 1 */
428 dkT("Failed to set up masked signal set for SIGINT!"),
429 
430 /* 2 */
431 dkT("Failed to set up masked signal set for SIGTERM!"),
432 
433 /* 3 */
434 dkT("Failed to restore SIGTERM settings!"),
435 
436 /* 4 */
437 dkT("Failed to restore SIGTERM settings!"),
438 
439 /* 5 */
440 dkT("Failed to restore SIGPIPE settings!"),
441 
442 /* 6 */
443 dkT("Illegal line number 0!"),
444 
445 /* 7 */
446 dkT("Number too large: \""),
447 
448 /* 8 */
449 dkT("\"!"),
450 
451 /* 9 */
452 dkT("Not a number: \""),
453 
454 /* 10 */
455 dkT("\"!"),
456 
457 /* 11 */
458 dkT("Start line number larger than end number!"),
459 
460 /* 12 */
461 dkT("Invalid line range specification (empty string)!"),
462 
463 /* 13 */
464 dkT("Missing line range specification!"),
465 
466 /* 14 */
467 dkT("Illegal input encoding: \""),
468 
469 /* 15 */
470 dkT("\"!"),
471 
472 /* 16 */
473 dkT("Missing input encoding!"),
474 
475 /* 17 */
476 dkT("Invalid line size 0!"),
477 
478 /* 18 */
479 dkT("Missing line size specification!"),
480 
481 /* 19 */
482 dkT("Can not use --today with both --from and --to!"),
483 
484 /* 20 */
485 dkT("Input line too long!"),
486 
487 /* 21 */
488 dkT("Too many lines, overflow in line number!"),
489 
490 /* 22 */
491 dkT("Overflow in line range calculation!"),
492 
493 /* 23 */
494 dkT("End line number is 1 (should not happen, bug)!"),
495 
496 /* 24 */
497 dkT("End line number too large, numeric overflow!"),
498 
499 /* 25 */
500 dkT("Start line number too large, numeric overflow!"),
501 
502 /* 26 */
503 dkT("Ring buffer size is 0 (should not happen, bug)!"),
504 
505 /* 27 */
506 dkT("Failed to obtain file name (should not happen, bug)!"),
507 
508 /* 28 */
509 dkT("Program stopped by SIGPIPE!"),
510 
511 /* 29 */
512 dkT("I/O errors while writing output!"),
513 
514 /* 30 */
515 dkT("Program stopped by interrupt!"),
516 
517 /* 31 */
518 dkT("Encoding error!"),
519 
520 /* 32 */
521 dkT("Decoding error!"),
522 
523 /* 33 */
524 dkT("Processing error!"),
525 
526 /* 34 */
527 dkT("Encoding error!\n\tByte: "),
528 
529 /* 35 */
530 dkT("Decoding error!\n\tByte: "),
531 
532 /* 36 */
533 dkT("Processing error!\n\tByte: "),
534 
535 /* 37 */
536 dkT(",\n\tCharacter: "),
537 
538 /* 38 */
539 dkT(",\n\tPosition in line: "),
540 
541 /* 39 */
542 dkT("."),
543 
544 NULL
545 
546 };
547 
548 
549 
550 /**	Options used by program.
551 */
552 static const dk4_option_specification_t dk_lines_options[] = {
553 
554 	/*	Input encoding.
555 	*/
556 	{ dkT('i'),		dkT("input-encoding"),	DK4_OPT_ARG_STRING },
557 
558 	/*	Only lines matching start text or lexicagraphically after text.
559 	*/
560 	{ dkT('f'),		dkT("from"),			DK4_OPT_ARG_STRING },
561 
562 	/*	Only lines matching end text or lexicographically before text.
563 	*/
564 	{ dkT('t'),		dkT("to"),				DK4_OPT_ARG_STRING },
565 
566 	/*	Line number selection _after_ applying from and to rules.
567 		First line is line 1, final line is line -1.
568 		dk-lines -l 5/8					Lines 5, 6, 7 and 8
569 		dk-lines -l 5					Lines 5, ...
570 		dk-lines -l /8					Lines 1, ... 8
571 		dk-lines -l -8/-5				8 before last ... 5 before last
572 		dk-lines -l -8					Final 8 lines
573 		dk-lines -l /-5					Skip final 5 lines
574 		dk-lines -l -8/125				Final 8 lines but not above line 125
575 		dk-lines -l 125/-8				Lines from 125 but skip final 8 lines
576 		dk-lines without -l option		All lines
577 	*/
578 	{ dkT('l'),		dkT("lines"),			DK4_OPT_ARG_STRING },
579 
580 	/*	Verbose flag (write notification on SIGPIPE).
581 	*/
582 	{ dkT('v'),		dkT("verbose"),			DK4_OPT_ARG_NONE },
583 
584 	/*	Treat multiple files as one stream.
585 	*/
586 	{ dkT('o'),		dkT("one-stream"),		DK4_OPT_ARG_NONE },
587 
588 	/*	Line buffer size.
589 	*/
590 	{ dkT('\0'),	dkT("line-size"),		DK4_OPT_ARG_SIZE },
591 
592 	/**	Use current date to filter lines.
593 	*/
594 	{ dkT('\0'),	dkT("today"),			DK4_OPT_ARG_NONE }
595 };
596 
597 
598 #if	DK4_ON_WINDOWS
599 
600 /**	File name separator.
601 */
602 static const dkChar	fnsep[] = {
603 #if DK4_HAVE_BACKSLASH_AS_SEP
604 dkT("\\")
605 #else
606 dkT("/")
607 #endif
608 };
609 
610 #endif
611 
612 
613 
614 /**	Ring buffer used for negative line numbers.
615 */
616 static rbe_t			*pribu	= NULL;
617 
618 
619 
620 /**	Application structure.
621 */
622 static dk4_app_t		*app	= NULL;
623 
624 
625 /**	Pointer to localized messages array.
626 */
627 static const dkChar * const		*msgs	=	dk_lines_kw_def;
628 
629 
630 
631 /**	Start range.
632 */
633 static const dkChar		*t_from	=	NULL;
634 
635 
636 
637 /**	End of range.
638 */
639 static const dkChar		*t_to	=	NULL;
640 
641 
642 /**	Input line buffer to use.
643 */
644 static dkChar	*ilb	=	default_input_line_buffer;
645 
646 
647 
648 /**	Start line number.
649 */
650 static dk4_um_t	l_start	=	(dk4_um_t)0UL;
651 
652 
653 
654 /**	End line number.
655 */
656 static dk4_um_t	l_end	=	(dk4_um_t)0UL;
657 
658 
659 
660 /**	Current line number.
661 */
662 static dk4_um_t	lineno	=	(dk4_um_t)0UL;
663 
664 
665 
666 /**	Length of --from text.
667 */
668 static size_t	sz_t_from	=	0;
669 
670 
671 
672 /**	Length of --to text.
673 */
674 static size_t	sz_t_to		=	0;
675 
676 
677 
678 /**	Ring buffer size (number of elements).
679 */
680 static size_t	sz_ribu		=	0;
681 
682 
683 
684 /**	Current position in ring buffer.
685 */
686 static size_t	pos_ribu	=	0;
687 
688 
689 
690 /**	Size of input line buffer.
691 */
692 static size_t	sz_ilb	=	DK4_SIZEOF(default_input_line_buffer,dkChar);
693 
694 
695 
696 /**	Number of usable elements in the dk_lines_kw_def array and in msg.
697 */
698 static size_t	sz_msg	=	(sizeof(dk_lines_kw_def)/sizeof(DK4_PDKCHAR) - 1);
699 
700 
701 
702 /**	Number of elements in the dk_lines_options array.
703 */
704 static const size_t dk_lines_sz_options =
705 sizeof(dk_lines_options)/sizeof(dk4_option_specification_t);
706 
707 
708 
709 /**	Line handling type.
710 */
711 static	int		l_type	=	RANGE_NONE_NONE;
712 
713 
714 
715 /**	Exit status code.
716 */
717 static	int		exval	=	EXIT_FAILURE;
718 
719 
720 
721 /**	Flag: Write errors.
722 */
723 static	int		had_write_error	= 0;
724 
725 
726 
727 /**	Expected input encoding when reading from file.
728 */
729 static	int		eie_file		=
730 #if DK4_ON_WINDOWS
731 	DK4_FILE_ENCODING_WIN1252
732 #else
733 	DK4_FILE_ENCODING_PLAIN
734 #endif
735 ;
736 
737 
738 
739 /**	Expected input encoding on standard input.
740 */
741 static	int		eie_stdin		=
742 #if DK4_ON_WINDOWS
743 	DK4_FILE_ENCODING_WIN1252
744 #else
745 	DK4_FILE_ENCODING_PLAIN
746 #endif
747 ;
748 
749 
750 
751 /**	Verbose flag (report SIGPIPE or unusual large line buffer size).
752 */
753 static	int		verbose	=	0;
754 
755 
756 
757 /**	Flag: At least one cyle in the ring buffer was completed.
758 */
759 static	int		cycle_completed	=	0;
760 
761 
762 
763 /**	Flag: Treat multiple files as one stream.
764 */
765 static	int		one_stream	=	0;
766 
767 
768 
769 /**	Number of decoding errors already reported.
770 */
771 static int num_r_decoding_e		= 0;
772 
773 
774 
775 /**	Maximum number of decoding errors to report unless verbose output required.
776 */
777 static const int max_r_decoding_e	= 3;
778 
779 
780 
781 /**	Number of encoding errors already reported.
782 */
783 static int num_r_encoding_e		= 0;
784 
785 
786 
787 /**	Maximum number of encoding errors to report unless verbose output required.
788 */
789 static const int max_r_encoding_e	= 3;
790 
791 
792 
793 /**	Number of processing errors already reported.
794 */
795 static int num_r_processing_e		= 0;
796 
797 
798 
799 /**	Maximum number of processing errors to report unless
800 	verbose output required.
801 */
802 static const int max_r_processing_e	= 3;
803 
804 
805 
806 #ifdef SIGPIPE
807 /**	Indicator: SIGPIPE signal received.
808 */
809 static
810 DK4_VOLATILE
811 dk4_sig_atomic_t	sig_had_pipe	=	0;
812 #endif
813 
814 /**	Indicator: SIGINT signal received.
815 */
816 static
817 DK4_VOLATILE
818 dk4_sig_atomic_t	sig_had_int	=	0;
819 
820 /**	Indicator: SIGTERM signal received.
821 */
822 static
823 DK4_VOLATILE
824 dk4_sig_atomic_t	sig_had_term	=	0;
825 
826 
827 
828 /**	Special function to pass a volatile pointer.
829 	Some C compiler does not handle direct assignments to volatile variables
830 	correctly.
831 	@param	ptr	Address of volatile variable.
832 	@return	Same address.
833 */
834 static
835 DK4_VOLATILE
836 dk4_sig_atomic_t *
sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t * ptr)837 sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr)
838 {
839 	return ptr;
840 }
841 
842 
843 #ifdef SIGPIPE
844 /**	Handler for SIGPIPE signal.
845 	@param	signo	Signal number (always SIGPIPE, ignored).
846 */
847 static
848 void
sig_handler_pipe(int DK4_ARG_UNUSED (signo))849 sig_handler_pipe(int DK4_ARG_UNUSED(signo) )
850 {
851 	DK4_UNUSED_ARG(signo)
852 	*sig_pass_pointer(&sig_had_pipe) = 1;
853 }
854 #endif
855 
856 
857 /**	Handler for SIGINT signal.
858 	@param	signo	Signal number (always SIGINT, ignored).
859 */
860 static
861 void
sig_handler_int(int DK4_ARG_UNUSED (signo))862 sig_handler_int(int DK4_ARG_UNUSED(signo) )
863 {
864 	DK4_UNUSED_ARG(signo)
865 	*sig_pass_pointer(&sig_had_int) = 1;
866 }
867 
868 
869 /**	Handler for SIGTERM signal.
870 	@param	signo	Signal number (always SIGTERM, ignored).
871 */
872 static
873 void
sig_handler_term(int DK4_ARG_UNUSED (signo))874 sig_handler_term(int DK4_ARG_UNUSED(signo) )
875 {
876 	DK4_UNUSED_ARG(signo)
877 	*sig_pass_pointer(&sig_had_term) = 1;
878 }
879 
880 
881 /**	Read value from volatile atomic type.
882 	This function is necessary as some compilers mis-optimize
883 	direct access to volatile variables (at least if you believe
884 	one of the coding standards).
885 	@param	ap	Pointer to volatile atomic variable.
886 	@return	Contents of the variable.
887 */
888 static
889 dk4_sig_atomic_t
sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t * ap)890 sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap)
891 {
892 	return (*ap);
893 }
894 
895 
896 
897 /**	Check whether we can continue or if a signal was received.
898 	@param	check_pipe	Flag: Check for occured SIGPIPE signal too.
899 	@return	1 if the program can continue, 0 if a signal was received.
900 */
901 static
902 int
sig_can_continue(int check_pipe)903 sig_can_continue(
904 #ifdef	SIGPIPE
905 int check_pipe
906 #else
907 int DK4_ARG_UNUSED(check_pipe)
908 #endif
909 )
910 {
911 	int		back = 1;
912 #ifndef SIGPIPE
913 	DK4_UNUSED_ARG(check_pipe)
914 #else
915 	if (0 != check_pipe) {
916 		if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; }
917 	}
918 #endif
919 	if (0 != sig_read_atomic(&sig_had_int )) { back = 0; }
920 	if (0 != sig_read_atomic(&sig_had_term)) { back = 0; }
921 	return back;
922 }
923 
924 
925 
926 /**	Retrieve value from text.
927 	@param	pdest	Address of result variable to fill.
928 	@param	vtxt	Text containing the value.
929 	@param	pback	Address of success variable to reset on error.
930 */
931 static
932 void
retrieve_number(dk4_um_t * pdest,const dkChar * vtxt,int * pback)933 retrieve_number(dk4_um_t *pdest, const dkChar *vtxt, int *pback)
934 {
935 	dk4_er_t		 er;
936 	dk4_um_t		 u	= (dk4_um_t)0UL;
937 	const dkChar	*pe	= NULL;
938 
939 	dk4error_init(&er);
940 	if (0 != dk4ma_input_dk_dec_dk4_um_t(&u, vtxt, &pe, 1, &er)) {
941 		if ((dk4_um_t)0UL < u) {
942 			*pdest = u;
943 		}
944 		else {
945 			*pback = 0;
946 			/* ERROR: Illegal line number 0 */
947 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 6);
948 		}
949 	}
950 	else {
951 		*pback = 0;
952 		switch (er.ec) {
953 			case DK4_E_MATH_OVERFLOW : {
954 				/* ERROR: Number too large */
955 				dk4app_log_3(app, msgs, sz_msg, DK4_LL_ERROR, 7, 8, vtxt);
956 			} break;
957 			default : {
958 				/* ERROR: Not a number */
959 				dk4app_log_3(app, msgs, sz_msg, DK4_LL_ERROR, 9, 10, vtxt);
960 			} break;
961 		}
962 	}
963 
964 }
965 
966 
967 
968 #if TRACE_DEBUG
969 
970 static
971 void
trace_type_start_end(int t,unsigned long s,unsigned long e)972 trace_type_start_end(int t, unsigned long s, unsigned long e)
973 {
974 
975 }
976 
977 #endif
978 
979 
980 
981 /**	Process line number range.
982 	@param	ps	Text containing start line number.
983 	@param	pe	Text containing end line number.
984 	@return	1 on success, 0 on error.
985 */
986 static
987 int
process_line_range_items(const dkChar * ps,const dkChar * pe)988 process_line_range_items(const dkChar *ps, const dkChar *pe)
989 {
990 	int			 back	= 1;
991 
992 
993 	/*	Retrieve pure data from texts
994 	*/
995 	if (NULL != ps) {
996 		if (NULL != pe) {
997 			if (dkT('-') != *ps) {
998 				if (dkT('-') != *pe) {
999 					l_type = RANGE_POS_POS;
1000 					retrieve_number(&l_start, ps, &back);
1001 					retrieve_number(&l_end, pe, &back);
1002 					if (l_start > l_end) {
1003 						back = 0;
1004 						/* ERROR: start line number larger than end */
1005 						dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 11);
1006 					}
1007 				}
1008 				else {
1009 					pe++;
1010 					l_type = RANGE_POS_NEG;
1011 					retrieve_number(&l_start, ps, &back);
1012 					retrieve_number(&l_end, pe, &back);
1013 				}
1014 			}
1015 			else {
1016 				ps++;
1017 				if (dkT('-') != *pe) {
1018 					l_type = RANGE_NEG_POS;
1019 					retrieve_number(&l_start, ps, &back);
1020 					retrieve_number(&l_end, pe, &back);
1021 				}
1022 				else {
1023 					pe++;
1024 					l_type = RANGE_NEG_NEG;
1025 					retrieve_number(&l_start, ps, &back);
1026 					retrieve_number(&l_end, pe, &back);
1027 					if (l_end > l_start) {
1028 						back = 0;
1029 						/* ERROR: End line number larger than start */
1030 						dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 11);
1031 					}
1032 				}
1033 			}
1034 		}
1035 		else {
1036 			if (dkT('-') != *ps) {
1037 				l_type = RANGE_POS_NONE;
1038 				retrieve_number(&l_start, ps, &back);
1039 			}
1040 			else {
1041 				ps++;
1042 				l_type = RANGE_NEG_NONE;
1043 				retrieve_number(&l_start, ps, &back);
1044 			}
1045 		}
1046 	}
1047 	else {
1048 		if (NULL != pe) {
1049 			if (dkT('-') != *pe) {
1050 				l_type = RANGE_NONE_POS;
1051 				retrieve_number(&l_end, pe, &back);
1052 			}
1053 			else {
1054 				pe++;
1055 				l_type = RANGE_NONE_NEG;
1056 				retrieve_number(&l_end, pe, &back);
1057 			}
1058 		}
1059 		else {
1060 		}
1061 	}
1062 
1063 	/*	Corrections for full ranges
1064 	*/
1065 	if (0 != back) {
1066 
1067 
1068 		switch (l_type) {
1069 			case RANGE_NONE_NEG : {
1070 				if ((dk4_um_t)1UL == l_end) {
1071 					l_type = RANGE_NONE_NONE;
1072 					l_end  = (dk4_um_t)0UL;
1073 
1074 				}
1075 			} break;
1076 			case RANGE_POS_NEG : {
1077 				if ((dk4_um_t)1UL == l_end) {
1078 					l_type = RANGE_POS_NONE;
1079 					l_end  = (dk4_um_t)0UL;
1080 
1081 					if ((dk4_um_t)1UL == l_start) {
1082 						l_type  = RANGE_NONE_NONE;
1083 						l_start = (dk4_um_t)0UL;
1084 
1085 					}
1086 				}
1087 				else {
1088 					if ((dk4_um_t)1UL == l_start) {
1089 						l_type  = RANGE_NONE_NEG;
1090 						l_start = (dk4_um_t)0UL;
1091 
1092 					}
1093 				}
1094 			} break;
1095 			case RANGE_NEG_NEG : {
1096 				if ((dk4_um_t)1UL == l_end) {
1097 					l_type = RANGE_NEG_NONE;
1098 					l_end  = (dk4_um_t)0UL;
1099 
1100 				}
1101 			} break;
1102 			case RANGE_POS_NONE : {
1103 				if ((dk4_um_t)1UL == l_start) {
1104 					l_start = (dk4_um_t)0UL;
1105 					l_type  = RANGE_NONE_NONE;
1106 
1107 				}
1108 			} break;
1109 			case RANGE_POS_POS : {
1110 				if ((dk4_um_t)1UL == l_start) {
1111 					l_start = (dk4_um_t)0UL;
1112 					l_type  = RANGE_NONE_POS;
1113 
1114 				}
1115 			} break;
1116 			default : {
1117 				/* Empty by intent */
1118 
1119 			} break;
1120 		}
1121 	}
1122 
1123 	return back;
1124 }
1125 
1126 
1127 
1128 /**	Process line number range.
1129 	@param	range	Text containing the line number range.
1130 */
1131 static
1132 int
process_line_range(const dkChar * range)1133 process_line_range(const dkChar *range)
1134 {
1135 	dkChar		 buf[64*sizeof(dk4_um_t)];
1136 	dkChar		*p1		= NULL;
1137 	dkChar		*p2		= NULL;
1138 	int			 back	= 0;
1139 
1140 	back = dk4str_cpy_s(buf, DK4_SIZEOF(buf,dkChar), range, NULL);
1141 	if (0 != back) {
1142 		p1 = dk4str_start(buf, NULL);
1143 		if (NULL != p1) {
1144 			p2 = dk4str_chr(p1, dkT('/'));
1145 			if (NULL != p2) {
1146 				*(p2++) = dkT('\0');
1147 				p2 = dk4str_start(p2, NULL);
1148 				p1 = dk4str_start(p1, NULL);
1149 			}
1150 			back = process_line_range_items(p1, p2);
1151 		}
1152 		else {
1153 			/* ERROR: Empty string */
1154 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 12);
1155 			back = 0;
1156 		}
1157 	}
1158 
1159 	return back;
1160 }
1161 
1162 
1163 
1164 /**	Retrieve configuration from command line arguments.
1165 	@return	1 on success, 0 on error.
1166 */
1167 static
1168 int
process_command_line_arguments(void)1169 process_command_line_arguments(void)
1170 {
1171 	dk4_time_t		 timer	= (dk4_time_t)0UL;
1172 	const dkChar	*ptr	= NULL;
1173 	size_t			 sz		= 0;
1174 	int				 back	= 1;
1175 	int				 res	= 0;
1176 	int				 iec	= 0;
1177 
1178 
1179 	/*	--verbose
1180 	*/
1181 	if (0 != dk4app_opt_is_set_short(app, dkT('v'), NULL)) {
1182 		verbose = 1;
1183 	}
1184 
1185 	/*	--one-stream
1186 	*/
1187 	if (0 != dk4app_opt_is_set_short(app, dkT('o'), NULL)) {
1188 		one_stream = 1;
1189 	}
1190 
1191 	/*	--from
1192 	*/
1193 	if (0 != dk4app_opt_is_set_short(app, dkT('f'), NULL)) {
1194 		t_from	= dk4app_opt_get_string_ptr_short(app, dkT('f'), NULL);
1195 		sz_t_from = dk4str_len(t_from);
1196 	}
1197 
1198 	/*	--to
1199 	*/
1200 	if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) {
1201 		t_to	= dk4app_opt_get_string_ptr_short(app, dkT('t'), NULL);
1202 		sz_t_to = dk4str_len(t_to);
1203 	}
1204 
1205 	/*	--lines
1206 	*/
1207 	if (0 != dk4app_opt_is_set_short(app, dkT('l'), NULL)) {
1208 		ptr		= dk4app_opt_get_string_ptr_short(app, dkT('l'), NULL);
1209 		if (NULL != ptr) {
1210 			back = process_line_range(ptr);
1211 		}
1212 		else {
1213 			/* ERROR: Failed to retrieve line range argument */
1214 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 13);
1215 			back = 0;
1216 		}
1217 	}
1218 
1219 	/*	--input-encoding
1220 	*/
1221 	if (0 != dk4app_opt_is_set_short(app, dkT('i'), NULL)) {
1222 		ptr		= dk4app_opt_get_string_ptr_short(app, dkT('i'), NULL);
1223 		if (NULL != ptr) {
1224 			res = dk4enc_find(&iec, NULL, ptr, NULL);
1225 			if (0 != res) {
1226 				eie_stdin = iec;
1227 				eie_file  = iec;
1228 			}
1229 			else {
1230 				/* ERROR: Illegal input encoding */
1231 				dk4app_log_3(app, msgs, sz_msg, DK4_LL_ERROR, 14, 15, ptr);
1232 			}
1233 		}
1234 		else {
1235 			back = 0;
1236 			/* ERROR: Failed to retrieve input encoding */
1237 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 16);
1238 		}
1239 	}
1240 
1241 	/*	--line-size
1242 	*/
1243 	if (0 != dk4app_opt_is_set_long(app, dk_lines_kwnl[3], NULL)) {
1244 		if (0 != dk4app_opt_get_size_long(&sz, app, dk_lines_kwnl[3], NULL)) {
1245 			if (0 < sz) {
1246 				if (DK4_SIZEOF(default_input_line_buffer,dkChar) < sz) {
1247 					sz_ilb = sz;
1248 				}
1249 #if TRACE_DEBUG
1250 				else {
1251 				}
1252 #endif
1253 			}
1254 			else {
1255 				/* ERROR: Line size 0 */
1256 				dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 17);
1257 				back = 0;
1258 			}
1259 		}
1260 		else {
1261 			/* ERROR: Failed to retrieve line size */
1262 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 18);
1263 			back = 0;
1264 		}
1265 	}
1266 
1267 	/*	--today
1268 	*/
1269 	if (0 != dk4app_opt_is_set_long(app, dk_lines_kwnl[4], NULL)) {
1270 		if ((NULL == t_from) || (NULL == t_to)) {
1271 			dk4time_get(&timer);
1272 			res = dk4time_as_text(
1273 				date_buffer, DK4_SIZEOF(date_buffer,dkChar), &timer, NULL
1274 			);
1275 			if (0 != res) {
1276 				date_buffer[10] = dkT('\0');
1277 				if (NULL == t_from) {
1278 					t_from = date_buffer;
1279 					sz_t_from = dk4str_len(t_from);
1280 				}
1281 				if (NULL == t_to  ) {
1282 					t_to   = date_buffer;
1283 					sz_t_to   = dk4str_len(t_to);
1284 				}
1285 			}
1286 		}
1287 		else {
1288 			/* ERROR: --today used with --from and --to */
1289 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 19);
1290 		}
1291 	}
1292 
1293 	return back;
1294 }
1295 
1296 
1297 
1298 /**	Report an error with position.
1299 	@param	i1	Index of first message part in array.
1300 	@param	i2	Index of alternative first message part.
1301 	@param	bno	Current byte number.
1302 	@param	lno	Current line number.
1303 	@param	cno	Current character number.
1304 	@param	cil	Current character number within line.
1305 	@param	fn	File name processed.
1306 */
1307 static
1308 void
report_with_position(size_t i1,size_t i2,dk4_um_t bno,dk4_um_t lno,dk4_um_t cno,dk4_um_t cil,const dkChar * fn)1309 report_with_position(
1310 	size_t			 i1,
1311 	size_t			 i2,
1312 	dk4_um_t		 bno,
1313 	dk4_um_t		 lno,
1314 	dk4_um_t		 cno,
1315 	dk4_um_t		 cil,
1316 	const dkChar	*fn
1317 )
1318 {
1319 	dkChar			 b1[8*(1+sizeof(dk4_um_t))+16];
1320 	dkChar			 b2[8*(1+sizeof(dk4_um_t))+16];
1321 	dkChar			 b3[8*(1+sizeof(dk4_um_t))+16];
1322 	const dkChar	*oldlogname		=	NULL;
1323 	dk4_um_t		 oldlogline		=	(dk4_um_t)0UL;
1324 	const size_t	 szb3			=	DK4_SIZEOF(b3,dkChar);
1325 	const size_t	 szb2			=	DK4_SIZEOF(b2,dkChar);
1326 	const size_t	 szb1			=	DK4_SIZEOF(b1,dkChar);
1327 	int				 allbuffersok	=	0;
1328 
1329 	oldlogname =  dk4app_get_log_source_file(app);
1330 	oldlogline =  dk4app_get_log_source_line(app);
1331 	dk4app_set_log_source_file(app, fn);
1332 	dk4app_set_log_source_line(app, lno);
1333 	if (0 != dk4ma_write_decimal_unsigned(b3, szb3, cil, 0, NULL)) {
1334 		if (0 != dk4ma_write_decimal_unsigned(b2, szb2, cno, 0, NULL)) {
1335 			if (0 != dk4ma_write_decimal_unsigned(b1, szb1, bno, 0, NULL)) {
1336 				allbuffersok = 1;
1337 			}
1338 		}
1339 	}
1340 	if (0 != allbuffersok) {
1341 		dk4app_log_7(
1342 			app, msgs, sz_msg, DK4_LL_ERROR, i1, 37, 38, 39, b1, b2, b3
1343 		);
1344 	}
1345 	else {
1346 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, i2);
1347 	}
1348 	dk4app_set_log_source_line(app, oldlogline);
1349 	dk4app_set_log_source_file(app, oldlogname);
1350 }
1351 
1352 
1353 
1354 static
1355 void
report_errors_from_tsp(dk4_er_t * er_en,dk4_er_t * er_pr,const dkChar * fn)1356 report_errors_from_tsp(
1357 	dk4_er_t		*er_en,
1358 	dk4_er_t		*er_pr,
1359 	const dkChar	*fn
1360 )
1361 {
1362 	if (NULL != er_en) {
1363 		switch (er_en->ec) {
1364 			case DK4_E_DECODING_FAILED : {
1365 				if ((0 != verbose) || (max_r_decoding_e > num_r_decoding_e)) {
1366 					report_with_position(
1367 						35, 32,
1368 						er_en->dt.fpos.byteno, er_en->dt.fpos.lineno,
1369 						er_en->dt.fpos.charno, er_en->dt.fpos.charinline,
1370 						fn
1371 					);
1372 					num_r_decoding_e++;
1373 					if (num_r_decoding_e > max_r_decoding_e) {
1374 						num_r_decoding_e = max_r_decoding_e;
1375 					}
1376 				}
1377 			} break;
1378 			case DK4_E_ENCODING_FAILED : {
1379 				if ((0 != verbose) || (max_r_encoding_e > num_r_encoding_e)) {
1380 					report_with_position(
1381 						34, 31,
1382 						er_en->dt.fpos.byteno, er_en->dt.fpos.lineno,
1383 						er_en->dt.fpos.charno, er_en->dt.fpos.charinline,
1384 						fn
1385 					);
1386 					num_r_encoding_e++;
1387 					if (num_r_encoding_e > max_r_encoding_e) {
1388 						num_r_encoding_e = max_r_encoding_e;
1389 					}
1390 				}
1391 			} break;
1392 		}
1393 	}
1394 	if (NULL != er_pr) {
1395 		if (DK4_E_NONE != er_pr->ec) {
1396 			if ((0 != verbose) || (max_r_processing_e > num_r_processing_e)) {
1397 				report_with_position(
1398 					36, 33,
1399 					er_pr->dt.fpos.byteno, er_pr->dt.fpos.lineno,
1400 					er_pr->dt.fpos.charno, er_pr->dt.fpos.charinline,
1401 					fn
1402 				);
1403 				num_r_processing_e++;
1404 				if (num_r_processing_e > max_r_processing_e) {
1405 					num_r_processing_e = max_r_processing_e;
1406 				}
1407 			}
1408 		}
1409 	}
1410 }
1411 
1412 
1413 
1414 static
1415 int
write_text_line(const dkChar * line,dk4_er_t * erp)1416 write_text_line(const dkChar *line, dk4_er_t *erp)
1417 {
1418 	int		 back = DK4_TSP_RES_OK;
1419 	if (0 == dk4fputs(line, stdout, erp)) {
1420 		had_write_error = 1;
1421 		back = DK4_TSP_RES_ERROR;
1422 	}
1423 	if (0 == dk4fputc(dkT('\n'), stdout, erp)) {
1424 		had_write_error = 1;
1425 		back = DK4_TSP_RES_ERROR;
1426 	}
1427 	return back;
1428 }
1429 
1430 
1431 
1432 /**	Add new line to ring buffer, write line stored previously.
1433 	@param	line	New line to add.
1434 	@param	erp		Error report.
1435 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on error.
1436 */
1437 static
1438 int
ribu_add_and_print(const dkChar * line,dk4_er_t * erp)1439 ribu_add_and_print(const dkChar *line, dk4_er_t *erp)
1440 {
1441 	dkChar		*ptr;
1442 	size_t		 sz;
1443 	int			 back	= DK4_TSP_RES_OK;
1444 
1445 	sz = dk4str_len(line);
1446 	if ((SIZE_MAX) > sz) {
1447 		if ((NULL != pribu) && (0 < sz_ribu)) {
1448 			if (NULL != pribu[pos_ribu].str) {
1449 
1450 
1451 				if (0 != cycle_completed) {
1452 					back = write_text_line(pribu[pos_ribu].str, erp);
1453 				}
1454 				if (sz > pribu[pos_ribu].buflen) {
1455 					ptr = dk4str_dup_app(line, app);
1456 					if (NULL != ptr) {
1457 						dk4mem_free(pribu[pos_ribu].str);
1458 						pribu[pos_ribu].str = ptr;
1459 						pribu[pos_ribu].buflen = sz;
1460 					}
1461 					else {
1462 						back = DK4_TSP_RES_ERROR;
1463 						dk4error_set_simple_error_code(
1464 							erp, DK4_E_MEMORY_ALLOCATION_FAILED
1465 						);
1466 						/* ERROR: Memory allocation failed */
1467 					}
1468 				}
1469 				else {
1470 					(void)dk4str_cpy_s(
1471 						pribu[pos_ribu].str, (1 + pribu[pos_ribu].buflen),
1472 						line, NULL
1473 					);
1474 				}
1475 			}
1476 			else {
1477 				pribu[pos_ribu].str = dk4str_dup_app(line, app);
1478 				pribu[pos_ribu].buflen = sz;
1479 				if (NULL == pribu[pos_ribu].str) {
1480 					back = DK4_TSP_RES_ERROR;
1481 					dk4error_set_simple_error_code(
1482 						erp, DK4_E_MEMORY_ALLOCATION_FAILED
1483 					);
1484 					pribu[pos_ribu].buflen = 0;
1485 					/* ERROR: Memory allocation failed */
1486 				}
1487 			}
1488 
1489 
1490 			pribu[pos_ribu].lineno = lineno;
1491 			pos_ribu++;
1492 			if (pos_ribu >= sz_ribu) {
1493 				pos_ribu = 0;
1494 				cycle_completed = 1;
1495 			}
1496 		}
1497 		else {
1498 			back = DK4_TSP_RES_ERROR;
1499 			dk4error_set_simple_error_code(erp, DK4_E_BUG);
1500 			/* ERROR: No ring buffer */
1501 		}
1502 	}
1503 	else {
1504 		back = DK4_TSP_RES_ERROR;
1505 		dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
1506 		/* ERROR: Line too long */
1507 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 20);
1508 	}
1509 
1510 	return back;
1511 }
1512 
1513 
1514 
1515 /**	Add new line to ring buffer, do not print line previously stored.
1516 	@param	line	New line to add.
1517 	@param	erp		Error report.
1518 	@return	DK4_TSP_RES_OK on success, DK4_TSP_RES_ERROR on error.
1519 */
1520 static
1521 int
ribu_add_silently(const dkChar * line,dk4_er_t * erp)1522 ribu_add_silently(const dkChar *line, dk4_er_t *erp)
1523 {
1524 	dkChar		*ptr;
1525 	size_t		 sz;
1526 	int			 back	= DK4_TSP_RES_OK;
1527 
1528 
1529 	sz = dk4str_len(line);
1530 	if ((SIZE_MAX) > sz) {
1531 		if ((NULL != pribu) && (0 < sz_ribu)) {
1532 			if (NULL != pribu[pos_ribu].str) {
1533 
1534 
1535 
1536 
1537 				if (sz > pribu[pos_ribu].buflen) {
1538 					ptr = dk4str_dup_app(line, app);
1539 					if (NULL != ptr) {
1540 						dk4mem_free(pribu[pos_ribu].str);
1541 						pribu[pos_ribu].str = ptr;
1542 						pribu[pos_ribu].buflen = sz;
1543 					}
1544 					else {
1545 						dk4mem_release(pribu[pos_ribu].str);
1546 						pribu[pos_ribu].buflen = 0;
1547 						pribu[pos_ribu].lineno = (dk4_um_t)0UL;
1548 						back = DK4_TSP_RES_ERROR;
1549 						dk4error_set_simple_error_code(
1550 							erp, DK4_E_MEMORY_ALLOCATION_FAILED
1551 						);
1552 						/* ERROR: Memory allocation failed */
1553 					}
1554 				}
1555 				else {
1556 					(void)dk4str_cpy_s(
1557 						pribu[pos_ribu].str, (1 + pribu[pos_ribu].buflen),
1558 						line, NULL
1559 					);
1560 				}
1561 			}
1562 			else {
1563 				pribu[pos_ribu].str = dk4str_dup_app(line, app);
1564 				pribu[pos_ribu].buflen = sz;
1565 				if (NULL == pribu[pos_ribu].str) {
1566 					back = DK4_TSP_RES_ERROR;
1567 					dk4error_set_simple_error_code(
1568 						erp, DK4_E_MEMORY_ALLOCATION_FAILED
1569 					);
1570 					pribu[pos_ribu].buflen = 0;
1571 					/* ERROR: Memory allocation failed */
1572 				}
1573 			}
1574 
1575 
1576 			pribu[pos_ribu].lineno = lineno;
1577 			pos_ribu++;
1578 			if (pos_ribu >= sz_ribu) {
1579 				pos_ribu = 0;
1580 			}
1581 		}
1582 		else {
1583 			back = DK4_TSP_RES_ERROR;
1584 			dk4error_set_simple_error_code(erp, DK4_E_BUG);
1585 			/* ERROR: No ring buffer */
1586 		}
1587 	}
1588 	else {
1589 		back = DK4_TSP_RES_ERROR;
1590 		dk4error_set_simple_error_code(erp, DK4_E_MATH_OVERFLOW);
1591 		/* ERROR: Line too long */
1592 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 20);
1593 	}
1594 
1595 	return back;
1596 }
1597 
1598 
1599 
1600 static
1601 int
dk_lines_line_handler(void * DK4_ARG_UNUSED (obj),dkChar * line,dk4_um_t xlineno,dk4_er_t * erp)1602 dk_lines_line_handler(
1603 	void			*DK4_ARG_UNUSED(obj),
1604 	dkChar			*line,
1605 	dk4_um_t		 xlineno,
1606 	dk4_er_t		*erp
1607 )
1608 {
1609 	dk4_er_t	 er;
1610 	size_t		 sz		= 0;
1611 	int			 back	= DK4_TSP_RES_OK;
1612 	int			 ok		= 1;
1613 
1614 	DK4_UNUSED_ARG(obj)
1615 
1616 	dk4app_set_log_source_line(app, xlineno);
1617 	dk4str_delnl(line);
1618 
1619 	if ((NULL != t_from) && (0 < sz_t_from)) {
1620 #if VERSION_BEFORE_2017_11_20
1621 		sz = dk4str_len(line);
1622 		if (sz < sz_t_from) {
1623 			ok = 0;
1624 		}
1625 		else {
1626 			if (0 > dk4str_ncmp(line, t_from, sz_t_from)) { ok = 0; }
1627 		}
1628 #endif
1629 		if (0 > dk4str_cmp(line, t_from)) { ok = 0; }
1630 	}
1631 	if ((0 != ok) && (NULL != t_to) && (0 < sz_t_to)) {
1632 #if VERSION_BEFORE_2017_11_20
1633 		if (0 == sz) { sz = dk4str_len(line); }
1634 		if (sz < sz_t_to) {
1635 			if (0 < dk4str_ncmp(line, t_to, sz)) { ok = 0; }
1636 		}
1637 		else {
1638 			if (0 < dk4str_ncmp(line, t_to, sz_t_to)) { ok = 0; }
1639 		}
1640 #endif
1641 		sz = dk4str_len(line);
1642 		if (sz < sz_t_to) {
1643 			if (0 < dk4str_cmp(line, t_to)) { ok = 0; }
1644 		}
1645 		else {
1646 			if (0 < dk4str_ncmp(line, t_to, sz_t_to)) { ok = 0; }
1647 		}
1648 	}
1649 	if (0 != ok) {
1650 		dk4error_init(&er);
1651 		lineno = dk4ma_um_add(lineno, (dk4_um_t)1UL, &er);
1652 		if (DK4_E_NONE == er.ec) {
1653 
1654 			switch (l_type) {
1655 				case RANGE_NONE_NONE : {
1656 					back = write_text_line(line, erp);
1657 				} break;
1658 				case RANGE_NONE_POS : {
1659 					if (lineno <= l_end) {
1660 						back = write_text_line(line, erp);
1661 					}
1662 				} break;
1663 				case RANGE_NONE_NEG : {
1664 					back = ribu_add_and_print(line, erp);
1665 				} break;
1666 				case RANGE_POS_NONE : {
1667 					if (l_start <= lineno) {
1668 						back = write_text_line(line, erp);
1669 					}
1670 				} break;
1671 				case RANGE_POS_POS : {
1672 					if ((l_start <= lineno) && (lineno <= l_end)) {
1673 						back = write_text_line(line, erp);
1674 					}
1675 				} break;
1676 				case RANGE_POS_NEG : {
1677 					if (l_start <= lineno) {
1678 						back = ribu_add_and_print(line, erp);
1679 					}
1680 				} break;
1681 				case RANGE_NEG_NONE : {
1682 					back = ribu_add_silently(line, erp);
1683 				} break;
1684 				case RANGE_NEG_POS : {
1685 					back = ribu_add_silently(line, erp);
1686 				} break;
1687 				case RANGE_NEG_NEG : {
1688 					back = ribu_add_silently(line, erp);
1689 				} break;
1690 			}
1691 		}
1692 		else {
1693 			back = DK4_TSP_RES_ERROR;
1694 			dk4error_copy(erp, &er);
1695 			/* ERROR: Overflow in line number */
1696 			dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 21);
1697 		}
1698 	}
1699 
1700 
1701 	return back;
1702 }
1703 
1704 
1705 
1706 /**	Flush the ring buffer after finishing file or stream.
1707 */
1708 static
1709 void
flush_ring_buffer(void)1710 flush_ring_buffer(void)
1711 {
1712 	dk4_er_t	er;
1713 	dk4_um_t	umax;
1714 	size_t		i;
1715 	size_t		idx;
1716 	size_t		max;
1717 
1718 	switch (l_type) {
1719 		case RANGE_NONE_NONE : {
1720 			/* Empty by intent, ring buffer not used */
1721 		} break;
1722 		case RANGE_NONE_POS : {
1723 			/* Empty by intent, ring buffer not used */
1724 		} break;
1725 		case RANGE_NONE_NEG : case RANGE_POS_NEG : {
1726 			/* Empty by intent, lines of interest already printed */
1727 		} break;
1728 		case RANGE_POS_NONE : {
1729 			/* Empty by intent, ring buffer not used */
1730 		} break;
1731 		case RANGE_POS_POS : {
1732 			/* Empty by intent, ring buffer not used */
1733 		} break;
1734 		case RANGE_NEG_NONE : {
1735 			idx = pos_ribu;
1736 			for (i = 0; i < sz_ribu; i++) {
1737 
1738 				if (NULL != pribu[idx].str) {
1739 
1740 					if (0 == dk4fputs(pribu[idx].str, stdout, NULL)) {
1741 						had_write_error = 1;
1742 					}
1743 					if (0 == dk4fputc(dkT('\n'), stdout, NULL)) {
1744 						had_write_error = 1;
1745 					}
1746 				}
1747 #if TRACE_DEBUG
1748 				else {
1749 				}
1750 #endif
1751 				idx++; if (idx >= sz_ribu) { idx = 0; }
1752 			}
1753 		} break;
1754 		case RANGE_NEG_POS : {
1755 			idx = pos_ribu;
1756 			for (i = 0; i < sz_ribu; i++) {
1757 				if ((NULL != pribu[idx].str) && (pribu[idx].lineno <= l_end)) {
1758 					if (0 == dk4fputs(pribu[idx].str, stdout, NULL)) {
1759 						had_write_error = 1;
1760 					}
1761 					if (0 == dk4fputc(dkT('\n'), stdout, NULL)) {
1762 						had_write_error = 1;
1763 					}
1764 				}
1765 				idx++; if (idx >= sz_ribu) { idx = 0; }
1766 			}
1767 		} break;
1768 		case RANGE_NEG_NEG : {
1769 			dk4error_init(&er);
1770 			umax = dk4ma_um_add(
1771 				dk4ma_um_sub(l_start, l_end, &er),
1772 				(dk4_um_t)1UL,
1773 				&er
1774 			);
1775 			if (DK4_E_NONE == er.ec) {
1776 				if ((dk4_um_t)(SIZE_MAX) >= umax) {
1777 					max = (size_t)umax;
1778 					idx = pos_ribu;
1779 					for (i = 0; i < max; i++) {
1780 						if (NULL != pribu[idx].str) {
1781 							if (0 == dk4fputs(pribu[idx].str, stdout, NULL)) {
1782 								had_write_error = 1;
1783 							}
1784 							if (0 == dk4fputc(dkT('\n'), stdout, NULL)) {
1785 								had_write_error = 1;
1786 							}
1787 						}
1788 						idx++; if (idx >= sz_ribu) { idx = 0; }
1789 					}
1790 				}
1791 				else {
1792 					exval = EXIT_FAILURE;
1793 					/* ERROR: Overflow in line range calculation */
1794 					dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 22);
1795 				}
1796 			}
1797 			else {
1798 				exval = EXIT_FAILURE;
1799 				/* ERROR: Overflow in line range calculation */
1800 				dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 22);
1801 			}
1802 		} break;
1803 	}
1804 }
1805 
1806 
1807 
1808 /**	Process file contents.
1809 	@param	fipo	File, opened for binary read access.
1810 	@param	fn		File name (for diagnostics).
1811 	@param	eie		Expected input encoding.
1812 */
1813 static
1814 void
run_for_file_with_name(FILE * fipo,const dkChar * fn,int eie)1815 run_for_file_with_name(FILE *fipo, const dkChar *fn, int eie)
1816 {
1817 	dk4_tspdk_t		 tsp;				/* Text stream processor */
1818 	dk4_er_t		 er_en;				/* Error report for enc/decoding */
1819 	dk4_er_t		 er_pr;				/* Error report for processing */
1820 	dk4_er_t		 er;				/* General error report */
1821 	const dkChar	*oldlogname	= NULL;	/* Old source file */
1822 	dk4_um_t		 oldlogline	= 0UL;	/* Old source line */
1823 	size_t			 i;					/* Traverse ring buffer elements */
1824 	int				 c;					/* Current character retrieved */
1825 	int				 res;				/* Operation result */
1826 	int				 cc;				/* Flag: Can continue */
1827 	unsigned char	 uc;				/* Byte added to processor */
1828 
1829 
1830 	oldlogname =  dk4app_get_log_source_file(app);
1831 	oldlogline =  dk4app_get_log_source_line(app);
1832 	dk4app_set_log_source_file(app, fn);
1833 	dk4app_set_log_source_line(app, (dk4_um_t)0UL);
1834 	/*	Initialize handling of one file
1835 	*/
1836 	if (0 == one_stream) {
1837 		lineno		= (dk4_um_t)0UL;
1838 		pos_ribu	= 0;
1839 		if (NULL != pribu) {
1840 			for (i = 0; i < sz_ribu; i++) {
1841 				pribu[i].str = NULL;
1842 				pribu[i].lineno = (dk4_um_t)0UL;
1843 				pribu[i].buflen = 0;
1844 			}
1845 		}
1846 	}
1847 
1848 	/*	Process file contents in loop
1849 	*/
1850 	dk4error_init(&er_en);
1851 	dk4error_init(&er_pr);
1852 	dk4error_init(&er);
1853 	res = dk4tspdk_setup_line(
1854 		&tsp, NULL, dk_lines_line_handler, ilb, sz_ilb,
1855 		dk4app_get_encoding(app), eie, &er
1856 	);
1857 	if (0 != res) {
1858 		cc = 1;
1859 		while(1 == cc) {
1860 			cc = -1;
1861 			if (0 != sig_can_continue(1)) {
1862 				c = fgetc(fipo);
1863 				if (EOF != c) {
1864 					cc = 1;
1865 					uc = (unsigned char)c;
1866 					switch (dk4tspdk_add_one_byte(&tsp, uc)) {
1867 						case DK4_TSP_RES_FATAL : {
1868 							cc = -1;
1869 							exval = EXIT_FAILURE;
1870 							dk4tspdk_get_errors(&er_en, &er_pr, &tsp);
1871 							report_errors_from_tsp(&er_en, &er_pr, fn);
1872 						} break;
1873 						case DK4_TSP_RES_ERROR : {
1874 							exval = EXIT_FAILURE;
1875 							dk4tspdk_get_errors(&er_en, &er_pr, &tsp);
1876 							report_errors_from_tsp(&er_en, &er_pr, fn);
1877 						} break;
1878 					}
1879 				}
1880 				else {
1881 					cc = 0;
1882 				}
1883 			}
1884 		}
1885 		/*	Flush data from text processor
1886 		*/
1887 		if (0 == cc) {
1888 			switch (dk4tspdk_finish(&tsp)) {
1889 				case DK4_TSP_RES_FATAL : case DK4_TSP_RES_ERROR : {
1890 					exval = EXIT_FAILURE;
1891 					dk4tspdk_get_errors(&er_en, &er_pr, &tsp);
1892 					report_errors_from_tsp(&er_en, &er_pr, fn);
1893 				} break;
1894 			}
1895 		}
1896 	}
1897 	dk4app_set_log_source_line(app, (dk4_um_t)0UL);
1898 
1899 	/*	Flush data from ring buffer
1900 	*/
1901 	if (0 == one_stream) {
1902 		flush_ring_buffer();
1903 	}
1904 
1905 	/*	Clean up resources
1906 	*/
1907 	if (0 == one_stream) {
1908 		cycle_completed = 0;
1909 		if (NULL != pribu) {
1910 			for (i = 0; i < sz_ribu; i++) {
1911 				dk4mem_release(pribu[i].str);
1912 				pribu[i].lineno = (dk4_um_t)0UL;
1913 				pribu[i].buflen = 0;
1914 			}
1915 		}
1916 	}
1917 	dk4app_set_log_source_line(app, oldlogline);
1918 	dk4app_set_log_source_file(app, oldlogname);
1919 
1920 }
1921 
1922 
1923 
1924 /**	Open and process a file.
1925 	@param	fn	File name to process.
1926 */
1927 static
1928 void
run_for_filename(const dkChar * fn)1929 run_for_filename(const dkChar *fn)
1930 {
1931 	const dkChar	*oldlogname	=	NULL;
1932 	FILE			*fipo		=	NULL;
1933 	dk4_um_t		 oldlogline	=	(dk4_um_t)0UL;
1934 	int				 tests	= DK4_FOPEN_SC_USER;
1935 
1936 	oldlogname =  dk4app_get_log_source_file(app);
1937 	oldlogline =  dk4app_get_log_source_line(app);
1938 	dk4app_set_log_source_file(app, fn);
1939 	dk4app_set_log_source_line(app, (dk4_um_t)0UL);
1940 	if (dk4isadmin()) { tests = DK4_FOPEN_SC_PRIVILEGED; }
1941 
1942 	fipo = dk4fopen_app(fn, dk_lines_kwnl[6], tests, app);
1943 	if (NULL != fipo) {
1944 		run_for_file_with_name(fipo, fn, eie_file);
1945 		fclose(fipo);
1946 	}
1947 	else {
1948 		exval = EXIT_FAILURE;
1949 	}
1950 	dk4app_set_log_source_line(app, oldlogline);
1951 	dk4app_set_log_source_file(app, oldlogname);
1952 
1953 }
1954 
1955 
1956 
1957 #if DK4_ON_WINDOWS
1958 
1959 static
1960 void
expand_filename_and_run(const dkChar * pattern)1961 expand_filename_and_run(const dkChar *pattern)
1962 {
1963 	dkChar			 buf[DK4_MAX_PATH];
1964 	dk4_dir_t		*fne;
1965 	const dkChar	*shf;
1966 	const dkChar	*pth;
1967 	const size_t	 szbuf	= DK4_SIZEOF(buf,dkChar);
1968 	int				 any_file_found = 0;
1969 	int				 cc;
1970 	int				 ok;
1971 
1972 	fne = dk4app_fne_open(pattern, app);
1973 	if (NULL != fne) {
1974 		pth = dk4dir_get_path(fne);
1975 		cc = 1;
1976 		while (1 == cc) {
1977 			if (0 != sig_can_continue(1)) {
1978 				shf = dk4dir_next_file(fne);
1979 				if (NULL != shf) {
1980 					any_file_found = 1;
1981 					if (NULL != pth) {
1982 						ok = 1;
1983 						if (0 == dk4str_cpy_s(buf, szbuf, pth, NULL)) {
1984 							ok = 0;
1985 						}
1986 						if(0 != dk4str_cat_s(buf, szbuf, fnsep, NULL)) {
1987 							ok = 0;
1988 						}
1989 						if(0 != dk4str_cat_s(buf, szbuf, shf, NULL)) {
1990 							ok = 0;
1991 						}
1992 						if (1 == ok) {
1993 							run_for_filename(buf);
1994 						}
1995 						else {
1996 							/* ERROR: Path too long */
1997 							exval = EXIT_FAILURE;
1998 							dk4app_log_base3(app,DK4_LL_ERROR,100,105,pattern);
1999 						}
2000 					}
2001 					else {
2002 						run_for_filename(shf);
2003 					}
2004 				}
2005 				else {
2006 					cc = 0;
2007 				}
2008 			}
2009 			else {
2010 				cc = -1;
2011 			}
2012 		}
2013 		dk4dir_close(fne);
2014 		if (0 == any_file_found) {
2015 			exval = EXIT_FAILURE;
2016 			dk4app_log_base3(app, DK4_LL_ERROR, 100, 107, pattern);
2017 		}
2018 	}
2019 	else {
2020 		exval = EXIT_FAILURE;
2021 		/* ERROR: Failed to open file name expander (already reported) */
2022 	}
2023 
2024 }
2025 
2026 #endif
2027 
2028 
2029 
2030 /**	Allocate ring buffer used for negative line numbers.
2031 	@return	1 on success, 0 on error.
2032 */
2033 static
2034 int
allocate_ring_buffer(void)2035 allocate_ring_buffer(void)
2036 {
2037 	size_t		 i;
2038 	int			 back	= 1;
2039 
2040 	switch (l_type) {
2041 		case RANGE_NONE_NEG : case RANGE_POS_NEG : case RANGE_NEG_NONE :
2042 		case RANGE_NEG_POS  : case RANGE_NEG_NEG : {
2043 			back = 0;
2044 			switch (l_type) {
2045 				case RANGE_NONE_NEG : case RANGE_POS_NEG : {
2046 					if ((dk4_um_t)(SIZE_MAX) >= l_end) {
2047 						if ((dk4_um_t)1UL < l_end) {
2048 							sz_ribu = (size_t)(l_end - (dk4_um_t)1UL);
2049 						}
2050 						else {
2051 							/* BUG: l_end is 1, should not happen */
2052 							dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 23);
2053 						}
2054 					}
2055 					else {
2056 						/* ERROR: Numeric overflow */
2057 						dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 24);
2058 					}
2059 				} break;
2060 				default : {
2061 					if ((dk4_um_t)(SIZE_MAX) >= l_start) {
2062 						sz_ribu = (size_t)l_start;
2063 					}
2064 					else {
2065 						/* ERROR: Numeric overflow */
2066 						dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 25);
2067 					}
2068 				} break;
2069 			}
2070 			if (0 < sz_ribu) {
2071 				pribu = dk4mem_new_app(rbe_t,sz_ribu,app);
2072 				if (NULL != pribu) {
2073 					back = 1;
2074 					for (i = 0; i < sz_ribu; i++) {
2075 						pribu[i].str = NULL;
2076 						pribu[i].lineno = (dk4_um_t)0UL;
2077 						pribu[i].buflen = 0;
2078 					}
2079 				}
2080 				else {
2081 					/* ERROR: Memory allocation failed (already reported) */
2082 				}
2083 			}
2084 			else {
2085 				/* Invalid ring buffer size */
2086 				dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 26);
2087 			}
2088 		} break;
2089 		default : {
2090 			/* Empty by intent */
2091 		} break;
2092 	}
2093 
2094 	return back;
2095 }
2096 
2097 
2098 
2099 /**	Allocate ring buffer if necessary and process input.
2100 */
2101 static
2102 void
run_for_input(void)2103 run_for_input(void)
2104 {
2105 	const dkChar	*fnptr;
2106 	size_t			 xi;
2107 	int				 argc;
2108 	int				 i;
2109 
2110 	if (0 != allocate_ring_buffer()) {
2111 		/*
2112 			Initialize handling of one large data stream
2113 		*/
2114 		if (0 != one_stream) {
2115 			lineno		= (dk4_um_t)0UL;
2116 			pos_ribu	= 0;
2117 			if (NULL != pribu) {
2118 				for (xi = 0; xi < sz_ribu; xi++) {
2119 					pribu[xi].str = NULL;
2120 					pribu[xi].lineno = (dk4_um_t)0UL;
2121 					pribu[xi].buflen = 0;
2122 				}
2123 			}
2124 		}
2125 		argc = dk4app_get_argc(app);
2126 		if (0 < argc) {
2127 			for (i = 0; ((i < argc) && (0 != sig_can_continue(1))); i++) {
2128 				fnptr = dk4app_get_argv(app, i);
2129 				if (NULL != fnptr) {
2130 #if DK4_ON_WINDOWS
2131 					if (0 != dk4path_must_expand(fnptr)) {
2132 						expand_filename_and_run(fnptr);
2133 					}
2134 					else {
2135 #endif
2136 						run_for_filename(fnptr);
2137 #if DK4_ON_WINDOWS
2138 					}
2139 #endif
2140 				}
2141 				else {
2142 					exval = EXIT_FAILURE;
2143 					/* ERROR: Did not obtain file name */
2144 					dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 27);
2145 				}
2146 			}
2147 		}
2148 		else {
2149 			run_for_file_with_name(stdin, dk_lines_kwnl[7], eie_stdin);
2150 		}
2151 		/*	Flush ring buffer and clean up resources for large data stream
2152 		*/
2153 		if (0 != one_stream) {
2154 			/*
2155 				Flush ring buffer
2156 			*/
2157 			flush_ring_buffer();
2158 			/*
2159 				Release ring buffer resources
2160 			*/
2161 			cycle_completed = 0;
2162 			if (NULL != pribu) {
2163 				for (xi = 0; xi < sz_ribu; xi++) {
2164 					dk4mem_release(pribu[xi].str);
2165 					pribu[xi].lineno = (dk4_um_t)0UL;
2166 					pribu[xi].buflen = 0;
2167 				}
2168 			}
2169 		}
2170 	}
2171 #if TRACE_DEBUG
2172 	else {
2173 	}
2174 #endif
2175 	if (NULL != pribu) {
2176 		dk4mem_free(pribu);
2177 	}
2178 
2179 }
2180 
2181 
2182 
2183 /**	Run the functionality.
2184 */
2185 static
2186 void
run_the_functions(void)2187 run_the_functions(void)
2188 {
2189 	dkChar		*mybuf	= NULL;
2190 
2191 
2192 	if (0 != process_command_line_arguments()) {
2193 		/*
2194 			If a line buffer larger than default is required,
2195 			allocate the buffer and run
2196 		*/
2197 		if (DK4_SIZEOF(default_input_line_buffer,dkChar) < sz_ilb) {
2198 			mybuf = dk4mem_new_app(dkChar,sz_ilb,app);
2199 			if (NULL != mybuf) {
2200 				ilb = mybuf;
2201 				run_for_input();
2202 				dk4mem_free(mybuf);
2203 			}
2204 			else {
2205 				exval = EXIT_FAILURE;
2206 			}
2207 		}
2208 		/*	Otherwise run with default buffer
2209 		*/
2210 		else {
2211 			run_for_input();
2212 		}
2213 	}
2214 	else {
2215 		exval = EXIT_FAILURE;
2216 	}
2217 
2218 }
2219 
2220 
2221 #if	DK4_HAVE_SIGACTION
2222 /**	Set signal handlers and run.
2223 */
2224 static
2225 void
run_with_signals(void)2226 run_with_signals(void)
2227 {
2228 #ifdef SIGPIPE
2229 	struct sigaction opipe;
2230 #endif
2231 	struct sigaction oint;
2232 	struct sigaction oterm;
2233 #ifdef SIGPIPE
2234 	struct sigaction npipe;
2235 #endif
2236 	struct sigaction nint;
2237 	struct sigaction nterm;
2238 	int	 success = 0;
2239 
2240 #ifdef SIGPIPE
2241 	/*	Set up signal handling for SIGPIPE.
2242 	*/
2243 	DK4_MEMRES(&npipe, sizeof(npipe));
2244 	npipe.sa_handler = sig_handler_pipe;
2245 	npipe.sa_flags = 0;
2246 	if (0 != sigemptyset(&npipe.sa_mask)) {
2247 		/* ERROR: Failed to set up masked signal set for SIGPIPE */
2248 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 0);
2249 		goto finished;
2250 	}
2251 	if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) {
2252 		/* ERROR: Failed to set up masked signal set for SIGPIPE */
2253 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 0);
2254 		goto finished;
2255 	}
2256 	if (0 != sigaction(SIGPIPE, &npipe, &opipe)) {
2257 		/* ERROR: Failed to set up signal handler for SIGPIPE */
2258 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 0);
2259 		goto finished;
2260 	}
2261 #endif
2262 
2263 	/*	Set up signal handling for SIGINT.
2264 	*/
2265 	DK4_MEMRES(&nint, sizeof(nint));
2266 	nint.sa_handler = sig_handler_int;
2267 	nint.sa_flags = 0;
2268 	if (0 != sigemptyset(&nint.sa_mask)) {
2269 		/* ERROR: Failed to set up masked signal set for SIGINT */
2270 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 1);
2271 		goto restore_old_pipe;
2272 	}
2273 	if (0 != sigaddset(&nint.sa_mask, SIGINT)) {
2274 		/* ERROR: Failed to set up masked signal set for SIGINT */
2275 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 1);
2276 		goto restore_old_pipe;
2277 	}
2278 	if (0 != sigaction(SIGINT, &nint, &oint)) {
2279 		/* ERROR: Failed to set up signal handler for SIGINT */
2280 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 1);
2281 		goto restore_old_pipe;
2282 	}
2283 
2284 	/*	Set up signal handling for SIGTERM
2285 	*/
2286 	DK4_MEMRES(&nterm, sizeof(nterm));
2287 	nterm.sa_handler = sig_handler_term;
2288 	nterm.sa_flags = 0;
2289 	if (0 != sigemptyset(&nterm.sa_mask)) {
2290 		/* ERROR: Failed to set up masked signal set for SIGTERM */
2291 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 2);
2292 		goto restore_old_int;
2293 	}
2294 	if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) {
2295 		/* ERROR: Failed to set up masked signal set for SIGTERM */
2296 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 2);
2297 		goto restore_old_int;
2298 	}
2299 	if (0 != sigaction(SIGTERM, &nterm, &oterm)) {
2300 		/* ERROR: Failed to set up signal handler for SIGTERM */
2301 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 2);
2302 		goto restore_old_int;
2303 	}
2304 
2305 	success = 1;
2306 	run_the_functions();
2307 
2308 	/*	Restore signal handling for SIGTERM.
2309 	*/
2310 	if (0 != sigaction(SIGTERM, &oterm, NULL)) {
2311 		/* ERROR: Failed to restore old SIGTERM settings */
2312 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 3);
2313 		success = 0;
2314 	}
2315 
2316 	/*	Restore signal handling for SIGINT.
2317 	*/
2318 	restore_old_int:
2319 	if (0 != sigaction(SIGINT, &oint, NULL)) {
2320 		/* ERROR: Failed to restore old SIGINT settings */
2321 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 4);
2322 		success = 0;
2323 	}
2324 
2325 #ifdef SIGPIPE
2326 	/*	Restore signal handling for SIGPIPE.
2327 	*/
2328 	restore_old_pipe:
2329 	if (0 != sigaction(SIGPIPE, &opipe, NULL)) {
2330 		/* ERROR: Failed to restore old SIGPIPE settings */
2331 		dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 5);
2332 		success = 0;
2333 	}
2334 #endif
2335 
2336 	/*	Set exit status code if error occured.
2337 	*/
2338 	finished:
2339 	if (0 == success) {
2340 		exval = EXIT_FAILURE;
2341 	}
2342 }
2343 #else
2344 #if	DK4_HAVE_SIGSET
2345 /**	Set signal handlers and run.
2346 */
2347 static
2348 void
run_with_signals(void)2349 run_with_signals(void)
2350 {
2351 #ifdef SIGPIPE
2352 	dk4_sig_handler_t	*oldpipe = NULL;
2353 #endif
2354 	dk4_sig_handler_t	*oldint  = NULL;
2355 	dk4_sig_handler_t	*oldterm = NULL;
2356 
2357 #ifdef SIGPIPE
2358 	oldpipe = sigset(SIGPIPE, sig_handler_pipe);
2359 #endif
2360 	oldint  = sigset(SIGINT,  sig_handler_int);
2361 	oldterm = sigset(SIGTERM, sig_handler_term);
2362 	run_the_functions();
2363 	sigset(SIGTERM, oldterm);
2364 	sigset(SIGINT,  oldint);
2365 #ifdef SIGPIPE
2366 	sigset(SIGPIPE, oldpipe);
2367 #endif
2368 }
2369 #else
2370 #if	DK4_HAVE_SIGNAL
2371 /**	Set signal handlers and run.
2372 */
2373 static
2374 void
run_with_signals(void)2375 run_with_signals(void)
2376 {
2377 #ifdef SIGPIPE
2378 	dk4_sig_handler_t	*oldpipe = NULL;
2379 #endif
2380 	dk4_sig_handler_t	*oldint  = NULL;
2381 	dk4_sig_handler_t	*oldterm = NULL;
2382 #ifdef SIGPIPE
2383 	oldpipe = signal(SIGPIPE, sig_handler_pipe);
2384 #endif
2385 	oldint  = signal(SIGINT,  sig_handler_int);
2386 	oldterm = signal(SIGTERM, sig_handler_term);
2387 	run_the_functions();
2388 	signal(SIGTERM, oldterm);
2389 	signal(SIGINT,  oldint);
2390 #ifdef SIGPIPE
2391 	signal(SIGPIPE, oldpipe);
2392 #endif
2393 }
2394 #else
2395 /**	Set signal handlers and run.
2396 */
2397 static
2398 void
run_with_signals(void)2399 run_with_signals(void)
2400 {
2401 	run_the_functions();
2402 }
2403 #endif
2404 #endif
2405 #endif
2406 
2407 
2408 /**	Main function.
2409 	@param	argc	Number of command line arguments.
2410 	@param	argv	Command line arguments array.
2411 	@return	0 on success, all other values indicate errors.
2412 */
2413 #if DK4_CHAR_SIZE > 1
wmain(int argc,wchar_t * argv[])2414 int wmain(int argc, wchar_t *argv[])
2415 #else
2416 int main(int argc, char *argv[])
2417 #endif
2418 {
2419 	dk4_sig_atomic_t	shp;
2420 
2421 
2422 	dk4fput_initialize_stdout();
2423 	dk4fput_initialize_stderr();
2424 	app = dk4app_open_cmd(
2425 		argc, argv, dk_lines_options, dk_lines_sz_options,
2426 		dk_lines_kwnl[0], DKT_VERSION_DK,
2427 		dk_lines_kwnl[1], dk_lines_help_text, dk_lines_license_text
2428 	);
2429 	if (NULL != app) {
2430 		sz_msg	=	dk4app_string_table_size(dk_lines_kw_def);
2431 		msgs	=	dk4app_string_table(app, dk_lines_kwnl[2], dk_lines_kw_def);
2432 		eie_file  = dk4app_get_file_in_encoding(app);
2433 		eie_stdin = dk4app_get_stdin_encoding(app);
2434 		if (0 != dk4app_can_run_normally(app)) {
2435 			exval = EXIT_SUCCESS;
2436 			run_with_signals();
2437 #ifdef	SIGPIPE
2438 			shp = sig_read_atomic(&sig_had_pipe);
2439 #else
2440 			shp = 0;
2441 #endif
2442 			if (0 != shp) {
2443 				if (0 != verbose) {
2444 					/* ERROR: Stopped by SIGPIPE */
2445 					dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 28);
2446 				}
2447 				exval = EXIT_FAILURE;
2448 			}
2449 			else {
2450 				if (0 != had_write_error) {
2451 					/* ERROR: Had write error */
2452 					dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 29);
2453 					exval = EXIT_FAILURE;
2454 				}
2455 			}
2456 			if (0 != sig_read_atomic(&sig_had_int)) {
2457 				/* ERROR: Stopped by interrupt */
2458 				dk4app_log_1(app, msgs, sz_msg, DK4_LL_ERROR, 30);
2459 			}
2460 		}
2461 		else {
2462 			if (0 != dk4app_help_version_license(app)) {
2463 				exval = EXIT_SUCCESS;
2464 			}
2465 		}
2466 		dk4app_close(app);
2467 	}
2468 	fflush(stdout);
2469 	fflush(stderr);
2470 	dk4fput_cleanup_stderr();
2471 	dk4fput_cleanup_stdout();
2472 
2473 
2474 	exit(exval); return exval;
2475 }
2476 
2477 /* vim: set ai sw=4 ts=4 : */
2478