%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module /** @file dk-th2.c The dk-t2h program. See dk_t2h_help_text for details. */ #include "dk4conf.h" #if DK4_HAVE_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #if DK4_HAVE_STDLIB_H #ifndef STDLIB_H_INCLUDED #include #define STDLIB_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_H_INCLUDED 1 #endif #endif #include "dk4types.h" #include "dk4const.h" #include "dk4enc.h" #include "dk4mem.h" #include "dk4app.h" #include "dk4aopt.h" #include "dk4fopda.h" #include "dk4fput.h" #include "dk4vers.h" #include "dk4tsp32.h" #include "dk4maodd.h" #include "dk4mao8d.h" #include "dk4mao8h.h" #include "dk4utf8.h" #include "dk4utf16.h" #include "dk4ansi.h" #include "dk4mpl.h" #include "dk4strd.h" #include "dk4pathd.h" $!trace-include /** Default help text, shown if no help text file is found. */ static const dkChar * const dk_t2h_help_text[] = { $!text macro=dkT,preprocessor Text to HTML converter dk-t2h [] [] Options: -i --input-encoding= Expected input encoding. -l --code-lines Input lines are code lines. -e --echo Process command line arguments. -f --full Write full HTML file. -t --title= Title for full HTML file. --verbose Show error message on SIGPIPE. --help Show this short help text. --manual *** SHOW FULL MANUAL. *** --version Show version information. --license Show license information. http://dktools.sourceforge.net $!end }; /** License text. */ static const dkChar * const dk_t2h_license_text[] = { $!text macro=dkT,preprocessor This software uses code from the following projects, either directly or as a library: dktools Dirk Krause's tools and libraries. See http://dktools.sourceforge.net/ for more information. #if DK4_HAVE_ZLIB_H zlib Data compression library. See http://www.zlib.net/ for more information. #endif #if DK4_HAVE_BZLIB_H bzip2 Data compression program and library. See http://www.bzip.org/ for more information. #endif All the licenses below apply to the program. Licenses for used libraries are shown as found on my Scientific Linux 6.x computer in the /usr/share/doc directory on 2015-04-01. Check the project homepages of the used libraries for additional information and/or updated license terms. DK tools and libraries license ============================== Copyright (c) 2015-2016, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #if DK4_HAVE_ZLIB_H Zlib license ============ (C) 1995-2004 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu #endif #if DK4_HAVE_BZLIB_H Bzip2 and libbzip2 library license ================================== This program, "bzip2", the associated library "libbzip2", and all documentation, are copyright (C) 1996-2007 Julian R Seward. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 3. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 4. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Julian Seward, jseward@bzip.org bzip2/libbzip2 version 1.0.5 of 10 December 2007 #endif $!end }; /** Constant text keywords used by the program, not localized. */ static const dkChar * const dk_t2h_kwnl[] = { $!string-table macro=dkT # # 0 Program group name # dktools # # 1 Help text file name # dk-t2h.txt # # 2 String table file name # dk-t2h.str # # 3 File opening mode, read binary # rb # # 4 Pseudo file name for standard input # stdin # # 5 Path separator for Windows # \\ # # 6 Long option for verbose mode # verbose $!end }; /** Constant keywords used by the program, replaced by localized texts. */ static const dkChar * const dk_t2h_kw_def[] = { $!string-table macro=dkT # # 0 Error: Failed to set up signal handlers! # Failed to set up signal handlers! # # 1 Error: Failed to restore signal handlers! # Failed to restore signal handlers! # # 2 3 Error: Illegal encoding! # Illegal encoding: " "! # # 4 Error: Conversion from number to text failed, probably bug! # Conversion from number to text failed, probably bug! # # 5 Error: Failed to decode string from UTF-16! # Failed to decode string from UTF-16! # # 6 Error: Failed to decode string from ANSI! # Failed to decode string from ANSI! # # 7 Error: Failed to decode string from UTF-8! # Failed to decode string from UTF-8! # # 8 Error: Too many input lines, line number overflow! # Too many input lines, line number overflow! # # 9 Error: No command line arguments specified! # No command line arguments specified! # # 10 11 12 13 Errors. # Aborted by SIGINT signal! Aborted by SIGTERM signal! Aborted by SIGPIPE signal! Failed to write to standard output! # # 14 # Option -t ignored, only full pages can have a title! # # 15 ... 20 Error messages # Decoding failed!\n\tByte: Encoding failed!\n\tByte: Processing failed!\n\tByte: ,\n\tCharacter: ,\n\tPosition in line: . # # 21 ... 26 Error messages # Decoding failed! Encoding failed! Processing failed! Further decoding failures! Further encoding failures! Further processing failures! $!end }; /** Constant 8 bit text keywords used by the program, not localized. */ static const char * const dk_t2h_kw8[] = { $!string-table # # 0 ... 4 Start of page # \n \n \n \n \n # # 5 Title line # __TITLE__\n # # 6 ... 33 Remaining start of file # \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n # # 34 35 End of file # \n \n # # 36 37 Title line when title specified # \n # # 38 39 Start and end of paragraph #

\n

\n # # 40 41 Start and end of pre-formatted text #
\n
\n # # 42 43 44 Code environment # # # 45 46 Code for hexadecimal characters # &#x ; $!end }; /** Options for the program. */ static const dk4_option_specification_t dk_t2h_options[] = { { dkT('i'), dkT("input-encoding"), DK4_OPT_ARG_STRING }, { dkT('l'), dkT("code-lines"), DK4_OPT_ARG_NONE }, { dkT('e'), dkT("echo"), DK4_OPT_ARG_NONE }, { dkT('f'), dkT("full"), DK4_OPT_ARG_NONE }, { dkT('t'), dkT("title"), DK4_OPT_ARG_STRING }, { dkT('\0'), dkT("verbose"), DK4_OPT_ARG_STRING } }; /** Translation table for ASCII characters. */ static char const * const dk_t2h_translation_table[] = { /* 0 00 */ NULL, /* 1 01 */ NULL, /* 2 02 */ NULL, /* 3 03 */ NULL, /* 4 04 */ NULL, /* 5 05 */ NULL, /* 6 06 */ NULL, /* 7 07 */ NULL, /* 8 08 */ NULL, /* 9 09 */ "\t", /* 10 0a */ NULL, /* 11 0b */ NULL, /* 12 0c */ NULL, /* 13 0d */ NULL, /* 14 0e */ NULL, /* 15 0f */ NULL, /* 16 10 */ NULL, /* 17 11 */ NULL, /* 18 12 */ NULL, /* 19 13 */ NULL, /* 20 14 */ NULL, /* 21 15 */ NULL, /* 22 16 */ NULL, /* 23 17 */ NULL, /* 24 18 */ NULL, /* 25 19 */ NULL, /* 26 1a */ NULL, /* 27 1b */ NULL, /* 28 1c */ NULL, /* 29 1d */ NULL, /* 30 1e */ NULL, /* 31 1f */ NULL, /* 32 20 */ " ", /* 33 21 */ "!", /* 34 22 */ """, /* 35 23 */ "#", /* 36 24 */ "$", /* 37 25 */ "%", /* 38 26 */ "&", /* 39 27 */ "'", /* 40 28 */ "(", /* 41 29 */ ")", /* 42 2a */ "*", /* 43 2b */ "+", /* 44 2c */ ",", /* 45 2d */ "-", /* 46 2e */ ".", /* 47 2f */ "/", /* 48 30 */ "0", /* 49 31 */ "1", /* 50 32 */ "2", /* 51 33 */ "3", /* 52 34 */ "4", /* 53 35 */ "5", /* 54 36 */ "6", /* 55 37 */ "7", /* 56 38 */ "8", /* 57 39 */ "9", /* 58 3a */ ":", /* 59 3b */ ";", /* 60 3c */ "<", /* 61 3d */ "=", /* 62 3e */ ">", /* 63 3f */ "?", /* 64 40 */ "@", /* 65 41 */ "A", /* 66 42 */ "B", /* 67 43 */ "C", /* 68 44 */ "D", /* 69 45 */ "E", /* 70 46 */ "F", /* 71 47 */ "G", /* 72 48 */ "H", /* 73 49 */ "I", /* 74 4a */ "J", /* 75 4b */ "K", /* 76 4c */ "L", /* 77 4d */ "M", /* 78 4e */ "N", /* 79 4f */ "O", /* 80 50 */ "P", /* 81 51 */ "Q", /* 82 52 */ "R", /* 83 53 */ "S", /* 84 54 */ "T", /* 85 55 */ "U", /* 86 56 */ "V", /* 87 57 */ "W", /* 88 58 */ "X", /* 89 59 */ "Y", /* 90 5a */ "Z", /* 91 5b */ "[", /* 92 5c */ "\\", /* 93 5d */ "]", /* 94 5e */ "^", /* 95 5f */ "_", /* 96 60 */ "`", /* 97 61 */ "a", /* 98 62 */ "b", /* 99 63 */ "c", /* 100 64 */ "d", /* 101 65 */ "e", /* 102 66 */ "f", /* 103 67 */ "g", /* 104 68 */ "h", /* 105 69 */ "i", /* 106 6a */ "j", /* 107 6b */ "k", /* 108 6c */ "l", /* 109 6d */ "m", /* 110 6e */ "n", /* 111 6f */ "o", /* 112 70 */ "p", /* 113 71 */ "q", /* 114 72 */ "r", /* 115 73 */ "s", /* 116 74 */ "t", /* 117 75 */ "u", /* 118 76 */ "v", /* 119 77 */ "w", /* 120 78 */ "x", /* 121 79 */ "y", /* 122 7a */ "z", /* 123 7b */ "{", /* 124 7c */ "|", /* 125 7d */ "}", /* 126 7e */ "~", /* 127 7f */ NULL, /* 128 80 */ NULL, /* 129 81 */ NULL, /* 130 82 */ NULL, /* 131 83 */ NULL, /* 132 84 */ NULL, /* 133 85 */ NULL, /* 134 86 */ NULL, /* 135 87 */ NULL, /* 136 88 */ NULL, /* 137 89 */ NULL, /* 138 8a */ NULL, /* 139 8b */ NULL, /* 140 8c */ NULL, /* 141 8d */ NULL, /* 142 8e */ NULL, /* 143 8f */ NULL, /* 144 90 */ NULL, /* 145 91 */ NULL, /* 146 92 */ NULL, /* 147 93 */ NULL, /* 148 94 */ NULL, /* 149 95 */ NULL, /* 150 96 */ NULL, /* 151 97 */ NULL, /* 152 98 */ NULL, /* 153 99 */ NULL, /* 154 9a */ NULL, /* 155 9b */ NULL, /* 156 9c */ NULL, /* 157 9d */ NULL, /* 158 9e */ NULL, /* 159 9f */ NULL, /* 160 a0 */ " ", /* 161 a1 */ "¡", /* 162 a2 */ "¢", /* 163 a3 */ "£", /* 164 a4 */ "¤", /* 165 a5 */ "¥", /* 166 a6 */ "¦", /* 167 a7 */ "§", /* 168 a8 */ "¨", /* 169 a9 */ "©", /* 170 aa */ "ª", /* 171 ab */ "«", /* 172 ac */ "¬", /* 173 ad */ "­", /* 174 ae */ "®", /* 175 af */ "¯", /* 176 b0 */ "°", /* 177 b1 */ "±", /* 178 b2 */ "²", /* 179 b3 */ "³", /* 180 b4 */ "´", /* 181 b5 */ "µ", /* 182 b6 */ "¶", /* 183 b7 */ "·", /* 184 b8 */ "¸", /* 185 b9 */ "¹", /* 186 ba */ "º", /* 187 bb */ "»", /* 188 bc */ "¼", /* 189 bd */ "½", /* 190 be */ "¾", /* 191 bf */ "¿", /* 192 c0 */ "À", /* 193 c1 */ "Á", /* 194 c2 */ "Â", /* 195 c3 */ "Ã", /* 196 c4 */ "Ä", /* 197 c5 */ "Å", /* 198 c6 */ "Æ", /* 199 c7 */ "Ç", /* 200 c8 */ "È", /* 201 c9 */ "É", /* 202 ca */ "Ê", /* 203 cb */ "Ë", /* 204 cc */ "/Igrave;", /* 205 cd */ "Í", /* 206 ce */ "Î", /* 207 cf */ "Ï", /* 208 d0 */ "Ð", /* 209 d1 */ "Ñ", /* 210 d2 */ "Ò", /* 211 d3 */ "Ó", /* 212 d4 */ "Ô", /* 213 d5 */ "Õ", /* 214 d6 */ "Ö", /* 215 d7 */ "×", /* 216 d8 */ "Ø", /* 217 d9 */ "Ù", /* 218 da */ "Ú", /* 219 db */ "Û", /* 220 dc */ "Ü", /* 221 dd */ "Ý", /* 222 de */ "Þ", /* 223 df */ "ß", /* 224 e0 */ "à", /* 225 e1 */ "á", /* 226 e2 */ "â", /* 227 e3 */ "ã", /* 228 e4 */ "ä", /* 229 e5 */ "å", /* 230 e6 */ "æ", /* 231 e7 */ "ç", /* 232 e8 */ "è", /* 233 e9 */ "é", /* 234 ea */ "ê", /* 235 eb */ "ë", /* 236 ec */ "ì", /* 237 ed */ "í", /* 238 ee */ "î", /* 239 ef */ "ï", /* 240 f0 */ "ð", /* 241 f1 */ "ñ", /* 242 f2 */ "ò", /* 243 f3 */ "ó", /* 244 f4 */ "ô", /* 245 f5 */ "õ", /* 246 f6 */ "ö", /* 247 f7 */ "÷", /* 248 f8 */ "ø", /* 249 f9 */ "ù", /* 250 fa */ "ú", /* 251 fb */ "û", /* 252 fc */ "ü", /* 253 fd */ "ý", /* 254 fe */ "þ", /* 255 ff */ "ÿ" }; /** Pointer to localized or not localized texts. */ static const dkChar * const *dk_t2h_msg = dk_t2h_kw_def; /** Application structure. */ static dk4_app_t *app = NULL; /** Page title for full HTML page, if specified on command line. */ static const dkChar *dk_t2h_title = NULL; /** Current line number. */ static dk4_um_t dk_t2h_lineno = (dk4_um_t)1UL; /** Number of elements in the dk_t2h_options array. */ static const size_t dk_t2h_sz_options = sizeof(dk_t2h_options)/sizeof(dk4_option_specification_t); /** Number of elements in dk_t2h_msg array. */ static size_t dk_t2h_sz_msg = sizeof(dk_t2h_kw_def)/sizeof(DK4_PCDKCHAR) - 1; /** Program exit status. */ static int exval = EXIT_FAILURE; /** Flag: Error occured while writing to stdout. */ static int output_error = 0; /** Flag: Verbose output (report SIGPIPE). */ static int verbose = 0; /** Flag: Echo command line arguments instead of processing files. */ static int dk_t2h_echo = 0; /** Flag: Produce full HTML page, not just a fragment. */ static int dk_t2h_full = 0; /** Flag: Wrap all lines in code environments. */ static int dk_t2h_code = 0; /** Input encoding expected when processing stdin. */ static int dk_t2h_i_std = DK4_FILE_ENCODING_ASCII; /** Input encoding expected when processing files. */ static int dk_t2h_i_file = DK4_FILE_ENCODING_ASCII; /** Number of decoding errors in current file. */ static int dk_t2h_dec_err = 0; /** Number of encoding errors in current file. */ static int dk_t2h_enc_err = 0; /** Number of processing errors in current file. */ static int dk_t2h_pro_err = 0; /** Flag: Previous character was carriage return. */ static int dk_t2h_last_cr = 0; /** Flag: Previous character was newline. */ static int dk_t2h_last_nl = 0; /** Flag: Have text in line, newline needed. */ static int dk_t2h_lhtx = 0; #ifdef SIGPIPE /** Indicator: SIGPIPE signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_pipe = 0; #endif /** Indicator: SIGINT signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_int = 0; /** Indicator: SIGTERM signal received. */ static DK4_VOLATILE dk4_sig_atomic_t sig_had_term = 0; /** Pass a volatile pointer to an atomic integer. This function is necessary as some compilers mis-optimize direct access to volatile variables (at least if you believe one of the coding standards). @param ptr Address of atomic integer variable. @return The unmodified pointer. */ static DK4_VOLATILE dk4_sig_atomic_t * sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) { return ptr; } #ifdef SIGPIPE /** Handler for SIGPIPE signal. @param signo Signal number (always SIGPIPE, ignored). */ static void sig_handler_pipe(int signo) { *sig_pass_pointer(&sig_had_pipe) = 1; } #endif /** Handler for SIGINT signal. @param signo Signal number (always SIGINT, ignored). */ static void sig_handler_int(int signo) { *sig_pass_pointer(&sig_had_int) = 1; } /** Handler for SIGTERM signal. @param signo Signal number (always SIGTERM, ignored). */ static void sig_handler_term(int signo) { *sig_pass_pointer(&sig_had_term) = 1; } /** Read value from volatile atomic type. This function is necessary as some compilers mis-optimize direct access to volatile variables (at least if you believe one of the coding standards). @param ap Pointer to volatile atomic variable. @return Contents of the variable. */ static dk4_sig_atomic_t sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) { return (*ap); } /** Check whether we can continue or if a signal was received. @param check_pipe Flag: Check for occured SIGPIPE signal too. @return 1 if the program can continue, 0 if a signal was received. */ static int sig_can_continue(int check_pipe) { int back = 1; #ifdef SIGPIPE if (0 != check_pipe) { if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } } #endif if (0 != sig_read_atomic(&sig_had_int )) { back = 0; } if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } return back; } /** Check whether we can continue. @return 1 for yes, 0 for no. */ static int dk_t2h_can_continue(void) { int back = 1; if (0 == sig_can_continue(1)) { back = 0; } return back; } /** Process command line options. @return 1 on success, 0 on error. */ static int dk_t2h_process_options(void) { const dkChar *oaptr; int encval = 0; int bomval = 0; int back = 1; if (0 != dk4app_opt_is_set_long(app, dk_t2h_kwnl[6], NULL)) { verbose = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('i'), NULL)) { oaptr = dk4app_opt_get_string_ptr_short(app, dkT('i'), NULL); if (NULL != oaptr) { if (0 != dk4enc_find(&encval, &bomval, oaptr, NULL)) { dk_t2h_i_std = dk_t2h_i_file = encval; } else { /* ERROR: Illegal encoding */ back = 0; dk4app_log_3(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 2, 3, oaptr); } } else { $? "! bug" /* ERROR: Failed to obtain option argument, bug! */ } } if (0 != dk4app_opt_is_set_short(app, dkT('e'), NULL)) { dk_t2h_echo = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('l'), NULL)) { dk_t2h_code = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('f'), NULL)) { dk_t2h_full = 1; if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { dk_t2h_title = dk4app_opt_get_string_ptr_short(app, dkT('t'), NULL); } } else { if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { back = 0; /* ERROR: Title only for full pages */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 14); } } return back; } /** Handler function after processing CR/NL sequences. Here we do the real output. @param c Character to process. @return Result code: - DK4_TSP_RES_OK if the character was processed successfully, - DK4_TSP_RES_ERROR if there was an error but we can continue, - DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk_t2h_c32_after_cr_nl_check( dk4_c32_t c ) { char buf[16*sizeof(dk4_um_t)]; size_t i; int back = DK4_TSP_RES_OK; int res = 0; int done = 0; $? "+ dk_t2h_c32_after_cr_nl_check" if (dkC32(0x0A) == c) { $? ". newline" /* Newline, finish line and write newline to output. */ if (0 != dk_t2h_code) { $? ". code" if (0 == dk_t2h_lhtx) { if (EOF == fputs(dk_t2h_kw8[42], stdout)) { output_error = 1; } res = dk4ma_write_c8_decimal_unsigned( buf, sizeof(buf), dk_t2h_lineno, 0, NULL ); if (0 != res) { i = strlen(buf); while (3 > i++) { if (EOF == fputc('0', stdout)) { output_error = 1; } } if (EOF == fputs(buf, stdout)) { output_error = 1; } } if (EOF == fputs(dk_t2h_kw8[43], stdout)) { output_error = 1; } dk_t2h_lhtx = 1; } if (0 != dk_t2h_lhtx) { $? ". already text in line" if (EOF == fputs(dk_t2h_kw8[44], stdout)) { output_error = 1; } } else { $? ". no text in line yet" } } else { $? ". not code" } if (EOF == fputc('\n', stdout)) { output_error = 1; } } else { $? ". not newline" if (0 != dk_t2h_code) { $? ". code" if (0 == dk_t2h_lhtx) { $? ". no text in line yet" /* Start new line. */ if (EOF == fputs(dk_t2h_kw8[42], stdout)) { output_error = 1; } res = dk4ma_write_c8_decimal_unsigned( buf, sizeof(buf), dk_t2h_lineno, 0, NULL ); if (0 != res) { i = strlen(buf); while (3 > i++) { if (EOF == fputc('0', stdout)) { output_error = 1; } } if (EOF == fputs(buf, stdout)) { output_error = 1; } } if (EOF == fputs(dk_t2h_kw8[43], stdout)) { output_error = 1; } dk_t2h_lhtx = 1; } else { $? ". already text in line" } } else { $? ". not code" } /* Write character to output. */ if (dkC32(0x00000100) > c) { i = (size_t)c; i &= 0x0000FFU; if (NULL != dk_t2h_translation_table[i]) { if (EOF == fputs(dk_t2h_translation_table[i], stdout)) { output_error = 1; } done = 1; } } if (0 == done) { res = dk4ma_write_c8_hex_unsigned( buf, sizeof(buf), (dk4_um_t)c, 0, NULL ); if (0 != res) { i = strlen(buf); if (EOF == fputs(dk_t2h_kw8[45], stdout)) { output_error = 1; } if (0 != (i % 2)) { if (EOF == fputc('0', stdout)) { output_error = 1; } } if (EOF == fputs(buf, stdout)) { output_error = 1; } if (EOF == fputs(dk_t2h_kw8[46], stdout)) { output_error = 1; } } else { exval = EXIT_FAILURE; /* ERROR: Conversion */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 4); } } } $? "- dk_t2h_c32_after_cr_nl_check %d", back return back; } #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 /* +++++ 4 +++++ */ /** Write 32 bit character string. @param str String to write. */ static void dk_t2h_output_c32(const dk4_c32_t *str) { while (dkC32(0x00) != *str) { switch (dk_t2h_c32_after_cr_nl_check(*(str++))) { case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : { exval = EXIT_FAILURE; } break; } } } /* ----- 4 ----- */ #else /* +++++ 2 +++++ */ /** Write UTF-16 encoded text string. @param str String to write. */ static void dk_t2h_output_utf16(const dk4_c16_t *str) { dk4_utf16_decoder_t dec; int cc; dk4utf16_init(&dec); cc = 1; while (1 == cc) { if (dkC16(0) != *str) { switch (dk4utf16_add(&dec, *(str++))) { case DK4_EDSTM_ERROR : { cc = -1; /* ERROR: Decoding error */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 5); } break; case DK4_EDSTM_FINISHED : { switch (dk_t2h_c32_after_cr_nl_check(dk4utf16_get(&dec))) { case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : { exval = EXIT_FAILURE; } break; } } break; } } else { cc = 0; } } if (0 == cc) { if (0 == dk4utf16_is_empty(&dec)) { /* Decoding error */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 5); exval = EXIT_FAILURE; } } } /* ----- 2 ----- */ #endif #else /* +++++ 1 +++++ */ /** Write ASCII encoded text string. @param str String to write. */ static void dk_t2h_output_ascii(const char *str) { dk4_c32_t c32; while ('\0' != *str) { c32 = dkC32(0xFF) & ((dk4_c32_t)((unsigned char)(*(str++)))); switch (dk_t2h_c32_after_cr_nl_check(c32)) { case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : { exval = EXIT_FAILURE; } break; } } } /** Write ANSI encoded text string. @param str String to write. */ static void dk_t2h_output_ansi(const char *str) { dk4_c32_t c32; char c; while ('\0' != *str) { c = *(str++); if (0 != dk4ansi_decode(&c32, (unsigned char)c)) { switch (dk_t2h_c32_after_cr_nl_check(c32)) { case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : { exval = EXIT_FAILURE; } } } else { exval = EXIT_FAILURE; /* ERROR: Decoding error */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 6); } } } /** Write UTF-8 encoded string. @param str String to write. */ static void dk_t2h_output_utf8(const char *str) { dk4_utf8_decoder_t dec; int cc; cc = 1; dk4utf8_init(&dec); while (1 == cc) { if ('\0' != *str) { switch (dk4utf8_add(&dec, *(str++))) { case DK4_EDSTM_ERROR : { cc = -1; exval = EXIT_FAILURE; /* Decoding error */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 7); } break; case DK4_EDSTM_FINISHED : { switch (dk_t2h_c32_after_cr_nl_check(dk4utf8_get(&dec))) { case DK4_TSP_RES_ERROR : case DK4_TSP_RES_FATAL : { exval = EXIT_FAILURE; } } } break; } } else { cc = 0; } } if (0 == cc) { if (0 == dk4utf8_is_empty(&dec)) { exval = EXIT_FAILURE; /* ERROR: Decoding error */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 7); } } } /* ----- 1 ----- */ #endif static void dk_t2h_output_dkstring(const dkChar *str) { #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 dk_t2h_output_c32(str); #else dk_t2h_output_utf16(str); #endif #else switch (dk4app_get_encoding(app)) { case DK4_FILE_ENCODING_UTF8 : { dk_t2h_output_utf8(str); } break; case DK4_FILE_ENCODING_ANSI : { dk_t2h_output_ansi(str); } break; default : { dk_t2h_output_ascii(str); } break; } #endif } /** Start output page. */ static void dk_t2h_output_start_page(void) { size_t i; if (0 != dk_t2h_full) { if (NULL != dk_t2h_title) { for (i = 0; i < 5; i++) { if (EOF == fputs(dk_t2h_kw8[i], stdout)) { output_error = 1; } } if (EOF == fputs(dk_t2h_kw8[36], stdout)) { output_error = 1; } dk_t2h_output_dkstring(dk_t2h_title); if (EOF == fputs(dk_t2h_kw8[37], stdout)) { output_error = 1; } for (i = 6; i < 34; i++) { if (EOF == fputs(dk_t2h_kw8[i], stdout)) { output_error = 1; } } } else { for (i = 0; i < 34; i++) { if (EOF == fputs(dk_t2h_kw8[i], stdout)) { output_error = 1; } } } } } /** Finish output page. */ static void dk_t2h_output_finish_page(void) { size_t i; if (0 != dk_t2h_full) { for (i = 34; i < 36; i++) { if (EOF == fputs(dk_t2h_kw8[i], stdout)) { output_error = 1; } } } } /** Start processing of one file. */ static void dk_t2h_output_start_file(void) { $? "+ dk_t2h_output_start_file" /* No errors in this file yet. */ dk_t2h_dec_err = 0; dk_t2h_enc_err = 0; dk_t2h_pro_err = 0; dk_t2h_last_cr = 0; dk_t2h_last_nl = 0; dk_t2h_lhtx = 0; dk_t2h_lineno = (dk4_um_t)1UL; dk4app_set_log_source_line(app, dk_t2h_lineno); if (0 != dk_t2h_full) { $? ". full" if (0 != dk_t2h_code) { $? ". code" if (EOF == fputs(dk_t2h_kw8[40], stdout)) { output_error = 1; } } else { $? ". not code" if (EOF == fputs(dk_t2h_kw8[38], stdout)) { output_error = 1; } } } $? "- dk_t2h_output_start_file" } /** Finish processing of one file. */ static void dk_t2h_output_finish_file(void) { $? "+ dk_t2h_output_finish_file" if (0 != dk_t2h_full) { $? ". full" if (0 != dk_t2h_code) { $? ". code" if (EOF == fputs(dk_t2h_kw8[41], stdout)) { output_error = 1; } } else { $? ". not code" if (EOF == fputs(dk_t2h_kw8[39], stdout)) { output_error = 1; } } } $? "- dk_t2h_output_finish_file" } /** Handler function for single characters. @param obj Object to modify while processing the character. @param c Character to process. @param pos Current position in file or data stream. @param erp Error report, may be NULL. @return Result code: - DK4_TSP_RES_OK if the character was processed successfully, - DK4_TSP_RES_ERROR if there was an error but we can continue, - DK4_TSP_RES_FATAL if there was a fatal error so we should abort processing. */ static int dk_t2h_c32_handler( void *obj, dk4_c32_t c, dk4_text_stream_position_t *pos, dk4_er_t *erp ) { int back = DK4_TSP_RES_OK; if (dkC32(0x0A) == c) { /* For a newline clear CR and TXT flag, set NL flag. */ back = dk_t2h_c32_after_cr_nl_check(c); dk_t2h_lineno++; if ((dk4_um_t)0UL == dk_t2h_lineno) { /* ERROR: Overflow in line number counting */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 8); exval = EXIT_FAILURE; } dk4app_set_log_source_line(app, dk_t2h_lineno); dk_t2h_last_cr = 0; dk_t2h_last_nl = 1; dk_t2h_lhtx = 0; } else { if (dkC32(0x0D) == c) { /* For a cr if CR flag is set, pass the cr and set TXT flag, clear nl flag. Otherwise simply set CR flag. */ if (0 != dk_t2h_last_cr) { back = dk_t2h_c32_after_cr_nl_check(dkC32(0x0D)); dk_t2h_lhtx = 1; dk_t2h_last_nl = 0; } else { dk_t2h_last_cr = 1; } } else { /* For any other character: If the CR flag is set, pass cr and current character. Otherwise pass the current character. Reset NL and CR flag, set TXT flag. */ if (0 != dk_t2h_last_cr) { back = dk_t2h_c32_after_cr_nl_check(dkC32(0x0D)); switch (dk_t2h_c32_after_cr_nl_check(c)) { case DK4_TSP_RES_FATAL: { back = DK4_TSP_RES_FATAL; } break; case DK4_TSP_RES_ERROR: { if (DK4_TSP_RES_OK == back) { back = DK4_TSP_RES_ERROR; } } break; } } else { back = dk_t2h_c32_after_cr_nl_check(c); } dk_t2h_lhtx = 1; dk_t2h_last_nl = 0; dk_t2h_last_cr = 0; } } return back; } /** Process command line arguments. */ static void dk_t2h_process_cmdline(void) { const dkChar *xargv; int xargc; int i; xargc = dk4app_get_argc(app); if (0 < xargc) { dk_t2h_output_start_file(); for (i = 0; i < xargc; i++) { xargv = dk4app_get_argv(app, i); if (0 != i) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } if (NULL != xargv) { dk_t2h_output_dkstring(xargv); } } dk_t2h_c32_after_cr_nl_check(dkC32(0x0A)); dk_t2h_output_finish_file(); } else { exval = EXIT_FAILURE; /* ERROR: No command line arguments */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 9); } } /** Report an error with position in source line. @param i1 Index of first message part in array. @param i2 Index of alternative first message part. @param bno Byte processed. @param lno Current line number. @param cno Current character number. @param cil Current character number in line. */ static void dk_t2h_report_with_position( size_t i1, size_t i2, dk4_um_t bno, dk4_um_t lno, dk4_um_t cno, dk4_um_t cil ) { dkChar b1[8*(1+sizeof(dk4_um_t))]; dkChar b2[8*(1+sizeof(dk4_um_t))]; dkChar b3[8*(1+sizeof(dk4_um_t))]; dk4_um_t oldlogline = (dk4_um_t)0UL; int allbuffersok = 0; oldlogline = dk4app_get_log_source_line(app); dk4app_set_log_source_line(app, lno); if (0 != dk4ma_write_decimal_unsigned(b3,DK4_SIZEOF(b3,dkChar),cil,0,NULL)) { if (0 != dk4ma_write_decimal_unsigned(b2,DK4_SIZEOF(b2,dkChar),cno,0,NULL)) { if (0 != dk4ma_write_decimal_unsigned(b1,DK4_SIZEOF(b1,dkChar),bno,0,NULL)) { allbuffersok = 1; } } } if (0 != allbuffersok) { dk4app_log_7( app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, i1, 18, 19, 20, b1, b2, b3 ); } else { dk4app_log_1( app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, i2 ); } dk4app_set_log_source_line(app, oldlogline); } static void dk_t2h_report_errors(dk4_er_t *er_en, dk4_er_t *er_pr) { if (NULL != er_en) { switch (er_en->ec) { case DK4_E_DECODING_FAILED: { switch (dk_t2h_dec_err) { case 0: case 1: { /* ERROR: Decoding failed */ dk_t2h_report_with_position( 15, 21, er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, er_en->dt.fpos.charno, er_en->dt.fpos.charinline ); } break; case 2: { /* ERROR: Further decoding errors */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 24); } break; } if (3 > dk_t2h_dec_err) { dk_t2h_dec_err++; } } break; case DK4_E_ENCODING_FAILED: { switch (dk_t2h_enc_err) { case 0: case 1: { /* ERROR: Encoding failed */ dk_t2h_report_with_position( 16, 22, er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, er_en->dt.fpos.charno, er_en->dt.fpos.charinline ); } break; case 2: { /* ERROR: Further encoding erros */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 25); } break; } if (3 > dk_t2h_enc_err) { dk_t2h_enc_err++; } } break; } } if (NULL != er_pr) { if (DK4_E_NONE != er_pr->ec) { switch (dk_t2h_pro_err) { case 0: case 1: { /* ERROR: Processing error */ dk_t2h_report_with_position( 17, 23, er_pr->dt.fpos.byteno, er_pr->dt.fpos.lineno, er_pr->dt.fpos.charno, er_pr->dt.fpos.charinline ); } break; case 2: { /* ERROR: Further processing errors */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 26); } break; } if (3 > dk_t2h_pro_err) { dk_t2h_pro_err++; } } } } /** Process an opened file with file name. @param fipo Opened file. @param fn File name. @param ienc_def Expected input encoding. */ static void dk_t2h_process_named_file(FILE *fipo, const dkChar *fn, int ienc_def) { dk4_tsp32_t tsp32; dk4_er_t er; dk4_er_t er_en; dk4_er_t er_pr; const dkChar *oldsourcefile; dk4_um_t oldsourceline; int c; int cc; int res; unsigned char ub; oldsourcefile = dk4app_get_log_source_file(app); oldsourceline = dk4app_get_log_source_line(app); dk4app_set_log_source_file(app, fn); dk4app_set_log_source_line(app, (dk4_um_t)0UL); dk_t2h_output_start_file(); dk4error_init(&er); res = dk4tsp32_setup_char( &tsp32, NULL, dk_t2h_c32_handler, ienc_def, &er ); if (0 != res) { cc = 1; while (1 == cc) { if (0 != dk_t2h_can_continue()) { c = fgetc(fipo); if (EOF != c) { ub = (unsigned char)c; res = dk4tsp32_add_one_byte(&tsp32, ub); switch (res) { case DK4_TSP_RES_ERROR: { exval = EXIT_FAILURE; dk4tsp32_get_errors(&er_en, &er_pr, &tsp32); dk_t2h_report_errors(&er_en, &er_pr); } break; case DK4_TSP_RES_FATAL: { cc = -1; exval = EXIT_FAILURE; dk4tsp32_get_errors(&er_en, &er_pr, &tsp32); dk_t2h_report_errors(&er_en, &er_pr); } break; default: { } break; } } else { cc = 0; } if (0 != feof(fipo)) { if (1 == cc) { cc = 0; } } } else { cc = -1; } } if (0 == cc) { res = dk4tsp32_finish(&tsp32); switch (res) { case DK4_TSP_RES_ERROR: case DK4_TSP_RES_FATAL: { exval = EXIT_FAILURE; dk4tsp32_get_errors(&er_en, &er_pr, &tsp32); dk_t2h_report_errors(&er_en, &er_pr); } break; } } if (0 != dk_t2h_can_continue()) { if ((0 == dk_t2h_last_nl) && (0 != dk_t2h_lhtx)) { (void)dk_t2h_c32_after_cr_nl_check(dkC32(0x0A)); } } } else { exval = EXIT_FAILURE; /* ERROR: Setup failed, should not happen, bug */ } dk_t2h_output_finish_file(); dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } /** Process standard input. */ static void dk_t2h_process_stdin(void) { #if DK4_ON_WINDOWS int oldmode; oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif dk_t2h_process_named_file(stdin, dk_t2h_kwnl[4], dk_t2h_i_std); #if DK4_ON_WINDOWS _setmode(_fileno(stdin), oldmode); #endif } /** Process one real file name. @param infname File name to process. */ static void dk_t2h_process_one_file_name(const dkChar *infname) { FILE *fipo = NULL; int tests = DK4_FOPEN_SC_IS_REGULAR; fipo = dk4fopen_app(infname, dk_t2h_kwnl[3], tests, app); if (NULL != fipo) { dk_t2h_process_named_file(fipo, infname, dk_t2h_i_file); fclose(fipo); } else { exval = EXIT_FAILURE; } } #if DK4_ON_WINDOWS /** Expand file name pattern and process the files. @pattern File name pattern to expand. @return 1 if files were found, 0 otherwise. */ static int dk_t2h_expand_and_process(const dkChar *pattern) { dkChar buf[DK4_MAX_PATH]; dk4_dir_t *fne; const dkChar *shf; const dkChar *pth; int cc; int back = 0; fne = dk4app_fne_open(pattern, app); if (NULL != fne) { cc = 1; while (1 == cc) { if (0 != dk_t2h_can_continue()) { shf = dk4dir_next_file(fne); if (NULL != shf) { back = 1; pth = dk4dir_get_path(fne); if (NULL != pth) { if (0 != dk4str_cpy_s(buf, DK4_SIZEOF(buf,dkChar), pth, NULL)) { if(0!=dk4str_cat_s(buf,DK4_SIZEOF(buf,dkChar),dk_t2h_kwnl[5],NULL)) { if(0 != dk4str_cat_s(buf, DK4_SIZEOF(buf,dkChar), shf, NULL)) { dk_t2h_process_one_file_name(buf); } else { exval = EXIT_FAILURE; /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { exval = EXIT_FAILURE; /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { exval = EXIT_FAILURE; /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); } } else { dk_t2h_process_one_file_name(shf); } } else { cc = 0; } } else { cc = -1; } } dk4dir_close(fne); } else { exval = EXIT_FAILURE; } return back; } #endif /** Process one file name, check whether expansion is necessary. @param infname Input file name to process, may be NULL. */ static void dk_t2h_process_filename(const dkChar *infname) { if (NULL != infname) { #if DK4_ON_WINDOWS if (0 != dk4path_must_expand(infname)) { if (0 == dk_t2h_expand_and_process(infname)) { exval = EXIT_FAILURE; /* ERROR: No such file */ dk4app_log_base3(app, DK4_LL_ERROR, 100, 107, infname); } } else { #endif dk_t2h_process_one_file_name(infname); #if DK4_ON_WINDOWS } #endif } } /** Run after installing the signal handlers. */ static void dk_t2h_normal_run(void) { int argc; int i; if (0 != dk_t2h_process_options()) { exval = EXIT_SUCCESS; dk_t2h_output_start_page(); if (0 != dk_t2h_echo) { dk_t2h_process_cmdline(); } else { argc = dk4app_get_argc(app); if (0 < argc) { for (i = 0; ((0 != dk_t2h_can_continue()) && (i < argc)); i++) { dk_t2h_process_filename(dk4app_get_argv(app, i)); } } else { dk_t2h_process_stdin(); } } dk_t2h_output_finish_page(); } } #if DK4_HAVE_SIGACTION /** Set signal handlers and run. */ static void dk_t2h_run_with_signal_handlers(void) { #ifdef SIGPIPE struct sigaction opipe; #endif struct sigaction oint; #ifdef SIGPIPE struct sigaction npipe; #endif struct sigaction nint; struct sigaction oterm; struct sigaction nterm; int success = 0; #ifdef SIGPIPE /* Set up signal handling for SIGPIPE. */ DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { /* ERROR: Failed to set up masked signal set for SIGPIPE */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { /* ERROR: Failed to set up signal handler for SIGPIPE */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto finished; } #endif /* Set up signal handling for SIGINT. */ DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { /* ERROR: Failed to set up masked signal set for SIGINT */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } if (0 != sigaction(SIGINT, &nint, &oint)) { /* ERROR: Failed to set up signal handler for SIGINT */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_pipe; } /* Set up signal handling for SIGTERM */ DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { /* ERROR: Failed to set up masked signal set for SIGTERM */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { /* ERROR: Failed to set up signal handler for SIGTERM */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } success = 1; dk_t2h_normal_run(); /* Restore signal handling for SIGTERM. */ if (0 != sigaction(SIGTERM, &oterm, NULL)) { /* ERROR: Failed to restore old SIGTERM settings */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 1); success = 0; } /* Restore signal handling for SIGINT. */ restore_old_int: if (0 != sigaction(SIGINT, &oint, NULL)) { /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 1); success = 0; } #ifdef SIGPIPE /* Restore signal handling for SIGPIPE. */ restore_old_pipe: if (0 != sigaction(SIGPIPE, &opipe, NULL)) { /* ERROR: Failed to restore old SIGPIPE settings */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 1); success = 0; } #endif /* Set exit status code if error occured. */ finished: if (0 == success) { exval = EXIT_FAILURE; } } #else #if DK4_HAVE_SIGSET /** Set signal handlers and run. */ static void dk_t2h_run_with_signal_handlers(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; #ifdef SIGPIPE oldpipe = sigset(SIGPIPE, sig_handler_pipe); #endif oldint = sigset(SIGINT, sig_handler_int); oldterm = sigset(SIGTERM, sig_handler_term); dk_t2h_normal_run(); sigset(SIGTERM, oldterm); sigset(SIGINT, oldint); #ifdef SIGPIPE sigset(SIGPIPE, oldpipe); #endif } #else #if DK4_HAVE_SIGNAL /** Set signal handlers and run. */ static void dk_t2h_run_with_signal_handlers(void) { #ifdef SIGPIPE dk4_sig_handler_t *oldpipe = NULL; #endif dk4_sig_handler_t *oldint = NULL; dk4_sig_handler_t *oldterm = NULL; #ifdef SIGPIPE oldpipe = signal(SIGPIPE, sig_handler_pipe); #endif oldint = signal(SIGINT, sig_handler_int); oldterm = signal(SIGTERM, sig_handler_term); dk_t2h_normal_run(); signal(SIGTERM, oldterm); signal(SIGINT, oldint); #ifdef SIGPIPE signal(SIGPIPE, oldpipe); #endif } #else /** Set signal handlers and run. */ static void dk_t2h_run_with_signal_handlers(void) { dk_t2h_normal_run(); } #endif #endif #endif /** Main function. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, all other values indicate errors. */ #if DK4_CHAR_SIZE > 1 int wmain(int argc, wchar_t *argv[]) #else int main(int argc, char *argv[]) #endif { int shp; $!trace-init dk-t2h.deb $? "+ main" dk4fput_initialize_stderr(); app = dk4app_open_cmd( argc, argv, dk_t2h_options, dk_t2h_sz_options, dk_t2h_kwnl[0], DKT_VERSION_DK, dk_t2h_kwnl[1], dk_t2h_help_text, dk_t2h_license_text ); if (NULL != app) { dk_t2h_i_std = dk4app_get_stdin_encoding(app); dk_t2h_i_file = dk4app_get_file_in_encoding(app); dk_t2h_sz_msg = dk4app_string_table_size(dk_t2h_kw_def); dk_t2h_msg = dk4app_string_table(app, dk_t2h_kwnl[2], dk_t2h_kw_def); if (0 != dk4app_can_run_normally(app)) { dk_t2h_run_with_signal_handlers(); } else { dk4fput_initialize_stdout(); if (0 != dk4app_help_version_license(app)) { exval = EXIT_SUCCESS; } fflush(stdout); fflush(stderr); dk4fput_cleanup_stdout(); } if (0 != sig_read_atomic(&sig_had_int )) { exval = EXIT_FAILURE; /* ERROR: Interrupted by SIGINT */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 10); } if (0 != sig_read_atomic(&sig_had_term)) { exval = EXIT_FAILURE; /* ERROR: Interrupted by SIGTERM */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 11); } #ifdef SIGPIPE if (0 != sig_read_atomic(&sig_had_pipe)) { exval = EXIT_FAILURE; shp = 1; /* ERROR: Interrupted by SIGPIPE */ if (0 != verbose) { dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 12); } } else { shp = 0; } #else shp = 0; #endif if ((0 == shp) && (0 != output_error)) { exval = EXIT_FAILURE; /* ERROR: Output to stdout failed */ dk4app_log_1(app, dk_t2h_msg, dk_t2h_sz_msg, DK4_LL_ERROR, 13); } dk4app_close(app); } fflush(stdout); if (0 != sig_read_atomic(&sig_had_int )) { exval = EXIT_FAILURE; } if (0 != sig_read_atomic(&sig_had_term)) { exval = EXIT_FAILURE; } #ifdef SIGPIPE if (0 != sig_read_atomic(&sig_had_pipe)) { exval = EXIT_FAILURE; } #endif if (0 != output_error) { exval = EXIT_FAILURE; } fflush(stderr); dk4fput_cleanup_stderr(); $? "- main %d", exval $!trace-end exit(exval); return exval; }