%% options copyright owner = Dirk Krause copyright year = 2015-xxxx license = bsd %% module /** @file dk-th2.c The dk-t2l program. See dk_t2l_help_text for details. */ #include "dk4conf.h" #include #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 "dk4mem.h" #include "dk4enc.h" #include "dk4app.h" #include "dk4aopt.h" #include "dk4fopda.h" #include "dk4fput.h" #include "dk4vers.h" #include "dk4tsp32.h" #include "dk4uc2l.h" #include "dk4maidhdu.h" #include "dk4maidddu.h" #include "dk4maodh.h" #include "dk4maodd.h" #include "dk4mpl.h" #include "dk4strd.h" #include "dk4pathd.h" #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE == 2 #include "dk4utf16.h" #endif #else #include "dk4ansi.h" #include "dk4utf8.h" #endif $!trace-include /** Default help text, shown if no help text file is found. */ static const dkChar * const dk_t2l_help_text[] = { $!text macro=dkT,preprocessor dk-t2l - Text to LaTeX converter dk-t2l [] [] Options: -i --input-encoding= Expected input encoding. -e --echo Process command line arguments. -n --numeric Numeric values on command line. -h --hex Hexadecimal values on cmd line. -r --recommendations Write recommendations for packages and font encodings to use. -l --line-feed Write \\ sequence for newline. -t --tabulator Write LaTeX sequence for tabulators --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_t2l_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 8 bit character texts, not localized. */ static const char * const dk_t2l_kw8[] = { $!string-table # # 0 1 Open and close math mode. # \\( \\) # # 2 # \\\\ $!end }; /** Constant text keywords used by the program, not localized. */ static const dkChar * const dk_t2l_kwnl[] = { $!string-table macro=dkT # # 0 Program group name # dktools # # 1 Help text file name # dk-t2l.txt # # 2 String table file name # dk-t2l.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_t2l_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 input encoding name: "..."! # Illegal input encoding name: " "! # # 4 5 Temporarily unused. # Not a hexadecimal number: " "! # # 6 7 8 Error: No data found for character 0x...! # No data found for character 0x ! No data found for character! # # 9 Error: Overflow in line number count! # Overflow in line number count! # # 10 Error: Failed to setup character by character processing! # Failed to setup character by character processing! # # 11 Error: Probably incorrect output due to problems ... # Probably incorrect output due to problems with the data files! # # 12 .. 15 Error: Aborted by SIGINT signal! # Aborted by SIGINT signal! Aborted by SIGTERM signal! Received SIGPIPE signal! Write attempt to standard output failed. # # 16 ... 21 Error messages. # Decoding failed!\n\tByte: Encoding failed!\n\tByte: Processing failed!\n\tByte: ,\n\tCharacter: ,\n\tPosition in line: . # # 22 ... 27 Error messages. # Decoding failed! Encoding failed! Processing failed! Further decoding failures! Further encoding failures! Further processing failures! # # 28 29 Error: Out of range! # Out of range: " "! # # 30 31 Error: Not a decimal number! # Not a decimal number: " "! $!end }; /** Options for the program. */ static const dk4_option_specification_t dk_t2l_options[] = { /* Expected input encoding. */ { dkT('i'), dkT("input-encoding"), DK4_OPT_ARG_STRING }, /* Process command line arguments. */ { dkT('e'), dkT("echo"), DK4_OPT_ARG_NONE }, /* Command line arguments are decimal character numbers. */ { dkT('n'), dkT("numeric"), DK4_OPT_ARG_NONE }, /* Command line arguments are hexadecimal character numbers. */ { dkT('x'), dkT("hex"), DK4_OPT_ARG_NONE }, /* Write recommendations about font encodings and packages. */ { dkT('r'), dkT("recommendations"), DK4_OPT_ARG_NONE }, /* Convert tabulators. */ { dkT('t'), dkT("tabulator"), DK4_OPT_ARG_NONE }, /* Convert line feeds. */ { dkT('l'), dkT("line-feed"), DK4_OPT_ARG_NONE }, /* Verbose output. */ { dkT('\0'), dkT("verbose"), DK4_OPT_ARG_NONE } }; /** Pointer to localized or not localized texts. */ static const dkChar * const *dk_t2l_msg = dk_t2l_kw_def; /** Application structure. */ static dk4_app_t *app = NULL; /** Conversion data structure. */ static dk4_uc2l_t *uc2l = NULL; /** Current line number. */ static dk4_um_t dk_t2l_lineno = (dk4_um_t)1UL; /** Number of elements in the dk_t2l_options array. */ static const size_t dk_t2l_sz_options = sizeof(dk_t2l_options)/sizeof(dk4_option_specification_t); /** Number of elements in dk_t2l_msg array. */ static size_t dk_t2l_sz_msg = sizeof(dk_t2l_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_t2l_echo = 0; /** Command line arguments are numeric: 0 = text, 1 = decimal, 2 = hexadecimal. */ static int dk_t2l_numeric = 0; /** Input encoding expected when processing stdin. */ static int dk_t2l_i_std = DK4_FILE_ENCODING_ASCII; /** Input encoding expected when processing files. */ static int dk_t2l_i_file = DK4_FILE_ENCODING_ASCII; /** Number of decoding errors in current file. */ static int dk_t2l_dec_err = 0; /** Number of encoding errors in current file. */ static int dk_t2l_enc_err = 0; /** Number of processing errors in current file. */ static int dk_t2l_pro_err = 0; /** Flag: Previous character was carriage return. */ static int dk_t2l_last_cr = 0; /** Flag: Previous character was newline. */ static int dk_t2l_last_nl = 0; /** Flag: Have text in line, newline needed. */ static int dk_t2l_lhtx = 0; /** Flag: In math mode. */ static int dk_t2l_in_mm = 0; /** Flag: Find LaTeX sequence also for tabulators. */ static int dk_t2l_tabs = 0; /** Flag: Write sequence for line feeds. */ static int dk_t2l_linef = 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_t2l_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_t2l_process_options(void) { const dkChar *oaptr; int encval = 0; int bomval = 0; int back = 1; if (0 != dk4app_opt_is_set_long(app, dk_t2l_kwnl[6], NULL)) { verbose = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('t'), NULL)) { dk_t2l_tabs = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('l'), NULL)) { dk_t2l_linef = 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_t2l_i_std = dk_t2l_i_file = encval; } else { /* ERROR: Illegal encoding */ dk4app_log_3(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 2, 3, oaptr); back = 0; } } else { $? "! bug" /* ERROR: Failed to obtain option argument, bug! */ } } if (0 != dk4app_opt_is_set_short(app, dkT('e'), NULL)) { dk_t2l_echo = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('n'), NULL)) { dk_t2l_echo = 1; dk_t2l_numeric = 1; } if (0 != dk4app_opt_is_set_short(app, dkT('x'), NULL)) { dk_t2l_echo = 1; dk_t2l_numeric = 2; } uc2l = dk4uc2l_open_from_app(app); if (NULL == uc2l) { back = 0; } return back; } /** Start output page. */ static void dk_t2l_output_start_page(void) { /* Hook */ } /** Finish output page. */ static void dk_t2l_output_finish_page(void) { /* Hook */ } /** Start processing of one file. */ static void dk_t2l_output_start_file(void) { /* No errors in this file yet. */ dk_t2l_dec_err = 0; dk_t2l_enc_err = 0; dk_t2l_pro_err = 0; dk_t2l_last_cr = 0; dk_t2l_last_nl = 0; dk_t2l_lhtx = 0; dk_t2l_lineno = (dk4_um_t)1UL; dk4app_set_log_source_line(app, dk_t2l_lineno); } /** Finish processing of one file. */ static void dk_t2l_output_finish_file(void) { } static void dk_t2l_begin_math_mode(void) { if (0 == dk_t2l_in_mm) { dk_t2l_in_mm = 1; if (EOF == fputs(dk_t2l_kw8[0], stdout)) { output_error = 1; } } } static void dk_t2l_end_math_mode(void) { if (0 != dk_t2l_in_mm) { dk_t2l_in_mm = 0; if (EOF == fputs(dk_t2l_kw8[1], stdout)) { output_error = 1; } } } /** Handler function after processing CR/NL sequences. Here we do the real output. @param c Character to process. @param pos Current position in file or data stream, may be NULL. @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_t2l_c32_after_cr_nl_check( dk4_c32_t c, dk4_text_stream_position_t *pos, dk4_er_t *erp ) { dkChar buf[16*sizeof(dk4_um_t)]; const char *lseq; size_t szbuf; int back = DK4_TSP_RES_OK; if (dkC32(0x0A) == c) { /* Newline, finish line and write newline to output. */ dk_t2l_end_math_mode(); if (0 != dk_t2l_linef) { if (EOF == fputs(dk_t2l_kw8[2], stdout)) { output_error = 1; } } if (EOF == fputc('\n', stdout)) { output_error = 1; } } else { if (0 == dk_t2l_lhtx) { /* Start new line. */ } /* Write character to output. */ if ((dkC32(0x09) == c) && (0 == dk_t2l_tabs)) { dk_t2l_end_math_mode(); if (EOF == fputc(' ', stdout)) { output_error = 1; } } else { lseq = dk4uc2l_find(uc2l, c, 0, app); if (NULL != lseq) { dk_t2l_end_math_mode(); if (EOF == fputs(lseq, stdout)) { output_error = 1; } } else { lseq = dk4uc2l_find(uc2l, c, 1, app); if (NULL != lseq) { dk_t2l_begin_math_mode(); if (EOF == fputs(lseq, stdout)) { output_error = 1; } } else { /* ERROR, no encoding found */ szbuf = DK4_SIZEOF(buf,dkChar); if (0 != dk4ma_write_hex_unsigned(buf, szbuf, (dk4_um_t)c, 8, NULL)) { dk4app_log_3(app,dk_t2l_msg,dk_t2l_sz_msg,DK4_LL_ERROR,6,7,buf); } else { dk4app_log_1(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 8); } exval = EXIT_FAILURE; } } } } return back; } /** 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_t2l_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_t2l_c32_after_cr_nl_check(c, pos, erp); dk_t2l_lineno++; if ((dk4_um_t)0UL == dk_t2l_lineno) { /* ERROR: Overflow in line number counting */ dk4app_log_1(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 9); exval = EXIT_FAILURE; } dk4app_set_log_source_line(app, dk_t2l_lineno); dk_t2l_last_cr = 0; dk_t2l_last_nl = 1; dk_t2l_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_t2l_last_cr) { back = dk_t2l_c32_after_cr_nl_check(dkC32(0x0D), pos, erp); dk_t2l_lhtx = 1; dk_t2l_last_nl = 0; } else { dk_t2l_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_t2l_last_cr) { back = dk_t2l_c32_after_cr_nl_check(dkC32(0x0D), pos, erp); switch (dk_t2l_c32_after_cr_nl_check(c, pos, erp)) { 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_t2l_c32_after_cr_nl_check(c, pos, erp); } dk_t2l_lhtx = 1; dk_t2l_last_nl = 0; dk_t2l_last_cr = 0; } } return back; } /** 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_t2l_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_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, i1, 19, 20, 21, b1, b2, b3 ); } else { dk4app_log_1( app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, i2 ); } dk4app_set_log_source_line(app, oldlogline); } static void dk_t2l_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_t2l_dec_err) { case 0: case 1: { dk_t2l_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: { dk4app_log_1( app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 25 ); } break; } if (3 > dk_t2l_dec_err) { dk_t2l_dec_err++; } } break; case DK4_E_ENCODING_FAILED: { switch (dk_t2l_enc_err) { case 0: case 1: { dk_t2l_report_with_position( 17, 23, er_en->dt.fpos.byteno, er_en->dt.fpos.lineno, er_en->dt.fpos.charno, er_en->dt.fpos.charinline ); } break; case 2: { dk4app_log_1( app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 26 ); } break; } if (3 > dk_t2l_enc_err) { dk_t2l_enc_err++; } } break; } } if (NULL != er_pr) { if (DK4_E_NONE != er_pr->ec) { switch (dk_t2l_pro_err) { case 0: case 1: { dk_t2l_report_with_position( 18, 24, er_pr->dt.fpos.byteno, er_pr->dt.fpos.lineno, er_pr->dt.fpos.charno, er_pr->dt.fpos.charinline ); } break; case 2: { dk4app_log_1( app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 27 ); } break; } if (3 > dk_t2l_pro_err) { dk_t2l_pro_err++; } } } } static void dk_t2l_echo_hex(const dkChar *txt, int argno) { const dkChar *endptr = NULL; dk4_um_t um = (dk4_um_t)0UL; int res = 0; if (dkT('0') == txt[0]) { if ((dkT('x') == txt[1]) || (dkT('X') == txt[1])) { txt++; txt++; } } res = dk4ma_input_dk_hex_dk4_um_t( &um, txt, &endptr, 1, NULL ); if (0 != res) { if ((dk4_um_t)0xFFFFFFFFUL >= um) { (void)dk_t2l_c32_after_cr_nl_check((dk4_c32_t)um, NULL, NULL); } else { dk4app_log_3(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 28, 29, txt); } } else { /* ERROR: Not a hexadecimal number */ dk4app_log_3(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 4, 5, txt); } } static void dk_t2l_echo_numeric(const dkChar *txt, int argno) { const dkChar *endptr = NULL; dk4_um_t um = (dk4_um_t)0UL; int res = 0; int ishex = 0; if (dkT('0') == txt[0]) { if ((dkT('x') == txt[1]) || (dkT('X') == txt[1])) { ishex = 1; } } if (0 == ishex) { res = dk4ma_input_dk_dec_dk4_um_t( &um, txt, &endptr, 1, NULL ); if (0 != res) { if ((dk4_um_t)0xFFFFFFFFUL >= um) { (void)dk_t2l_c32_after_cr_nl_check((dk4_c32_t)um, NULL, NULL); } else { dk4app_log_3(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 28, 29, txt); } } else { /* ERROR: Not a decimal number */ dk4app_log_3(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 30, 31, txt); } } else { dk_t2l_echo_hex(&(txt[2]), argno); } } #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 /** Process one text word from command line, UNICODE character. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_c32(const dkChar *txt, int argno) { int isfirst = 1; while (dkC32(0) != *txt) { if ((1 == isfirst) && (0 != argno)) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } isfirst = 0; (void)dk_t2l_c32_after_cr_nl_check(*(txt++), NULL, NULL); } } #else /** Process one text word from command line, UTF-16 encoded. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_utf16(const dkChar *txt, int argno) { dk4_utf16_decoder_t dec; int cc = 1; int isfirst = 1; dk4utf16_init(&dec); while (1 == cc) { if (dkC16(0) != *txt) { switch (dk4utf16_add(&dec, *(txt++))) { case DK4_EDSTM_ERROR : { cc = -1; /* !!!!! ERROR: Decoding */ exval = EXIT_FAILURE; } break; case DK4_EDSTM_FINISHED : { if ((1 == isfirst) && (0 != argno)) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } isfirst = 0; (void)dk_t2l_c32_after_cr_nl_check(dk4utf16_get(&dec), NULL, NULL); } break; } } else { cc = 0; } } if (0 == cc) { if (0 == dk4utf16_is_empty(&dec)) { /* !!!!! ERROR: Decoding */ exval = EXIT_FAILURE; } } /* !!!!! TODO: Implementation */ } #endif #else /** Process one text word from command line, ASCII encoded. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_ascii(const dkChar *txt, int argno) { dk4_c32_t c32; int isfirst = 1; while ('\0' != *txt) { if ((1 == isfirst) && (0 != argno)) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } isfirst = 0; c32 = dkC32(0xFF) & ((dk4_c32_t)((unsigned char)(*(txt++)))); (void)dk_t2l_c32_after_cr_nl_check(c32, NULL, NULL); } } /** Process one text word from command line, UTF-8 encoded. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_utf8(const dkChar *txt, int argno) { dk4_utf8_decoder_t dec; int cc = 1; int isfirst = 1; dk4utf8_init(&dec); while (1 == cc) { if ('\0' != *txt) { switch (dk4utf8_add(&dec, *(txt++))) { case DK4_EDSTM_ERROR : { cc = -1; exval = EXIT_FAILURE; /* !!!!! ERROR: Decoding */ } break; case DK4_EDSTM_FINISHED : { if ((1 == isfirst) && (0 != argno)) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } isfirst = 0; (void)dk_t2l_c32_after_cr_nl_check(dk4utf8_get(&dec), NULL, NULL); } break; } } else { cc = 0; } } if (0 == cc) { if (0 == dk4utf8_is_empty(&dec)) { exval = EXIT_FAILURE; /* !!!!! ERROR: Decoding */ } } } /** Process one text word from command line, ANSI encoded. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_ansi(const dkChar *txt, int argno) { dk4_c32_t c32; int isfirst = 1; char c; while ('\0' != *txt) { c = *(txt++); if (0 != dk4ansi_decode(&c32, (unsigned char)c)) { if ((1 == isfirst) && (0 != argno)) { if (EOF == fputc(' ', stdout)) { output_error = 1; } } isfirst = 0; (void)dk_t2l_c32_after_cr_nl_check(c32, NULL, NULL); } else { /* !!!!! ERROR: Decoding */ exval = EXIT_FAILURE; } } } #endif /** Process one text word from command line. @param txt Text word. @param argno Number of current word. */ static void dk_t2l_echo_text(const dkChar *txt, int argno) { #if DK4_CHAR_SIZE > 1 #if DK4_CHAR_SIZE > 2 dk_t2l_echo_c32(txt, argno); #else dk_t2l_echo_utf16(txt, argno); #endif #else switch (dk4app_get_encoding(app)) { case DK4_ENCODING_UTF8 : { dk_t2l_echo_utf8(txt, argno); } break; case DK4_ENCODING_ANSI : { dk_t2l_echo_ansi(txt, argno); } break; default : { dk_t2l_echo_ascii(txt, argno); } break; } #endif dk_t2l_end_math_mode(); } /** Process command line arguments. */ static void dk_t2l_process_cmdline(void) { const dkChar *xargv; int argc; int i; /* !!!!! TODO: Implementation */ dk_t2l_output_start_file(); argc = dk4app_get_argc(app); if (0 < argc) { switch (dk_t2l_numeric) { case 2: { for (i = 0; i < argc; i++) { xargv = dk4app_get_argv(app, i); if (NULL != xargv) { dk_t2l_echo_hex(xargv, i); } } dk_t2l_end_math_mode(); } break; case 1: { for (i = 0; i < argc; i++) { xargv = dk4app_get_argv(app, i); if (NULL != xargv) { dk_t2l_echo_numeric(xargv, i); } } dk_t2l_end_math_mode(); } break; default: { for (i = 0; i < argc; i++) { xargv = dk4app_get_argv(app, i); if (NULL != xargv) { dk_t2l_echo_text(xargv, i); } } } break; } if (EOF == fputc('\n', stdout)) { output_error = 1; } } else { /* !!!!! ERROR: No command line arguments specified */ } dk_t2l_output_finish_file(); } /** Process an opened file with file name. @param fipo Opened file. @param fn File name. @param ienc_def Expected input encoding. */ static void dk_t2l_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; dk_t2l_in_mm = 0; 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_t2l_output_start_file(); dk4error_init(&er); res = dk4tsp32_setup_char( &tsp32, NULL, dk_t2l_c32_handler, ienc_def, &er ); if (0 != res) { cc = 1; while (1 == cc) { if (0 != dk_t2l_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_t2l_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_t2l_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_t2l_report_errors(&er_en, &er_pr); } break; } } if (0 != dk_t2l_can_continue()) { /* TODO: Finish current line */ if (0 != dk_t2l_in_mm) { dk_t2l_end_math_mode(); if (EOF == fputc('\n', stdout)) { output_error = 1; } } else { if (0 == dk_t2l_last_nl) { if (EOF == fputc('\n', stdout)) { output_error = 1; } } } } } else { /* ERROR: Setup failed, should not happen, bug */ dk4app_log_1(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 10); exval = EXIT_FAILURE; } dk_t2l_output_finish_file(); dk4app_set_log_source_file(app, oldsourcefile); dk4app_set_log_source_line(app, oldsourceline); } /** Process standard input. */ static void dk_t2l_process_stdin(void) { #if DK4_ON_WINDOWS int oldmode; oldmode = _setmode(_fileno(stdin), _O_BINARY); #endif dk_t2l_process_named_file(stdin, dk_t2l_kwnl[4], dk_t2l_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_t2l_process_one_file_name(const dkChar *infname) { FILE *fipo = NULL; int tests = DK4_FOPEN_SC_IS_REGULAR; fipo = dk4fopen_app(infname, dk_t2l_kwnl[3], tests, app); if (NULL != fipo) { dk_t2l_process_named_file(fipo, infname, dk_t2l_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_t2l_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_t2l_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_t2l_kwnl[5],NULL)) { if(0 != dk4str_cat_s(buf, DK4_SIZEOF(buf,dkChar), shf, NULL)) { dk_t2l_process_one_file_name(buf); } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); exval = EXIT_FAILURE; } } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); exval = EXIT_FAILURE; } } else { /* ERROR: Path too long */ dk4app_log_base3(app, DK4_LL_ERROR, 98, 99, pth); exval = EXIT_FAILURE; } } else { dk_t2l_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_t2l_process_filename(const dkChar *infname) { if (NULL != infname) { #if DK4_ON_WINDOWS if (0 != dk4path_must_expand(infname)) { if (0 == dk_t2l_expand_and_process(infname)) { exval = EXIT_FAILURE; /* ERROR: No such file */ dk4app_log_base3(app, DK4_LL_ERROR, 100, 107, infname); } } else { #endif dk_t2l_process_one_file_name(infname); #if DK4_ON_WINDOWS } #endif } } /** Run after installing the signal handlers. */ static void dk_t2l_normal_run(void) { int argc; int i; if (0 != dk_t2l_process_options()) { exval = EXIT_SUCCESS; dk_t2l_output_start_page(); if (0 != dk_t2l_echo) { dk_t2l_process_cmdline(); } else { argc = dk4app_get_argc(app); if (0 < argc) { for (i = 0; ((0 != dk_t2l_can_continue()) && (i < argc)); i++) { dk_t2l_process_filename(dk4app_get_argv(app, i)); } } else { dk_t2l_process_stdin(); } } dk_t2l_output_finish_page(); if (0 != dk4app_opt_is_set_short(app, dkT('r'), NULL)) { dk4uc2l_recommendations(uc2l, stdout); } if (0 != dk4uc2l_retrieve_errors(uc2l)) { $? "! ERROR" /* ERROR: Probably incorrect output due to problems */ dk4app_log_1(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 11); exval = EXIT_FAILURE; } } if (NULL != uc2l) { dk4uc2l_close(uc2l); uc2l = NULL; } } #if DK4_HAVE_SIGACTION /** Set signal handlers and run. */ static void dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 0); goto restore_old_int; } success = 1; dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_msg, dk_t2l_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_t2l_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_t2l_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_t2l_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_t2l_normal_run(); signal(SIGTERM, oldterm); signal(SIGINT, oldint); #ifdef SIGPIPE signal(SIGPIPE, oldpipe); #endif } #else /** Set signal handlers and run. */ static void dk_t2l_run_with_signal_handlers(void) { dk_t2l_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-t2l.deb $? "+ main" dk4fput_initialize_stderr(); app = dk4app_open_cmd( argc, argv, dk_t2l_options, dk_t2l_sz_options, dk_t2l_kwnl[0], DKT_VERSION_DK, dk_t2l_kwnl[1], dk_t2l_help_text, dk_t2l_license_text ); if (NULL != app) { dk_t2l_i_std = dk4app_get_stdin_encoding(app); dk_t2l_i_file = dk4app_get_file_in_encoding(app); dk_t2l_sz_msg = dk4app_string_table_size(dk_t2l_kw_def); dk_t2l_msg = dk4app_string_table(app, dk_t2l_kwnl[2], dk_t2l_kw_def); if (0 != dk4app_can_run_normally(app)) { dk_t2l_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_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 12); } if (0 != sig_read_atomic(&sig_had_term)) { exval = EXIT_FAILURE; /* ERROR: Interrupted by SIGTERM */ dk4app_log_1(app, dk_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 13); } #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_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 14); } } 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_t2l_msg, dk_t2l_sz_msg, DK4_LL_ERROR, 15); } 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; }