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