/* Copyright (C) 2016-2020, Dirk Krause SPDX-License-Identifier: BSD-3-Clause */ /* WARNING: This file was generated by the dkct program (see http://dktools.sourceforge.net/ for details). Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: printqdc.ctr */ /** @file printqdc.c The printqdc module. */ #line 10 "printqdc.ctr" #include "dk4conf.h" #include "dk4types.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_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif /** Requirements to build this program: * Use 8 bit characters, so we can use the directories from dk4inst.c. * Signal handling mechanism. */ #if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) #if DK4_HAVE_MATH_H #ifndef MATH_H_INCLUDED #if DK4_ON_WINDOWS #ifndef _USE_MATH_DEFINES #define _USE_MATH_DEFINES 1 #endif #endif #include #define MATH_H_INCLUDED 1 #endif #endif #if DK4_HAVE_ERRNO_H #ifndef ERRNO_H_INCLUDED #include #define ERRNO_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_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_STRING_H #ifndef STRING_H_INCLUDED #include #define STRING_H_INCLUDED 1 #endif #endif #include "dk4inst.h" #include "dk4mpl.h" #include "dk4mem.h" #include "dk4mai8ddu.h" #include "dk4mai8dus.h" #include "dk4str8.h" #include "dk4lprng.h" #include "dk4opt.h" #include "dk4sock.h" #include "dk4vers.h" #include "dk4unused.h" #line 109 "printqdc.ctr" /** Information from one LPRng accounting line. */ typedef struct { char *username; char *queuename; char *jobtitle; char *pagecount; } lprng_info_t; /** Command line options for program. */ static dk4_option_t options[] = { { { dkT('i'), dkT("interactive"), DK4_OPT_ARG_NONE }, { NULL }, 0}, { { dkT('s'), dkT("socket"), DK4_OPT_ARG_STRING }, { NULL }, 0}, { { dkT('h'), dkT("host"), DK4_OPT_ARG_STRING }, { NULL }, 0}, { { dkT('p'), dkT("port"), DK4_OPT_ARG_UNSIGNED }, { NULL }, 0}, { { dkT('\0'),dkT("help"), DK4_OPT_ARG_NONE}, { NULL }, 0}, { { dkT('\0'),dkT("version"), DK4_OPT_ARG_NONE}, { NULL }, 0}, { { dkT('\0'),dkT("license"), DK4_OPT_ARG_NONE}, { NULL }, 0} }; /** Help text. */ static const char * const help_text[] = { "", "Print quota daemon client", "", "printqdc [-i] [-s path] | [-h host -p port]", "", "-i\t\t\tInteractive mode instead of default pipe mode.", "--interactive", "", "-s path\t\t\tPath name for local UNIX domain socket.", "--socket=path", "", "-h host\t\t\tHost name of remote host.", "--host=host", "", "-p port\t\t\tPort number at remote host.", "--port=port", "", "--help\t\t\tShow this help text.", "--version\t\tShow version number.", "--license\t\tShow license information.", "", NULL #line 164 "printqdc.ctr" }; /** License conditions text. */ static const char * const license_text[] = { "", "This software uses code from the following projects, either directly or as", "a library:", "", "dktools\t\tDirk Krause's tools and libraries.", "\t\tSee http://sourceforge.net/p/dktools/wiki/Home/", "\t\tfor more information.", "", "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:", "", "1. Redistributions of source code must retain the above copyright notice,", " this list of conditions and the following disclaimer.", "2. 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.", "3. Neither the name of the copyright holder nor the names of its", " 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 HOLDER 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.", "", NULL #line 211 "printqdc.ctr" }; /** Version information. */ static const char version_text[] = { DKT_VERSION_C8 }; /** Constant text keywords used by the module. */ static const char * const pqdc_kw[] = { /* 0 */ "\n", /* 1 */ " ", /* 2 */ "x@x+1", /* 3 */ "Print job", /* 4 */ "-> ", /* 5 */ "<- \"", /* 6 */ "\"\n", /* 7 */ "printqdc: ", /* 8 */ "ERROR: Port number too large!\n", /* 9 */ "ERROR: Port number required!\n", /* 10 */ "ERROR: Host name required!\n", /* 11 */ "ERROR: Failed to shut down socket!\n", /* 12 */ "ERROR: Failed to send data!\n", /* 13 */ "ERROR: Failed to open connection to accounting system!\n", /* 14 */ "ERROR: Failed to construct request (would be too long)!\n", /* 15 */ "ERROR: Incomplete information to construct request!\n", /* 16 */ "ERROR: Pagecounter not numeric!\n", /* 17 */ "ERROR: Too few arguments for request!\n", /* 18 */ "ERROR: Unknown command keyword!\n", /* 19 */ "ERROR: Missing arguments!\n", /* 20 */ "ERROR: Interrupted by signal!\n", /* 21 */ "ERROR: Failed to install signal handlers!\n", /* 22 */ "ERROR: Failed to restore signal handlers!\n", /* 23 */ "ERROR: Failed to initialize socket subsystem!\n", NULL #line 283 "printqdc.ctr" }; /** Default socket name. */ static const char def_sock_name[] = { DK4_INST_DIR_RUNSTATE "/printqd/printqd.sock" }; /** Protocol keywords at start of accounting line. */ static const char * const command_names[] = { /* 0 */ "jobstart", /* 1 */ "jobend", /* 2 */ "start", /* 3 */ "end", /* 4 */ "filestart", /* 5 */ "fileend", /* 6 */ "info", /* 7 */ "acct-check", /* 8 */ "acct-start", /* 9 */ "acct-end", /* 10 */ "acct-charge", /* 11 */ "control", NULL #line 318 "printqdc.ctr" }; /** Responses from printqd */ static const char * const responses[] = { /* 0 */ "ACCEPT", /* 1 */ "HOLD", /* 2 */ "REMOVE", NULL #line 329 "printqdc.ctr" }; /** Data exchange buffer. */ static char inbuf[4096]; /** Copy for inspection. */ static char cpbuf[sizeof(inbuf)]; /** Host name for network connection. */ static char *host_name = NULL; /** Socket file name for local connection. */ static char *sock_name = NULL; /** Number of options. */ static size_t szoptions = sizeof(options)/sizeof(dk4_option_t); /** Normal exit value (when run as pipe). */ static int exval = LPRNG_EXIT_SUCCESS; /** Help (1), version (2), license (4). */ static int hvl = 0; /** Exit value for interactive mode. */ static int iexval = EXIT_FAILURE; /** Flag: Interactive mode (-i option). */ static int intera = 0; /** Flag: EOF was found. */ static int eof_found = 0; /** Flag: Response already found and processed. */ static int found_response = 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; /** Port number for network connection. */ static unsigned short portno = 0U; /** Pass pointer through. Use of this function is recommended by CERT C coding standard to avoid optimizing out. @param ptr Pointer to pass through. @return The ptr argument. */ 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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 DK4_ARG_UNUSED(signo) ) { DK4_UNUSED_ARG(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 must abort due to signal. @param dopipe Flag: Check for SIGPIPE too. @return 1 if we can continue, 0 otherwise. */ static int can_continue(void) { int back = 1; if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } if (0 != sig_read_atomic(&sig_had_int)) { back = 0; } return back; } /** Log one-component message to stderr. @param kwind Index of text in printqdc_kw array. */ static void log_1(size_t kwind) { if (0 != intera) { fputs(pqdc_kw[7], stderr); fputs(pqdc_kw[kwind], stderr); fflush(stderr); } } /** Eat up input to avoid broken pipe in feeder. */ static void eatup_input(void) { size_t rdb; int cc = 1; do { if (0 != can_continue()) { rdb = fread(inbuf, 1, sizeof(inbuf), stdin); if (0 == rdb) { cc = 0; } } else { cc = -1; } } while(1 == cc); } /** Process command line arguments. @param argc Number of command line arguments. @param argv Command line arguments array. @return 1 on success, 0 on error. */ static int cmd_line_args(int argc, char *argv[]) { dkChar *filenames[32]; size_t szfilenames = DK4_SIZEOF(filenames,DK4_PDKCHAR); int back; back = dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 0, NULL ); if (1 == back) { if (0 != options[4].found) { hvl |= 1; } if (0 != options[5].found) { hvl |= 2; } if (0 != options[6].found) { hvl |= 4; } if (0 != options[0].found) { intera = 1; } if (0 != options[1].found) { sock_name = options[1].val.t; } if (0 != options[2].found) { host_name = options[2].val.t; } if (0 != options[3].found) { if ((dk4_um_t)0x0000FFFFUL >= options[3].val.u) { portno = (unsigned short)(options[3].val.u); } else { back = 0; /* ERROR: Port number to large! */ log_1(8); } } if ((NULL != host_name) && (0 == portno)) { back = 0; /* ERROR: Port number required */ log_1(9); } if ((NULL == host_name) && (0 != portno)) { back = 0; /* ERROR: Host name required */ log_1(10); } } else { if (0 != options[0].found) { (void)dk4opt_process_argv( options, szoptions, argc, argv, filenames, &szfilenames, 1, 1, NULL ); } } return back; } /** Data exchange with accounting system. @param pres Flag: Process response, 0=no, 1=acct-check, 2=info. */ static void process_data(int pres) { const char *ep; /* End pointer for text to number conversions */ char *ptr; /* Traverse data line */ dk4_um_t um; /* Number obtained from text */ size_t sl; /* Input buffer string length */ size_t wrb; /* Bytes we still have to write */ dk4_socket_t sock; /* Connection to accounting/quota daemon */ int res; /* Operation result */ int cc; /* Flag: Can continue */ #line 621 "printqdc.ctr" wrb = sl = strlen(inbuf); /* LOG/SHOW: Request */ if (0 != intera) { #line 624 "printqdc.ctr" fputs(pqdc_kw[4], stdout); if (0 < sl) { fputs(inbuf, stdout); if (0 < sl) { if ('\n' != inbuf[sl - 1]) { fputc('\n', stdout); } } else { fputc('\n', stdout); } } fflush(stdout); } if ((0 < sl) && (0 != can_continue())) { #line 638 "printqdc.ctr" if ((NULL != host_name) && (0 < portno)) { #line 639 "printqdc.ctr" sock = dk4socket_c8_tcp_client_host_port( host_name, portno, 0, 0L, 0L, NULL ); } else { #line 643 "printqdc.ctr" sock = dk4socket_c8_unix_client( ((NULL != sock_name) ? sock_name : def_sock_name), NULL ); } if (INVALID_SOCKET != sock) { #line 648 "printqdc.ctr" if (0 != can_continue()) { #line 649 "printqdc.ctr" res = dk4socket_send(sock, inbuf, &wrb, 0, 0L, 0L, NULL); if ((DK4_SOCKET_RESULT_SUCCESS == res) && (wrb == sl)) { #line 651 "printqdc.ctr" if (0 != can_continue()) { #line 652 "printqdc.ctr" res = dk4socket_shutdown(sock, DK4_SOCKET_SHUT_WRITE, NULL); if (DK4_SOCKET_RESULT_SUCCESS == res) { #line 654 "printqdc.ctr" cc = 1; do { if (0 != can_continue()) { #line 657 "printqdc.ctr" wrb = sizeof(inbuf); res = dk4socket_recv(sock, inbuf, &wrb, 0, 0L, 0L, NULL); if ((DK4_SOCKET_RESULT_SUCCESS==res)&&(0 != can_continue())) { if (0 < wrb) { #line 661 "printqdc.ctr" if (0 != pres) { #line 662 "printqdc.ctr" if (sizeof(inbuf) > wrb) { inbuf[wrb] = '\0'; } else { iexval = EXIT_FAILURE; inbuf[sizeof(inbuf)-1] = '\0'; } dk4str8_normalize(inbuf, NULL); /* LOG/SHOW: Response */ if (0 != intera) { fputs(pqdc_kw[5], stdout); fputs(inbuf, stdout); fputs(pqdc_kw[6], stdout); fflush(stdout); } switch (pres) { case 1: { if (0 == found_response) { switch (dk4str8_array_index(responses,inbuf,0)) { case 1: { exval = LPRNG_EXIT_HOLD; } break; case 2: { exval = LPRNG_EXIT_REMOVE; } break; } } found_response = 1; } break; case 2: { if (0 == found_response) { um = (dk4_um_t)0UL; ep = NULL; ptr = dk4str8_start(inbuf, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { ptr = dk4str8_next(ptr, NULL); if (NULL != ptr) { res = dk4ma_input_c8_dec_dk4_um_t( &um, ptr, &ep, 1, NULL ); if (0 == res) { um = (dk4_um_t)0UL; } } } } } if ((dk4_um_t)0UL == um) { exval = LPRNG_EXIT_REMOVE; } } found_response = 1; } break; } } else { #line 720 "printqdc.ctr" } } else { #line 722 "printqdc.ctr" cc = 0; } } else { #line 725 "printqdc.ctr" iexval = EXIT_FAILURE; cc = -1; } } else { #line 729 "printqdc.ctr" cc = -1; } } while (1 == cc); } else { #line 733 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to shut down socket */ log_1(11); } } else { #line 738 "printqdc.ctr" } } else { #line 740 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Sending data failed */ log_1(12); } } else { #line 745 "printqdc.ctr" } dk4socket_close(sock, NULL); } else { #line 748 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to open socket */ log_1(13); } } else { #line 753 "printqdc.ctr" } #line 755 "printqdc.ctr" } /** Find final quote for current word. @param str String to find quote in. @param quote Quote character. @return Pointer to found quote on success, NULL on error. */ static char * lprng_final_quote(char *str, char quote) { char *back = NULL; #line 770 "printqdc.ctr" while (('\0' != *str) && (NULL == back)) { if (quote == *str) { *str = '\0'; back = str; back++; back = dk4str8_start(back, NULL); } else { if ('\\' == *str) { if ('\0' != str[1]) { dk4str8_cpy_to_left(str, &(str[1])); str++; } else { *str = '\0'; } } else { str++; } } } #line 790 "printqdc.ctr" return back; } /** Find start of next text word in LPRng accounting line. @param str Current word (remaining text) in accounting line. @return Pointer to next word if found, NULL on error. */ static char * lprng_next_word(char *str) { char *back = NULL; #line 804 "printqdc.ctr" switch (*str) { case '\'' : { back = lprng_final_quote(&(str[1]), '\''); } break; case '"' : { back = lprng_final_quote(&(str[1]), '"'); } break; default : { back = dk4str8_next(str, NULL); } break; } #line 815 "printqdc.ctr" return back; } /** Fill data structure from LPRng accounting line. @param liptr Structure to fill. @param textline The text line to use. @return 1 on success, 0 on error. */ static int lprng_info_from_line(lprng_info_t *liptr, char *textline) { char *next; int back = 1; #line 832 "printqdc.ctr" DK4_MEMRES(liptr, sizeof(lprng_info_t)); liptr->username = NULL; liptr->queuename = NULL; liptr->jobtitle = NULL; liptr->pagecount = NULL; while (NULL != textline) { next = lprng_next_word(textline); if (('\'' == *textline) || ('"' == *textline)) { textline++; } if ('-' == *textline) { textline++; switch (*textline) { case 'n': { liptr->username = ++textline; } break; case 'P': { liptr->queuename = ++textline; } break; case 'J': { liptr->jobtitle = ++textline; } break; case 'p': { liptr->pagecount = ++textline; } break; } } else { #line 857 "printqdc.ctr" #if 0 /* 2016-02-15 Simply ignore non-option text. */ back = 0; /* ERROR: No minus sign */ #endif } textline = next; } #line 867 "printqdc.ctr" return back; } /** Process one line received from LPRng. @param cmd Index in command names array. @param args Further arguments in line. */ static void lprng_line(int cmd, char *args) { lprng_info_t li; /* All relevant components of line */ const char *ep = NULL; /* End pointer for numeric conversion */ const char *jt; /* Job title */ dk4_um_t um; /* Text to number conversion result */ int res; /* Operation result */ int ok = 0; /* Flag: Can process line */ #line 887 "printqdc.ctr" if (0 != lprng_info_from_line(&li, args)) { switch (cmd) { case 0: { if ((NULL != li.username) && (NULL != li.queuename)) { if (0 != dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[7], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[0], NULL)) { ok = 1; #line 898 "printqdc.ctr" } } } } } } if (0 != ok) { process_data(1); } else { #line 907 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to construct request */ log_1(14); } } else { #line 912 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } break; default: { if ((NULL != li.username) && (NULL != li.queuename)) { if (NULL != li.pagecount) { res = dk4ma_input_c8_dec_dk4_um_t(&um, li.pagecount, &ep, 1, NULL); if (0 != res) { cmd += 4; if(0 !=dk4str8_cpy_s(inbuf,sizeof(inbuf),command_names[cmd],NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.queuename, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.username, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),li.pagecount, NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[2], NULL)) { if (0 != dk4str8_cat_s(inbuf,sizeof(inbuf),pqdc_kw[1], NULL)) { jt = li.jobtitle; if (NULL == jt) { jt = pqdc_kw[3]; } if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), jt, NULL)) { if (0 != dk4str8_cat_s(inbuf, sizeof(inbuf), pqdc_kw[0], NULL)) { ok = 1; } } } } } } } } } } } } if (0 != ok) { #line 952 "printqdc.ctr" process_data(0); } else { #line 954 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Failed to construct request */ log_1(14); } } else { #line 959 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Pagecounter not numeric */ log_1(16); } } else { #line 964 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } else { #line 969 "printqdc.ctr" iexval = EXIT_FAILURE; /* ERROR: Incomplete information */ log_1(15); } } break; } } else { iexval = EXIT_FAILURE; } #line 979 "printqdc.ctr" } /** Process one line containing printqd style data. @param args Arguments text. @param minargs Minimum required number of arguments. @param num3 Flag: Argument 3 must be unsigned number. @param pres Flag: Process response. */ static void printqd_line(char *args, size_t minargs, int num3, int pres) { const char *ep = NULL; /* End of usable data */ char *next; /* Start of arguments */ dk4_um_t um = (dk4_um_t)0UL; /* Numeric conversion result */ size_t i; /* Current argument index */ int res; /* Operation result */ int errnum = 0; /* Flag: Numeric error */ #line 1000 "printqdc.ctr" dk4str8_normalize(args, NULL); i = 0; #line 1002 "printqdc.ctr" while(args) { i++; next = dk4str8_next(args, NULL); if ((3 == i) && (0 != num3)) { #line 1006 "printqdc.ctr" res = dk4ma_input_c8_dec_dk4_um_t(&um, args, &ep, 1, NULL); if (0 == res) { errnum = 1; } } args = next; } #line 1011 "printqdc.ctr" if ((i >= minargs) && (0 == errnum)) { process_data(pres); } else { if (i < minargs) { /* ERROR: Too few arguments */ log_1(17); } if (0 != errnum) { /* ERROR: Page counter not numeric */ log_1(16); } iexval = EXIT_FAILURE; } #line 1025 "printqdc.ctr" } /** Process input from stdin. */ static void process_input(void) { char *args; /* Start of arguments after command */ int cc; /* Flag: Can continue */ int res; /* Operation result for numeric conversions */ #line 1039 "printqdc.ctr" cc = 1; do { if (0 != can_continue()) { #line 1042 "printqdc.ctr" if (fgets(inbuf, sizeof(inbuf), stdin)) { #line 1043 "printqdc.ctr" dk4str8_cpy_s(cpbuf, sizeof(cpbuf), inbuf, NULL); dk4str8_delnl(cpbuf); if (NULL != dk4str8_start(cpbuf, NULL)) { if (0 != intera) { #line 1047 "printqdc.ctr" fputs(cpbuf, stdout); fputc('\n', stdout); fflush(stdout); } args = dk4str8_next(cpbuf, NULL); if (NULL != args) { #line 1053 "printqdc.ctr" res = dk4str8_array_index(command_names, cpbuf, 0); if (0 != can_continue()) { switch (res) { case 0: { lprng_line(res, args); } break; case 1: { } break; case 2: { } break; case 3: { } break; case 4: { lprng_line(res, args); } break; case 5: { lprng_line(res, args); } break; case 6: { printqd_line(args, 2, 0, 2); } break; case 7: { printqd_line(args, 2, 0, 1); } break; case 8: { printqd_line(args, 4, 1, 0); } break; case 9: { printqd_line(args, 4, 1, 0); } break; case 10: { printqd_line(args, 3, 1, 0); } break; case 11: { printqd_line(args, 1, 0, 0); } break; default: { iexval = EXIT_FAILURE; /* ERROR: Unknown keyword */ log_1(18); } break; } } else { cc = -1; } } else { #line 1099 "printqdc.ctr" /* ERROR: No arguments */ log_1(19); iexval = EXIT_FAILURE; } } else { #line 1104 "printqdc.ctr" } } else { #line 1106 "printqdc.ctr" eof_found = 1; cc = 0; } } else { #line 1110 "printqdc.ctr" cc = -1; } } while (1 == cc); #line 1114 "printqdc.ctr" } /** Show a text paragraph on standard output. @param txt Text to show. */ static void show_text(const char * const *txt) { if (NULL != txt) { while (NULL != *txt) { fputs(*(txt++), stdout); fputc('\n', stdout); } fflush(stdout); } } /** Handle --help, --version, --license options. */ static void run_hvl(void) { if (0 != (1 & hvl)) { show_text(help_text); } if (0 != (2 & hvl)) { fputs(version_text, stdout); fputc('\n', stdout); fflush(stdout); } if (0 != (4 & hvl)) { show_text(license_text); } } /** Main program. @param argc Number of command line arguments. @param argv Command line arguments array. @return Exit status code. */ int main(int argc, char *argv[]) { #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE struct sigaction opipe; struct sigaction npipe; #endif struct sigaction oint; struct sigaction nint; struct sigaction oterm; struct sigaction nterm; #else #ifdef SIGPIPE dk4_sig_handler_t *opipe = NULL; #endif dk4_sig_handler_t *oterm = NULL; dk4_sig_handler_t *oint = NULL; #endif #ifdef DK4_HAVE_SIGACTION #ifdef SIGPIPE int spipe = 0; #endif int sint = 0; int sterm = 0; int s_f_i = 0; int s_f_r = 0; #endif int socki = 0; /* Set signal handlers */ #if DK4_HAVE_SIGACTION #ifdef SIGPIPE DK4_MEMRES(&npipe, sizeof(npipe)); npipe.sa_handler = sig_handler_pipe; npipe.sa_flags = 0; if (0 != sigemptyset(&npipe.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { s_f_i = 1; goto finished; } spipe = 1; #endif DK4_MEMRES(&nterm, sizeof(nterm)); nterm.sa_handler = sig_handler_term; nterm.sa_flags = 0; if (0 != sigemptyset(&nterm.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGTERM, &nterm, &oterm)) { s_f_i = 1; goto finished; } sterm = 1; DK4_MEMRES(&nint, sizeof(nint)); nint.sa_handler = sig_handler_int; nint.sa_flags = 0; if (0 != sigemptyset(&nint.sa_mask)) { s_f_i = 1; goto finished; } if (0 != sigaddset(&nint.sa_mask, SIGINT)) { s_f_i = 1; goto finished; } if (0 != sigaction(SIGINT, &nint, &oint)) { s_f_i = 1; goto finished; } sint = 1; #else #ifdef SIGPIPE opipe = sigset(SIGPIPE, sig_handler_pipe); #endif oint = sigset(SIGINT, sig_handler_int); oterm = sigset(SIGTERM, sig_handler_term); #endif /* Start tracing */ #line 1256 "printqdc.ctr" #line 1257 "printqdc.ctr" /* Process command line arguments */ if (0 == cmd_line_args(argc, argv)) { goto finished; } /* Help, version, license. */ if (0 != hvl) { run_hvl(); goto finished; } /* Bring socket subsystem up. */ if (DK4_SOCKET_RESULT_SUCCESS != dk4socket_up(NULL)) { /* ERROR: Failed to initialize socket subsystem */ log_1(23); goto finished; } socki = 1; iexval = EXIT_SUCCESS; #line 1280 "printqdc.ctr" process_input(); finished: /* Eat up remaining input, if any. */ if ((0 == hvl) && (0 == eof_found)) { eatup_input(); } /* Log notification about abort by signal. */ if (0 == can_continue()) { /* LOG: Interrupted by signal */ log_1(20); iexval = EXIT_FAILURE; } /* Release socket subsystem. */ if (0 != socki) { (void)dk4socket_down(NULL); } /* Restore signal handlers */ #if DK4_HAVE_SIGACTION if (0 != s_f_i) { /* ERROR: Failed to install signal handlers */ log_1(21); iexval = EXIT_FAILURE; } if (0 != sint) { if (0 != sigaction(SIGINT, &oint, NULL)) { s_f_r = 1; } } if (0 != sterm) { if (0 != sigaction(SIGTERM, &oterm, NULL)) { s_f_r = 1; } } #ifdef SIGPIPE if (0 != spipe) { if (0 != sigaction(SIGPIPE, &opipe, NULL)) { s_f_r = 1; } } #endif if (0 != s_f_r) { /* ERROR: Failed to restore signal handlers */ log_1(22); iexval = EXIT_FAILURE; } #else if (NULL != oterm) { sigset(SIGTERM, oterm); } if (NULL != oint ) { sigset(SIGINT, oint ); } #ifdef SIGPIPE if (NULL != opipe) { sigset(SIGPIPE, opipe); } #endif #endif /* Set exit status code depending on interactive mode */ if (0 != intera) { exval = iexval; } /* Finish tracing */ #line 1345 "printqdc.ctr" #line 1346 "printqdc.ctr" /* Exit */ exit(exval); return exval; } #else /* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */ /** Main program. @param argc Number of command line arguments. @param argv Command line arguments array. @return Exit status code. */ int main(int argc, char *argv[]) { fputs("printqdc: ERROR: Program can not be used on this system!\n", stderr); fflush(stderr); exit(EXIT_FAILURE); return EXIT_FAILURE; } #endif /* if (DK4_CHAR_SIZE == 1) && ((DK4_HAVE_SIGACTION) || (DK4_HAVE_SIGSET)) */