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