1%% options 2 3copyright owner = Dirk Krause 4copyright year = 2015-xxxx 5SPDX-License-Identifier: BSD-3-Clause 6 7%% module 8 9#include "dk4conf.h" 10 11#if DK4_ON_WINDOWS 12#ifndef WINDOWS_H_INCLUDED 13#include <windows.h> 14#define WINDOWS_H_INCLUDED 15#endif 16#endif 17 18#if DK4_HAVE_SIGNAL_H 19#ifndef SIGNAL_H_INCLUDED 20#include <signal.h> 21#define SIGNAL_H_INCLUDED 1 22#endif 23#endif 24 25#if DK4_HAVE_IO_H 26#ifndef IO_H_INCLUDED 27#include <io.h> 28#define IO_H_INCLUDED 1 29#endif 30#endif 31 32#if DK4_HAVE_FCNTL_H 33#ifndef FCNTL_H_INCLUDED 34#include <fcntl.h> 35#define FCNTL_H_INCLUDED 1 36#endif 37#endif 38 39#include <libdk4base/dk4types.h> 40#include <libdk4base/dk4const.h> 41#include <libdk4base/dk4vers.h> 42#include <libdk4app/dk4app.h> 43#include <libdk4app/dk4aopt.h> 44#include <libdk4base/dk4mem.h> 45#include <libdk4app/dk4mema.h> 46#include <libdk4c/dk4fput.h> 47#include <libdk4base/dk4mpl.h> 48#include <libdk4maiodd/dk4maiddbl.h> 49#if 0 50#include <libdk4maiodh/dk4maidhmu.h> 51#include <libdk4maiodd/dk4maiddmu.h> 52#include <libdk4maiodd/dk4maiddmi.h> 53#endif 54#include <libdk4maiodd/dk4maidddu.h> 55#include <libdk4maiodh/dk4maidhdu.h> 56#include <libdk4maiodd/dk4maidddi.h> 57#include <libdk4maiodd/dk4maodd.h> 58#include <libdk4c/dk4enc.h> 59#include <libdk4base/dk4strd.h> 60#include <libdk4app/dk4strda.h> 61#include <libdk4c/dk4tspdk.h> 62#include <libdk4app/dk4fopda.h> 63#include <libdk4c/dk4pathd.h> 64#include <libdk4c/dk4filed.h> 65#include <libdk4base/dk4unused.h> 66 67#ifndef DK4WMAIN_H_INCLUDED 68#include <libdk4base/dk4wmain.h> 69#endif 70 71 72$!trace-include 73 74 75 76/** Structure to store one line, optionally with evaluation result. 77*/ 78typedef struct { 79 dkChar *line; /**< Text line. */ 80 dkChar *fts; /**< File type suffix. */ 81 union { 82 dk4_um_t u; /**< Unsigned number at start of line. */ 83 dk4_im_t i; /**< Signed number at start of line. */ 84 double d; /**< Floating point number at start of line. */ 85 } value; /**< Value at start of line. */ 86 char h; /**< Flag: Have value. */ 87} dk_sort_line_t; 88 89 90/** Default help text, shown if help file is not found. 91*/ 92static const dkChar * const dk_sort_help_text[] = { 93$!text macro=dkT 94 95Sort text line by line 96 97dk-sort [<options>] [<file(s)>] 98 99Options: 100-i <encoding> --input-encoding=<encoding> Expected input encoding. 101-c --case-insensitive Case-insensitive comparisons. 102-b --ignore-leading-blanks Ignore leading whitespaces. 103-w --normalize Normalize text lines. 104-e --suppress-empty-lines Suppress output for empty lines. 105-t --file-type Sort by file type. 106-s <size> --skip-words=<size> Number of words to skip. 107-n --number Leading signed integer values. 108-u --unsigned Leading unsigned integer values. 109-x --hex Leading hexadecimal numbers. 110-f --float Leading floating point numbers. 111-v --value-lines-first Lines containing numbers first. 112-m --merge-equal-lines Merge equal lines. 113-r --reverse Reverse output order. 114-l <size> --line-size=<size> Line buffer sizes. 115-R --reset Ignore preferences values. 116 117--help Show this short help text. 118--manual *** SHOW FULL MANUAL. *** 119--version Show version information. 120--license Show license information. 121 122http://sourceforge.net/p/dktools/wiki/dk-sort/ 123 124$!end 125}; 126 127 128 129/** License text. 130*/ 131static const dkChar * const dk_sort_license_text[] = { 132$!text macro=dkT,preprocessor 133This software uses code from the following projects, either directly or as 134a library: 135 136dktools Dirk Krause's tools and libraries. 137 See http://sourceforge.net/p/dktools/wiki/Home/ 138 for more information. 139#if DK4_HAVE_ZLIB_H 140 141zlib Data compression library. 142 See http://www.zlib.net/ for more information. 143#endif 144#if DK4_HAVE_BZLIB_H 145 146bzip2 Data compression program and library. 147 See http://www.bzip.org/ for more information. 148#endif 149 150All the licenses below apply to the program. 151Licenses for used libraries are shown as found on my Scientific Linux 6.x 152computer in the /usr/share/doc directory on 2015-04-01. Check the project 153homepages of the used libraries for additional information and/or updated 154license terms. 155 156 157DK tools and libraries license 158============================== 159Copyright (c) 2015-2016, Dirk Krause 160All rights reserved. 161 162Redistribution and use in source and binary forms, with or without 163modification, are permitted provided that the following conditions are met: 164 1651. Redistributions of source code must retain the above copyright notice, 166 this list of conditions and the following disclaimer. 1672. Redistributions in binary form must reproduce the above copyright 168 notice, this list of conditions and the following disclaimer in the 169 documentation and/or other materials provided with the distribution. 1703. Neither the name of the copyright holder nor the names of its 171 contributors may be used to endorse or promote products derived from 172 this software without specific prior written permission. 173 174THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 176LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 177A PARTICULAR PURPOSE ARE DISCLAIMED. 178IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 179DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 180(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 181SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 182CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 183LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 184OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 185SUCH DAMAGE. 186#if DK4_HAVE_ZLIB_H 187 188 189Zlib license 190============ 191(C) 1995-2004 Jean-loup Gailly and Mark Adler 192 193This software is provided 'as-is', without any express or implied 194warranty. In no event will the authors be held liable for any damages 195arising from the use of this software. 196 197Permission is granted to anyone to use this software for any purpose, 198including commercial applications, and to alter it and redistribute it 199freely, subject to the following restrictions: 200 2011. The origin of this software must not be misrepresented; you must not 202 claim that you wrote the original software. If you use this software 203 in a product, an acknowledgment in the product documentation would be 204 appreciated but is not required. 2052. Altered source versions must be plainly marked as such, and must not be 206 misrepresented as being the original software. 2073. This notice may not be removed or altered from any source distribution. 208 209Jean-loup Gailly Mark Adler 210jloup@gzip.org madler@alumni.caltech.edu 211#endif 212#if DK4_HAVE_BZLIB_H 213 214 215Bzip2 and libbzip2 library license 216================================== 217This program, "bzip2", the associated library "libbzip2", and all 218documentation, are copyright (C) 1996-2007 Julian R Seward. All 219rights reserved. 220 221Redistribution and use in source and binary forms, with or without 222modification, are permitted provided that the following conditions 223are met: 224 2251. Redistributions of source code must retain the above copyright 226 notice, this list of conditions and the following disclaimer. 227 2282. The origin of this software must not be misrepresented; you must 229 not claim that you wrote the original software. If you use this 230 software in a product, an acknowledgment in the product 231 documentation would be appreciated but is not required. 232 2333. Altered source versions must be plainly marked as such, and must 234 not be misrepresented as being the original software. 235 2364. The name of the author may not be used to endorse or promote 237 products derived from this software without specific prior written 238 permission. 239 240THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 241OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 242WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 243ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 244DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 245DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 246GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 247INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 248WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 249NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 250SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251 252Julian Seward, jseward@bzip.org 253bzip2/libbzip2 version 1.0.5 of 10 December 2007 254#endif 255 256$!end 257}; 258 259 260 261/** Command line options. 262*/ 263static const dk4_option_specification_t dk_sort_options[] = { 264 { dkT('R'), dkT("reset"), DK4_OPT_ARG_NONE }, 265 { dkT('i'), dkT("input-encoding"), DK4_OPT_ARG_STRING }, 266 { dkT('c'), dkT("case-insensitive"), DK4_OPT_ARG_NONE }, 267 { dkT('b'), dkT("ignore-leading-blanks"), DK4_OPT_ARG_NONE }, 268 { dkT('w'), dkT("normalize"), DK4_OPT_ARG_NONE }, 269 { dkT('t'), dkT("file-type"), DK4_OPT_ARG_NONE }, 270 { dkT('s'), dkT("skip-words"), DK4_OPT_ARG_SIZE }, 271 { dkT('n'), dkT("number"), DK4_OPT_ARG_NONE }, 272 { dkT('u'), dkT("unsigned"), DK4_OPT_ARG_NONE }, 273 { dkT('x'), dkT("hex"), DK4_OPT_ARG_NONE }, 274 { dkT('f'), dkT("float"), DK4_OPT_ARG_NONE }, 275 { dkT('v'), dkT("value-lines-first"), DK4_OPT_ARG_NONE }, 276 { dkT('m'), dkT("merge-equal-lines"), DK4_OPT_ARG_NONE }, 277 { dkT('r'), dkT("reverse"), DK4_OPT_ARG_NONE }, 278 { dkT('l'), dkT("line-size"), DK4_OPT_ARG_SIZE }, 279 { dkT('e'), dkT("suppress-empty-lines"), DK4_OPT_ARG_NONE } 280}; 281 282 283 284/** Number of elements in the dk_sort_options array. 285*/ 286static const size_t dk_sort_sz_options = 287sizeof(dk_sort_options)/sizeof(dk4_option_specification_t); 288 289 290 291/** Constant text strings used by the module, not localized. 292*/ 293static const dkChar * const dk_sort_kwnl[] = { 294$!string-table macro=dkT 295# 296# 0 Program group name 297# 298dktools 299# 300# 1 Help text file name 301# 302dk-sort.txt 303# 304# 2 String table file name 305# 306dk-sort.str 307# 308# 3 File name when processing standard input. 309# 310stdin 311# 312# 4 File open mode to read a file 313# 314rb 315# 316# 5 Backslash for file name expansion 317# 318\\ 319# 320# 6 Preference name for line size 321# 322line.size 323$!end 324}; 325 326 327 328/** Text strings used by program, localized versions used if found. 329*/ 330static const dkChar * const dk_sort_kw_def[] = { 331$!string-table macro=dkT 332# 333# 0 Error message: Failed to set up signal handlers! 334# 335Failed to set up signal handlers! 336# 337# 1 Error message: Failed to restore previous signal handlers! 338# 339Failed to restore previous signal handlers! 340# 341# 2 3 4 Error messages for encoding/decoding/processing errors 342# 343Encoding error! 344Decoding error! 345Processing error! 346# 347# 5 6 7 8 9 10 Error messages with detailed position 348# 349Encoding error!\n\tByte: 350Decoding error!\n\tByte: 351Processing error!\n\tByte: 352,\n\tCharacter: 353,\n\tPosition in line: 354. 355# 356# 11 Options -u, -x, -f mutually exclusive! 357# 358Options -u, -x, and -f are mutually exclusive! 359# 360# 12 13 Error: Illegal input encoding! 361# 362Illegal input encoding: " 363"! 364# 365# 14 Error: Failed to initialize text stream processing! 366# 367Failed to initialize text stream processing! 368$!end 369}; 370 371 372 373/** Default buffer to use if sizes up to 1024 are specified. 374*/ 375static dkChar input_line_buffer[1024]; 376 377 378 379/** Input buffer really to use. 380*/ 381static dkChar *ibptr = input_line_buffer; 382 383 384 385/** Allocated input buffer address for line sizes larger than 1024. 386*/ 387static dkChar *allocated_buffer = NULL; 388 389 390 391/** Localized message texts. 392*/ 393static const dkChar * const *dk_sort_msg = dk_sort_kw_def; 394 395 396 397/** Application structure. 398*/ 399static dk4_app_t *app = NULL; 400 401 402 403/** Line storage. 404*/ 405static dk4_sto_t *lsto = NULL; 406 407 408 409/** Iterator to traverse line storage. 410*/ 411static dk4_sto_it_t *lsti = NULL; 412 413 414 415/** Number of strings in dk_sort_msg array. 416*/ 417static size_t dk_sort_sz_msg = 418sizeof(dk_sort_kw_def)/sizeof(DK4_PCDKCHAR) - 1; 419 420 421/** Size of ibptr buffer. 422*/ 423static size_t ibsz = DK4_SIZEOF(input_line_buffer,dkChar); 424 425 426 427/** Number of words to skip when processing file names. 428*/ 429static size_t skip_words = 0; 430 431 432 433/** Flag: Case-insensitive comparison. 434*/ 435static int case_insensitive = 0; 436 437 438 439/** How to handle blanks: 440 0 leave as is, 441 1 remove leading and trailing blanks, 442 2 normalize lines. 443*/ 444static int handle_blanks = 0; 445 446 447 448/** How to handle leading values: 449 0 do not use numeric values, 450 1 use signed integers 451 2 use unsigned integers 452 3 use unsigned integers, specified in hexadecimal notation 453 4 use floating point numbers. 454*/ 455static int handle_values = 0; 456 457 458 459/** Flag: Sort files type file type suffix. 460*/ 461static int handle_file_type = 0; 462 463 464 465/** Flag: Show lines containing values before lines not containing 466 a value. Default is to show lines without a value first. 467*/ 468static int value_first = 0; 469 470 471 472/** Flag: Merge equal lines. 473*/ 474static int merge = 0; 475 476 477 478/** Flag: Reverse search order. 479*/ 480static int reversed = 0; 481 482 483 484/** Flag: Suppress empty lines. 485*/ 486static int suppress_empty = 0; 487 488 489/** Expected input encoding. 490*/ 491static int input_encoding = 492#if DK4_ON_WINDOWS 493 DK4_FILE_ENCODING_WIN1252 494#else 495 DK4_FILE_ENCODING_PLAIN 496#endif 497; 498 499 500 501/** Flag: Already reported decoding errors. 502*/ 503static int dk_sort_had_decoding_errors = 0; 504 505 506 507/** Flag: Already reported encoding errors. 508*/ 509static int dk_sort_had_encoding_errors = 0; 510 511 512 513/** Flag: Already reported processing errors. 514*/ 515static int dk_sort_had_proc_errors = 0; 516 517 518 519/** Exit status code returned by the main function. 520*/ 521static int exval = EXIT_FAILURE; 522 523 524 525#ifdef SIGPIPE 526/** Indicator: SIGPIPE signal received. 527*/ 528static 529DK4_VOLATILE 530dk4_sig_atomic_t sig_had_pipe = 0; 531#endif 532 533/** Indicator: SIGINT signal received. 534*/ 535static 536DK4_VOLATILE 537dk4_sig_atomic_t sig_had_int = 0; 538 539/** Indicator: SIGTERM signal received. 540*/ 541static 542DK4_VOLATILE 543dk4_sig_atomic_t sig_had_term = 0; 544 545 546 547/** Pass a volatile pointer to an atomic integer. 548 This function is necessary as some compilers mis-optimize 549 direct access to volatile variables (at least if you believe 550 one of the coding standards). 551 @param ptr Address of atomic integer variable. 552 @return The unmodified pointer. 553*/ 554static 555DK4_VOLATILE 556dk4_sig_atomic_t * 557sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) 558{ 559 return ptr; 560} 561 562 563 564#ifdef SIGPIPE 565/** Handler for SIGPIPE signal. 566 @param signo Signal number (always SIGPIPE, ignored). 567*/ 568static 569void 570sig_handler_pipe(int DK4_ARG_UNUSED(signo)) 571{ 572 DK4_UNUSED_ARG(signo) 573 *sig_pass_pointer(&sig_had_pipe) = 1; 574} 575#endif 576 577/** Handler for SIGINT signal. 578 @param signo Signal number (always SIGINT, ignored). 579*/ 580static 581void 582sig_handler_int(int DK4_ARG_UNUSED(signo) ) 583{ 584 DK4_UNUSED_ARG(signo) 585 *sig_pass_pointer(&sig_had_int) = 1; 586} 587 588/** Handler for SIGTERM signal. 589 @param signo Signal number (always SIGTERM, ignored). 590*/ 591static 592void 593sig_handler_term(int DK4_ARG_UNUSED(signo) ) 594{ 595 DK4_UNUSED_ARG(signo) 596 *sig_pass_pointer(&sig_had_term) = 1; 597} 598 599/** Read value from volatile atomic type. 600 This function is necessary as some compilers mis-optimize 601 direct access to volatile variables (at least if you believe 602 one of the coding standards). 603 @param ap Pointer to volatile atomic variable. 604 @return Contents of the variable. 605*/ 606static 607dk4_sig_atomic_t 608sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) 609{ 610 return (*ap); 611} 612 613/** Check whether we can continue or if a signal was received. 614 @param check_pipe Flag: Check for occured SIGPIPE signal too. 615 @return 1 if the program can continue, 0 if a signal was received. 616*/ 617static 618int 619sig_can_continue( 620#ifdef SIGPIPE 621 int check_pipe 622#else 623 int DK4_ARG_UNUSED(check_pipe) 624#endif 625) 626{ 627 int back = 1; 628#ifndef SIGPIPE 629 DK4_UNUSED_ARG(check_pipe) 630#else 631 if (0 != check_pipe) { 632 if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } 633 } 634#endif 635 if (0 != sig_read_atomic(&sig_had_int )) { back = 0; } 636 if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } 637 return back; 638} 639 640 641 642/** Check whether we can continue. 643 @return 1 for yes, 0 for no. 644*/ 645static 646int 647dk_sort_can_continue(void) 648{ 649 int back = 1; 650 if (0 == sig_can_continue(1)) { 651 back = 0; 652 } 653 return back; 654} 655 656 657 658/** Delete a storage node. 659 @param ptr Node to delete. 660*/ 661static 662void 663dk_sort_delete_node(dk_sort_line_t *ptr) 664{ 665 $? "+ dk_sort_delete_node" 666 if (NULL != ptr) { 667 dk4mem_release(ptr->line); 668 dk4mem_free(ptr); 669 } 670 $? "- dk_sort_delete_node" 671} 672 673 674 675/** Create storage node for a text line. 676 @param line Text line to store. 677 @return Pointer to new node on success, NULL on error. 678*/ 679static 680dk_sort_line_t * 681dk_sort_new_node(dkChar *line) 682{ 683 dk_sort_line_t *back = NULL; 684 dkChar *lines = NULL; /* Start of line */ 685 const dkChar *endptr = NULL; /* First text after value */ 686 double d; /* Evaluation double */ 687 dk4_um_t u; /* Evaluation unsigned */ 688 dk4_im_t i; /* Evaluation integer */ 689 $? "+ dk_sort_new_node" 690 /* Normalize or remove leading and trailing whitespace if required. 691 */ 692 if (NULL != line) { 693 dk4str_delnl(line); 694 if (0 < handle_blanks) { 695 lines = dk4str_start(line, NULL); 696 if (NULL != lines) { 697 line = lines; 698 switch (handle_blanks) { 699 case 1: { 700 dk4str_rtwh(line, NULL); 701 } break; 702 case 2: { 703 dk4str_normalize(line, NULL); 704 } break; 705 } 706 } else { 707 *line = dkT('\0'); 708 } 709 } 710 } 711 if ((0 != suppress_empty) && (NULL != line)) { 712 lines = dk4str_start(line, NULL); 713 if (NULL == lines) { 714 line = NULL; 715 } 716 } 717 718 /* Create node. 719 */ 720 if (NULL != line) { 721 back = dk4mem_new_app(dk_sort_line_t,1,app); 722 if (NULL != back) { 723 back->fts = NULL; 724 back->h = 0x00; 725 back->line = dk4str_dup_app(line, app); 726 if (NULL != back->line) { 727 if (0 != handle_file_type) { 728 back->fts = dk4path_get_suffix(back->line, NULL); 729 } 730 } else { 731 dk_sort_delete_node(back); 732 back = NULL; 733 exval = EXIT_FAILURE; 734 /* ERROR: Memory, already reported */ 735 } 736 } else { 737 exval = EXIT_FAILURE; 738 /* ERROR: Memory, already reported */ 739 } 740 } 741 742 /* Evaluate node if necessary. 743 */ 744 if (NULL != back) { 745 switch (handle_values) { 746 case 4: { 747 d = 0.0; 748 if (0 != dk4ma_input_dk_double(&d, line, &endptr, 2, NULL)) { 749 (back->value).d = d; 750 back->h = 0x01; 751 } 752 } break; 753 case 3: { 754 u = (dk4_um_t)0UL; 755 if (0 != dk4ma_input_dk_hex_dk4_um_t(&u, line, &endptr, 2, NULL)) { 756 (back->value).u = u; 757 back->h = 0x01; 758 } 759 } break; 760 case 2: { 761 u = (dk4_um_t)0UL; 762 if (0 != dk4ma_input_dk_dec_dk4_um_t(&u, line, &endptr, 2, NULL)) { 763 (back->value).u = u; 764 back->h = 0x01; 765 } 766 } break; 767 case 1: { 768 i = (dk4_im_t)0L; 769 if (0 != dk4ma_input_dk_dec_dk4_im_t(&i, line, &endptr, 2, NULL)) { 770 (back->value).i = i; 771 back->h = 0x01; 772 } 773 } break; 774 } 775 } 776 $? "- dk_sort_new_node PTR=%d", TR_IPTR(back) 777 return back; 778} 779 780 781 782static 783int 784dk_sort_is_dot_file(const dkChar *fn) 785{ 786 const dkChar *fns = NULL; 787 const dkChar *ptr = NULL; 788 int back = 0; 789 $? "+ dk_sort_is_dot_file \"%s\"", fn 790 ptr = fn; 791 while (dkT('\0') != *ptr) { 792#if DK4_HAVE_BACKSLASH_AS_SEP 793 if (dkT('\\') == *ptr) { fns = ptr; } 794#else 795 if (dkT('/') == *ptr) { fns = ptr; } 796#endif 797 ptr++; 798 } 799 if (NULL == fns) { fns = fn; } 800 else { fns++; } 801 $? ". fns = \"%s\"", fns 802 if (dkT('.') == *fns) { 803 back = 1; 804 } 805#if DK4_ON_WINDOWS 806 if (dkT('_') == *fns) { 807 back = 1; 808 } 809#endif 810 $? "- dk_sort_is_dot_file %d", back 811 return back; 812} 813 814 815 816/** Compare two storage nodes. 817 @param l Left node. 818 @param r Right node. 819 @param cr Comparison criteria, ignored here. 820 @return Comparison result. 821*/ 822static 823int 824dk_sort_compare_nodes(const void *l, const void *r, int DK4_ARG_UNUSED(cr) ) 825{ 826 int back = 0; 827 dk_sort_line_t *pl; 828 dk_sort_line_t *pr; 829 const dkChar *fnleft; 830 const dkChar *fnright; 831 $? "+ dk_sort_compare_nodes" 832 DK4_UNUSED_ARG(cr) 833 if (NULL != l) { 834 if (NULL != r) { 835 pl = (dk_sort_line_t *)l; 836 pr = (dk_sort_line_t *)r; 837 838 /* Check file type suffix if required. 839 */ 840 if (0 != handle_file_type) { 841 fnleft = dk4str_skip(pl->line, skip_words); 842 fnright = dk4str_skip(pr->line, skip_words); 843 if (NULL != fnleft) { $? ". fnleft = \"%s\"", fnleft 844 if (NULL != fnright) { $? ". fnright = \"%s\"", fnright 845 if (0 != dk4file_is_directory(fnleft, NULL)) { 846 if (0 == dk4file_is_directory(fnright, NULL)) { 847 back = -1; 848 } 849 } else { 850 if (0 != dk4file_is_directory(fnright, NULL)) { 851 back = 1; 852 } 853 } 854 if (0 == back) { 855 if (0 != dk_sort_is_dot_file(fnleft)) { 856 if (0 == dk_sort_is_dot_file(fnright)) { 857 back = -1; 858 } 859 } else { 860 if (0 != dk_sort_is_dot_file(fnright)) { 861 back = 1; 862 } 863 } 864 } 865 } else { 866 back = 1; 867 } 868 } else { 869 if (NULL != fnright) { 870 back = -1; 871 } 872 } 873 if (0 == back) { 874 if (NULL != pl->fts) { 875 if (NULL != pr->fts) { 876 back = dk4str_pathcmp(pl->fts, pr->fts); 877#if DK4_HAVE_CASE_INSENSITIVE_PATHNAMES 878 if (0 == back) { 879 back = dk4str_cmp(pl->fts, pr->fts); 880 } 881#endif 882 } else { 883 back = 1; 884 } 885 } else { 886 if (NULL != pr->fts) { 887 back = -1; 888 } 889 } 890 } 891 } 892 893 /* Check evaluation if required. 894 */ 895 if (0 == back) { 896 if (0 != handle_values) { 897 if (0x00 != pl->h) { 898 if (0x00 != pr->h) { /* both values */ 899 switch (handle_values) { 900 case 4: { 901 if ((pl->value).d < (pr->value).d) { 902 back = -1; 903 } else { 904 if ((pl->value).d > (pr->value).d) { 905 back = 1; 906 } 907 } 908 } break; 909 case 2: case 3: { 910 if ((pl->value).u < (pr->value).u) { 911 back = -1; 912 } else { 913 if ((pl->value).u > (pr->value).u) { 914 back = 1; 915 } 916 } 917 } break; 918 case 1: { 919 if ((pl->value).i < (pr->value).i) { 920 back = -1; 921 } else { 922 if ((pl->value).i > (pr->value).i) { 923 back = 1; 924 } 925 } 926 } break; 927 } 928 } else { /* only left value */ 929 back = ((0 != value_first) ? -1 : 1); 930 } 931 } else { 932 if (0x00 != pr->h) { /* only right value */ 933 back = ((0 != value_first) ? 1 : -1); 934 } 935 } 936 } 937 } 938 939 /* String comparison 940 */ 941 if (0 == back) { 942 if (0 != case_insensitive) { 943 back = dk4str_casecmp(pl->line, pr->line); 944 if (0 == back) { 945 back = dk4str_cmp(pl->line, pr->line); 946 } 947 } else { 948 back = dk4str_cmp(pl->line, pr->line); 949 } 950 } 951 952 /* Reverse order if necessary. 953 */ 954 if (0 != reversed) { back = -1 * back; } 955 } else { 956 back = 1; 957 } 958 } else { 959 if (NULL != r) { 960 back = -1; 961 } 962 } $? "- dk_sort_compare_nodes %d", back 963 return back; 964} 965 966 967 968static 969int 970dk_sort_line_handler( 971 void * DK4_ARG_UNUSED(obj), 972 dkChar *line, 973 dk4_um_t DK4_ARG_UNUSED(lineno), 974 dk4_er_t * DK4_ARG_UNUSED(erp) 975) 976{ 977 dk_sort_line_t *nptr; 978 int back = DK4_TSP_RES_OK; 979 $? "+ dk_sort_line_handler" 980 DK4_UNUSED_ARG(obj) 981 DK4_UNUSED_ARG(lineno) 982 DK4_UNUSED_ARG(erp) 983 nptr = dk_sort_new_node(line); 984 if (NULL != nptr) { 985 if (0 == dk4sto_add(lsto, nptr, NULL)) { 986 dk_sort_delete_node(nptr); 987 dk4app_log_base1(app, DK4_LL_ERROR, 90); 988 back = DK4_TSP_RES_FATAL; 989 exval = EXIT_FAILURE; 990 } 991 } $? "- dk_sort_line_handler %d", back 992 return back; 993} 994 995 996 997/** Report an error with position. 998 @param i1 Index of first message part in array. 999 @param i2 Index of alternative first message part. 1000 @param bno Current byte number. 1001 @param lno Current line number. 1002 @param cno Current character number. 1003 @param cil Current character number within line. 1004 @param fn File name processed. 1005*/ 1006static 1007void 1008dk_sort_report_with_position( 1009 size_t i1, 1010 size_t i2, 1011 dk4_um_t bno, 1012 dk4_um_t lno, 1013 dk4_um_t cno, 1014 dk4_um_t cil, 1015 const dkChar *fn 1016) 1017{ 1018 dkChar b1[8*(1+sizeof(dk4_um_t))+16]; 1019 dkChar b2[8*(1+sizeof(dk4_um_t))+16]; 1020 dkChar b3[8*(1+sizeof(dk4_um_t))+16]; 1021 const dkChar *oldlogname = NULL; 1022 dk4_um_t oldlogline = (dk4_um_t)0UL; 1023 int allbuffersok = 0; 1024 1025 oldlogname = dk4app_get_log_source_file(app); 1026 oldlogline = dk4app_get_log_source_line(app); 1027 dk4app_set_log_source_file(app, fn); 1028 dk4app_set_log_source_line(app, lno); 1029 if (0 != dk4ma_write_decimal_unsigned(b3,DK4_SIZEOF(b3,dkChar),cil,0,NULL)) { 1030 if (0 != dk4ma_write_decimal_unsigned(b2,DK4_SIZEOF(b2,dkChar),cno,0,NULL)) { 1031 if (0 != dk4ma_write_decimal_unsigned(b1,DK4_SIZEOF(b1,dkChar),bno,0,NULL)) { 1032 allbuffersok = 1; 1033 } 1034 } 1035 } 1036 if (0 != allbuffersok) { 1037 dk4app_log_7( 1038 app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, i1, 8, 9, 10, b1, b2, b3 1039 ); 1040 } else { 1041 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, i2); 1042 } 1043 dk4app_set_log_source_line(app, oldlogline); 1044 dk4app_set_log_source_file(app, oldlogname); 1045} 1046 1047 1048 1049/** Report errors from line processing. 1050 @param er_en Error report for encoding/decoding errors. 1051 @param en_pr Error report for processing errors. 1052 @param fn File name for error message. 1053*/ 1054static 1055void 1056dk_sort_report_errors( 1057 dk4_er_t *er_en, 1058 dk4_er_t *er_pr, 1059 const dkChar *fn 1060) 1061{ 1062 $? "+ dk_sort_report_errors" 1063 if (NULL != er_en) { 1064 switch (er_en->ec) { 1065 case DK4_E_DECODING_FAILED : { 1066 switch (dk_sort_had_decoding_errors) { 1067 case 0: case 1: case 2: { 1068 dk_sort_report_with_position( 1069 6, 3, 1070 er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, 1071 er_en->dt.fpos.charno, er_en->dt.fpos.charinline, 1072 fn 1073 ); 1074 } break; 1075 } 1076 if (3 > dk_sort_had_decoding_errors) { dk_sort_had_decoding_errors++; } 1077 } break; 1078 case DK4_E_ENCODING_FAILED : { 1079 switch (dk_sort_had_encoding_errors) { 1080 case 0: case 1: case 2: { 1081 dk_sort_report_with_position( 1082 5, 2, 1083 er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, 1084 er_en->dt.fpos.charno, er_en->dt.fpos.charinline, 1085 fn 1086 ); 1087 } break; 1088 } 1089 if (3 > dk_sort_had_encoding_errors) { dk_sort_had_encoding_errors++; } 1090 } break; 1091 } 1092 } 1093 if (NULL != er_pr) { 1094 if (DK4_E_NONE != er_pr->ec) { 1095 switch (dk_sort_had_proc_errors) { 1096 case 0: case 1: case 2: { 1097 dk_sort_report_with_position( 1098 7, 4, 1099 er_pr->dt.fpos.byteno, er_pr->dt.fpos.lineno, 1100 er_pr->dt.fpos.charno, er_pr->dt.fpos.charinline, 1101 fn 1102 ); 1103 } break; 1104 } 1105 if (3 > dk_sort_had_proc_errors) { dk_sort_had_proc_errors++; } 1106 } 1107 } 1108 $? "- dk_sort_report_errors" 1109} 1110 1111 1112 1113/** Process one input file opened in binary mode. 1114 @param fipo File to process. 1115 @param filename File name. 1116*/ 1117static 1118void 1119dk_sort_process_file(FILE *fipo, const dkChar *filename) 1120{ 1121 dk4_tspdk_t tsp; 1122 dk4_er_t er_en; 1123 dk4_er_t er_pr; 1124 dk4_er_t er; 1125 int res; 1126 int cc; 1127 int c; 1128 unsigned char ub; 1129 $? "+ dk_sort_process_file" 1130 dk4error_init(&er_en); 1131 dk4error_init(&er_pr); 1132 dk4error_init(&er); 1133 res = dk4tspdk_setup_line( 1134 &tsp, NULL, 1135 dk_sort_line_handler, 1136 ibptr, ibsz, 1137 dk4app_get_encoding(app), input_encoding, 1138 &er 1139 ); 1140 if (0 != res) { 1141 cc = 1; 1142 do { 1143 if (dk_sort_can_continue()) { 1144 c = fgetc(fipo); 1145 if (EOF != c) { 1146 ub = (unsigned char)c; 1147 switch (dk4tspdk_add_one_byte(&tsp, ub)) { 1148 case DK4_TSP_RES_FATAL : { 1149 cc = -1; 1150 exval = EXIT_FAILURE; 1151 dk4tspdk_get_errors(&er_en, &er_pr, &tsp); 1152 dk_sort_report_errors(&er_en, &er_pr, filename); 1153 } break; 1154 case DK4_TSP_RES_ERROR : { 1155 exval = EXIT_FAILURE; 1156 dk4tspdk_get_errors(&er_en, &er_pr, &tsp); 1157 dk_sort_report_errors(&er_en, &er_pr, filename); 1158 } break; 1159 } 1160 } else { 1161 cc = 0; 1162 } 1163 } else { 1164 cc = -1; 1165 } 1166 } while (1 == cc); 1167 if (0 == cc) { 1168 switch (dk4tspdk_finish(&tsp)) { 1169 case DK4_TSP_RES_FATAL : { 1170 exval = EXIT_FAILURE; 1171 dk4tspdk_get_errors(&er_en, &er_pr, &tsp); 1172 dk_sort_report_errors(&er_en, &er_pr, filename); 1173 } break; 1174 case DK4_TSP_RES_ERROR : { 1175 exval = EXIT_FAILURE; 1176 dk4tspdk_get_errors(&er_en, &er_pr, &tsp); 1177 dk_sort_report_errors(&er_en, &er_pr, filename); 1178 } break; 1179 } 1180 } 1181 } else { 1182 /* ERROR: Failed to initialize text stream processor */ 1183 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 14); 1184 exval = EXIT_FAILURE; 1185 } 1186 $? "- dk_sort_process_file" 1187} 1188 1189 1190 1191/** Process standard input. 1192*/ 1193static 1194void 1195dk_sort_process_stdin(void) 1196{ 1197#if DK4_ON_WINDOWS 1198 int oldmode; 1199#endif 1200 $? "+ dk_sort_process_stdin" 1201#if DK4_ON_WINDOWS 1202 oldmode = _setmode(_fileno(stdin), _O_BINARY); 1203#endif 1204 dk_sort_process_file(stdin, dk_sort_kwnl[3]); 1205#if DK4_ON_WINDOWS 1206 _setmode(_fileno(stdin), oldmode); 1207#endif 1208 $? "- dk_sort_process_stdin" 1209} 1210 1211 1212 1213static 1214void 1215dk_sort_process_one_file_name(const dkChar *fn) 1216{ 1217 FILE *fipo; 1218 int tests = DK4_FOPEN_SC_IS_REGULAR; 1219 $? "+ dk_sort_process_one_file_name" 1220 fipo = dk4fopen_app(fn, dk_sort_kwnl[4], tests, app); 1221 if (NULL != fipo) { 1222 dk_sort_process_file(fipo, fn); 1223 fclose(fipo); 1224 } else { 1225 /* ERROR: Failed to open file, already reported */ 1226 exval = EXIT_FAILURE; 1227 } 1228 $? "- dk_sort_process_one_file_name" 1229} 1230 1231 1232 1233#if DK4_ON_WINDOWS 1234static 1235void 1236dk_sort_expand_one_file_name(const dkChar *pattern) 1237{ 1238 dkChar buf[DK4_MAX_PATH]; 1239 dk4_dir_t *fne; 1240 const dkChar *shf; /* Short file name */ 1241 const dkChar *pth; /* Path */ 1242 int any_file_found = 0; /* Flag: Any file found */ 1243 int can_continue; 1244 $? "+ dk_sort_expand_one_file_name" 1245 fne = dk4app_fne_open(pattern, app); 1246 if (NULL != fne) { 1247 can_continue = 1; 1248 while ((0 != can_continue) && (NULL != (shf = dk4dir_next_file(fne)))) { 1249 any_file_found = 1; 1250 pth = dk4dir_get_path(fne); 1251 if (NULL != pth) { 1252 if (0 != dk4str_cpy_s(buf, DK4_SIZEOF(buf,dkChar), pth, NULL)) { 1253 if(0 != dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),dk_sort_kwnl[5],NULL)) 1254 { 1255 if(0 != dk4str_cat_s(buf, DK4_SIZEOF(buf,dkChar), shf, NULL)) { 1256 dk_sort_process_one_file_name(buf); 1257 } else { 1258 exval = EXIT_FAILURE; 1259 /* ERROR: Path too long */ 1260 dk4app_log_base3(app, DK4_LL_ERROR, 100, 105, pattern); 1261 } 1262 } 1263 else 1264 { 1265 exval = EXIT_FAILURE; 1266 /* ERROR: Path too long */ 1267 dk4app_log_base3(app, DK4_LL_ERROR, 100, 105, pattern); 1268 } 1269 } else { 1270 exval = EXIT_FAILURE; 1271 /* ERROR: Path too long! */ 1272 dk4app_log_base3(app, DK4_LL_ERROR, 100, 105, pattern); 1273 } 1274 } else { 1275 dk_sort_process_one_file_name(shf); 1276 } 1277 can_continue = dk_sort_can_continue(); 1278 if (EXIT_FAILURE == exval) { can_continue = 0; } 1279 } 1280 dk4dir_close(fne); 1281 if (0 == any_file_found) { 1282 /* ERROR: No such file */ 1283 dk4app_log_base3(app, DK4_LL_ERROR, 100, 107, pattern); 1284 exval = EXIT_FAILURE; 1285 } 1286 } else { 1287 /* ERROR: Failed to open file name expander (already reported) */ 1288 exval = EXIT_FAILURE; 1289 } 1290 $? "- dk_sort_expand_one_file_name" 1291} 1292#endif 1293 1294 1295 1296/** Process either the files specified on the command line 1297 or standard input otherwise. 1298*/ 1299static 1300void 1301dk_sort_process_files(void) 1302{ 1303 const dkChar *fn; /* Current file to process */ 1304 int xargc; /* Number of command line arguments */ 1305 int i; /* Current file index */ 1306 $? "+ dk_sort_process_files" 1307 xargc = dk4app_get_argc(app); 1308 if (0 < xargc) { 1309 for ( 1310 i = 0; 1311 ((i < xargc) && (0 != dk_sort_can_continue()) && (EXIT_SUCCESS == exval)); 1312 i++ 1313 ) 1314 { 1315 fn = dk4app_get_argv(app, i); 1316 if (NULL != fn) { 1317#if DK4_ON_WINDOWS 1318 if (0 != dk4path_must_expand(fn)) { 1319 dk_sort_expand_one_file_name(fn); 1320 } else { 1321#endif 1322 dk_sort_process_one_file_name(fn); 1323#if DK4_ON_WINDOWS 1324 } 1325#endif 1326 } 1327 } 1328 } else { 1329 dk_sort_process_stdin(); 1330 } 1331 $? "- dk_sort_process_files" 1332} 1333 1334 1335 1336/** Write stored text lines to standard output. 1337*/ 1338static 1339void 1340dk_sort_write_output(void) 1341{ 1342 dk_sort_line_t *nptr; 1343 const dkChar *prevtext; 1344 int printthis; 1345 $? "+ dk_sort_write_output" 1346 if ((0 != dk_sort_can_continue()) && (EXIT_SUCCESS == exval)) { 1347 dk4sto_it_reset(lsti); 1348 prevtext = NULL; 1349 do { 1350 if ((0 != dk_sort_can_continue()) && (EXIT_SUCCESS == exval)) { 1351 nptr = (dk_sort_line_t *)dk4sto_it_next(lsti); 1352 if (NULL != nptr) { 1353 printthis = 1; 1354 if (0 != merge) { 1355 if (NULL != prevtext) { 1356 if (0 == dk4str_cmp(prevtext, nptr->line)) { 1357 printthis = 0; 1358 } 1359 } 1360 prevtext = nptr->line; 1361 } 1362 if (0 != printthis) { 1363 if (0 == dk4fputs(nptr->line, stdout, NULL)) { 1364 exval = EXIT_FAILURE; 1365 nptr = NULL; 1366 } 1367 if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { 1368 exval = EXIT_FAILURE; 1369 nptr = NULL; 1370 } 1371 } 1372 } 1373 } else { 1374 nptr = NULL; 1375 } 1376 } while (NULL != nptr); 1377 } 1378 $? "- dk_sort_write_output" 1379} 1380 1381 1382 1383/** Run after setting signal handlers. 1384*/ 1385static 1386void 1387dk_sort_normal_run(void) 1388{ 1389 dkChar buf[32]; /* Input encoding name */ 1390 dk4_er_t er; /* Error report */ 1391 dk_sort_line_t *nopt; /* Current node */ 1392 size_t myll = 1024; /* Line length */ 1393 size_t nskip = 0; 1394 int options_error = 0; /* Flag: Error in options */ 1395 int res = 0; /* Operations result */ 1396 $? "+ dk_sort_normal_run" 1397 /* Process command line options 1398 */ 1399 if (0 != dk4app_opt_is_set_short(app, dkT('c'), NULL)) { 1400 case_insensitive = 1; 1401 } 1402 if (0 != dk4app_opt_is_set_short(app, dkT('b'), NULL)) { 1403 handle_blanks = 1; 1404 } 1405 if (0 != dk4app_opt_is_set_short(app, dkT('w'), NULL)) { 1406 handle_blanks = 2; 1407 } 1408 if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { 1409 handle_file_type = 1; 1410 } 1411 if (0 != dk4app_opt_is_set_short(app, dkT('s'), NULL)) { 1412 if (0 != dk4app_opt_get_size_short(&nskip, app, dkT('s'), NULL)) { 1413 skip_words = nskip; 1414 } 1415 } 1416 if (0 != dk4app_opt_is_set_short(app, dkT('n'), NULL)) { 1417 handle_values = 1; 1418 } 1419 if (0 != dk4app_opt_is_set_short(app, dkT('u'), NULL)) { 1420 handle_values = 2; 1421 } 1422 if (0 != dk4app_opt_is_set_short(app, dkT('x'), NULL)) { 1423 handle_values = 3; 1424 } 1425 if (0 != dk4app_opt_is_set_short(app, dkT('f'), NULL)) { 1426 if ((2 != handle_values) && (3 != handle_values)) { 1427 handle_values = 4; 1428 } else { 1429 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 11); 1430 options_error = 1; 1431 } 1432 } 1433 if (0 != dk4app_opt_is_set_short(app, dkT('v'), NULL)) { 1434 value_first = 1; 1435 } 1436 if (0 != dk4app_opt_is_set_short(app, dkT('m'), NULL)) { 1437 merge = 1; 1438 } 1439 if (0 != dk4app_opt_is_set_short(app, dkT('r'), NULL)) { 1440 reversed = 1; 1441 } 1442 if (0 != dk4app_opt_is_set_short(app, dkT('e'), NULL)) { 1443 suppress_empty = 1; 1444 } 1445 if (0 < dk4app_get_argc(app)) { 1446 input_encoding = dk4app_get_file_in_encoding(app); 1447 } else { 1448 input_encoding = dk4app_get_stdin_encoding(app); 1449 } 1450 if (0 != dk4app_opt_is_set_short(app, dkT('i'), NULL)) { 1451 res = dk4app_opt_get_string_short( 1452 buf, DK4_SIZEOF(buf,dkChar), app, dkT('i'), NULL 1453 ); 1454 if (0 != res) { 1455 res = dk4enc_find(&input_encoding, NULL, buf, NULL); 1456 if (0 == res) { 1457 dk4app_log_3(app,dk_sort_msg,dk_sort_sz_msg,DK4_LL_ERROR,12,13,buf); 1458 options_error = 1; 1459 } 1460 } 1461 } 1462 res = 0; 1463 if (0 != dk4app_opt_is_set_short(app, dkT('l'), NULL)) { 1464 res = dk4app_opt_get_size_short(&myll, app, dkT('l'), NULL); 1465 } 1466 if (0 == res) { 1467 if (0 == dk4app_opt_is_set_short(app, dkT('R'), NULL)) { 1468 res = dk4app_pref_get_size(&myll, app, dk_sort_kwnl[6], 0); 1469 } 1470 } 1471 if ((0 != res) && (DK4_SIZEOF(input_line_buffer,dkChar) < myll)) { 1472 allocated_buffer = dk4mem_new_app(dkChar,myll,app); 1473 if (NULL != allocated_buffer) { 1474 ibptr = allocated_buffer; 1475 ibsz = myll; 1476 } else { 1477 /* ERROR: Memory allocation failed, already reported */ 1478 options_error = 1; 1479 } 1480 } 1481 1482 /* Processing part. 1483 */ 1484 if (0 == options_error) { 1485 dk4error_init(&er); 1486 lsto = dk4sto_open(&er); 1487 if (NULL != lsto) { 1488 dk4sto_set_comp(lsto, dk_sort_compare_nodes, 0); 1489 lsti = dk4sto_it_open(lsto, &er); 1490 if (NULL != lsti) { 1491 exval = EXIT_SUCCESS; 1492 dk_sort_process_files(); 1493 dk_sort_write_output(); 1494 dk4sto_it_reset(lsti); 1495 do { 1496 nopt = (dk_sort_line_t *)dk4sto_it_next(lsti); 1497 if (NULL != nopt) { 1498 dk_sort_delete_node(nopt); 1499 } 1500 } while (NULL != nopt); 1501 dk4sto_it_close(lsti); 1502 } else { 1503 dk4app_log_base1(app, DK4_LL_ERROR, 90); 1504 } 1505 dk4sto_close(lsto); 1506 } else { 1507 dk4app_log_base1(app, DK4_LL_ERROR, 90); 1508 } 1509 } 1510 1511 /* Cleanup: release dynamically allocated memory for input line buffer. 1512 */ 1513 if (NULL != allocated_buffer) { 1514 dk4mem_free(allocated_buffer); allocated_buffer = NULL; ibsz = 1024; 1515 } 1516 $? "- dk_sort_normal_run" 1517} 1518 1519 1520 1521#if DK4_HAVE_SIGACTION 1522/** Set signal handlers and run. 1523*/ 1524static 1525void 1526dk_sort_run_with_signal_handlers(void) 1527{ 1528#ifdef SIGPIPE 1529 struct sigaction opipe; 1530#endif 1531 struct sigaction oint; 1532#ifdef SIGPIPE 1533 struct sigaction npipe; 1534#endif 1535 struct sigaction nint; 1536 struct sigaction oterm; 1537 struct sigaction nterm; 1538 int success = 0; 1539 $? "+ dk_sort_run_with_signal_handlers (sigaction)" 1540#ifdef SIGPIPE 1541 /* Set up signal handling for SIGPIPE. 1542 */ 1543 DK4_MEMRES(&npipe, sizeof(npipe)); 1544 npipe.sa_handler = sig_handler_pipe; 1545 npipe.sa_flags = 0; 1546 if (0 != sigemptyset(&npipe.sa_mask)) { 1547 /* ERROR: Failed to set up masked signal set for SIGPIPE */ 1548 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1549 goto finished; 1550 } 1551 if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { 1552 /* ERROR: Failed to set up masked signal set for SIGPIPE */ 1553 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1554 goto finished; 1555 } 1556 if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { 1557 /* ERROR: Failed to set up signal handler for SIGPIPE */ 1558 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1559 goto finished; 1560 } 1561#endif 1562 1563 /* Set up signal handling for SIGINT. 1564 */ 1565 DK4_MEMRES(&nint, sizeof(nint)); 1566 nint.sa_handler = sig_handler_int; 1567 nint.sa_flags = 0; 1568 if (0 != sigemptyset(&nint.sa_mask)) { 1569 /* ERROR: Failed to set up masked signal set for SIGINT */ 1570 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1571 goto restore_old_pipe; 1572 } 1573 if (0 != sigaddset(&nint.sa_mask, SIGINT)) { 1574 /* ERROR: Failed to set up masked signal set for SIGINT */ 1575 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1576 goto restore_old_pipe; 1577 } 1578 if (0 != sigaction(SIGINT, &nint, &oint)) { 1579 /* ERROR: Failed to set up signal handler for SIGINT */ 1580 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1581 goto restore_old_pipe; 1582 } 1583 1584 /* Set up signal handling for SIGTERM 1585 */ 1586 DK4_MEMRES(&nterm, sizeof(nterm)); 1587 nterm.sa_handler = sig_handler_term; 1588 nterm.sa_flags = 0; 1589 if (0 != sigemptyset(&nterm.sa_mask)) { 1590 /* ERROR: Failed to set up masked signal set for SIGTERM */ 1591 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1592 goto restore_old_int; 1593 } 1594 if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { 1595 /* ERROR: Failed to set up masked signal set for SIGTERM */ 1596 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1597 goto restore_old_int; 1598 } 1599 if (0 != sigaction(SIGTERM, &nterm, &oterm)) { 1600 /* ERROR: Failed to set up signal handler for SIGTERM */ 1601 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 0); 1602 goto restore_old_int; 1603 } 1604 1605 success = 1; 1606 dk_sort_normal_run(); 1607 1608 /* Restore signal handling for SIGTERM. 1609 */ 1610 if (0 != sigaction(SIGTERM, &oterm, NULL)) { 1611 /* ERROR: Failed to restore old SIGTERM settings */ 1612 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 1); 1613 success = 0; 1614 } 1615 1616 /* Restore signal handling for SIGINT. 1617 */ 1618 restore_old_int: 1619 if (0 != sigaction(SIGINT, &oint, NULL)) { 1620 /* ERROR: Failed to restore old SIGPIPE settings */ 1621 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 1); 1622 success = 0; 1623 } 1624 1625#ifdef SIGPIPE 1626 /* Restore signal handling for SIGPIPE. 1627 */ 1628 restore_old_pipe: 1629 if (0 != sigaction(SIGPIPE, &opipe, NULL)) { 1630 /* ERROR: Failed to restore old SIGPIPE settings */ 1631 dk4app_log_1(app, dk_sort_msg, dk_sort_sz_msg, DK4_LL_ERROR, 1); 1632 success = 0; 1633 } 1634#endif 1635 1636 /* Set exit status code if error occured. 1637 */ 1638 finished: 1639 if (0 == success) { exval = EXIT_FAILURE; } 1640 $? "- dk_sort_run_with_signal_handlers (sigaction)" 1641} 1642#else 1643#if DK4_HAVE_SIGSET 1644/** Set signal handlers and run. 1645*/ 1646static 1647void 1648dk_sort_run_with_signal_handlers(void) 1649{ 1650#ifdef SIGPIPE 1651 dk4_sig_handler_t *oldpipe = NULL; 1652#endif 1653 dk4_sig_handler_t *oldint = NULL; 1654 dk4_sig_handler_t *oldterm = NULL; 1655 $? "+ dk_sort_run_with_signal_handlers (sigset)" 1656#ifdef SIGPIPE 1657 oldpipe = sigset(SIGPIPE, sig_handler_pipe); 1658#endif 1659 oldint = sigset(SIGINT, sig_handler_int); 1660 oldterm = sigset(SIGTERM, sig_handler_term); 1661 dk_sort_normal_run(); 1662 sigset(SIGTERM, oldterm); 1663 sigset(SIGINT, oldint); 1664#ifdef SIGPIPE 1665 sigset(SIGPIPE, oldpipe); 1666#endif 1667 $? "- dk_sort_run_with_signal_handlers (sigset)" 1668} 1669#else 1670#if DK4_HAVE_SIGNAL 1671/** Set signal handlers and run. 1672*/ 1673static 1674void 1675dk_sort_run_with_signal_handlers(void) 1676{ 1677#ifdef SIGPIPE 1678 dk4_sig_handler_t *oldpipe = NULL; 1679#endif 1680 dk4_sig_handler_t *oldint = NULL; 1681 dk4_sig_handler_t *oldterm = NULL; 1682 $? "+ dk_sort_run_with_signal_handlers (signal)" 1683#ifdef SIGPIPE 1684 oldpipe = signal(SIGPIPE, sig_handler_pipe); 1685#endif 1686 oldint = signal(SIGINT, sig_handler_int); 1687 oldterm = signal(SIGTERM, sig_handler_term); 1688 dk_sort_normal_run(); 1689 signal(SIGTERM, oldterm); 1690 signal(SIGINT, oldint); 1691#ifdef SIGPIPE 1692 signal(SIGPIPE, oldpipe); 1693#endif 1694 $? "- dk_sort_run_with_signal_handlers (signal)" 1695} 1696#else 1697/** Set signal handlers and run. 1698*/ 1699static 1700void 1701dk_sort_run_with_signal_handlers(void) 1702{ 1703 dk_sort_normal_run(); 1704} 1705#endif 1706#endif 1707#endif 1708 1709 1710 1711/** Main function. 1712 @param argc Number of command line arguments. 1713 @param argv Command line arguments array. 1714 @return 0 on success, all other values indicate errors. 1715*/ 1716#if DK4_CHAR_SIZE > 1 1717int wmain(int argc, wchar_t *argv[]) 1718#else 1719int main(int argc, char *argv[]) 1720#endif 1721{ 1722 $!trace-init dk-sort.deb 1723 $? "+ main" 1724 dk4fput_initialize_stdout(); 1725 dk4fput_initialize_stderr(); 1726 app = dk4app_open_cmd( 1727 argc, argv, dk_sort_options, dk_sort_sz_options, 1728 dk_sort_kwnl[0], DKT_VERSION_DK, 1729 dk_sort_kwnl[1], dk_sort_help_text, dk_sort_license_text 1730 ); 1731 if (NULL != app) { 1732 dk_sort_sz_msg = dk4app_string_table_size(dk_sort_kw_def); 1733 dk_sort_msg = dk4app_string_table(app, dk_sort_kwnl[2], dk_sort_kw_def); 1734 if (0 != dk4app_can_run_normally(app)) { 1735 $? ". normal processing" 1736 dk_sort_run_with_signal_handlers(); 1737 } else { 1738 $? ". help/version/license" 1739 if (0 != dk4app_help_version_license(app)) { 1740 exval = EXIT_SUCCESS; 1741 } 1742 } 1743 dk4app_close(app); 1744 } else { 1745 } 1746 fflush(stdout); 1747 fflush(stderr); 1748 dk4fput_cleanup_stderr(); 1749 dk4fput_cleanup_stdout(); 1750 $? "- main %d", exval 1751 $!trace-end 1752 return exval; 1753} 1754 1755