]> ruderich.org/simon Gitweb - coloredstderr/coloredstderr.git/commitdiff
Hook error() and error_at_line() if available.
authorSimon Ruderich <simon@ruderich.org>
Wed, 5 Jun 2013 21:57:05 +0000 (23:57 +0200)
committerSimon Ruderich <simon@ruderich.org>
Wed, 5 Jun 2013 21:57:05 +0000 (23:57 +0200)
They are used by some GNU programs to display error messages.

.gitignore
configure.ac
src/coloredstderr.c
tests/Makefile.am
tests/example_error.c [new file with mode: 0644]
tests/example_error.expected [new file with mode: 0644]
tests/run.sh

index 098d9185ec572afe8e1fc12dd776b85fd9ca595b..5139119ff6da15da2b8d1f548ec7c3d95904c9d0 100644 (file)
@@ -23,6 +23,8 @@
 /tests/Makefile.in
 /tests/example
 /tests/example.o
+/tests/example_error
+/tests/example_error.o
 /tests/example_exec
 /tests/example_exec.o
 /tests/example_vfork
index a5279d06ef0dd6d1648bdd71c0beab43b7308b56..f660e60ebdf7833167557a4b3fd8ec66132f65b3 100644 (file)
@@ -32,7 +32,7 @@ dnl Used by test suite.
 AC_PROG_SED
 AC_PROG_EGREP
 
-AC_CHECK_HEADERS([fcntl.h])
+AC_CHECK_HEADERS([fcntl.h error.h])
 
 AC_TYPE_PID_T
 AC_TYPE_SIZE_T
@@ -51,5 +51,8 @@ AC_ARG_ENABLE([debug],
                    AC_DEFINE([DEBUG], 1, [Define to enable debug output.])
                fi])
 
+dnl Used in tests/Makefile.am to build the test only if error() is available.
+AM_CONDITIONAL([HAVE_ERROR_H],[test "x$ac_cv_header_error_h" = xyes])
+
 AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile])
 AC_OUTPUT
index e04a2ea01be40b4d0644ed65a031b93629c6b2b9..7ffa1581dcdf9c2791f4b42046284daf6253646c 100644 (file)
 #include <string.h>
 #include <unistd.h>
 
+#ifdef HAVE_ERROR_H
+# include <error.h>
+#endif
+
 /* Conflicting declaration in glibc. */
 #undef fwrite_unlocked
 
@@ -231,6 +235,74 @@ HOOK_FILE1(int, puts_unlocked, stdout,
 HOOK_VOID1(void, perror, STDERR_FILENO,
            const char *, s)
 
+/* error(3) */
+#ifdef HAVE_ERROR_H
+static void  error_vararg(int status, int errnum,
+                   const char *filename, unsigned int linenum,
+                   const char *format, va_list ap) {
+    static const char *last_filename;
+    static unsigned int last_linenum;
+
+    /* Skip this error message if requested and if there was already an error
+     * in the same file/line. */
+    if (error_one_per_line
+            && filename != NULL && linenum != 0
+            && filename == last_filename && linenum == last_linenum) {
+        return;
+    }
+    last_filename = filename;
+    last_linenum  = linenum;
+
+    error_message_count++;
+
+    fflush(stdout);
+
+    if (error_print_progname) {
+        error_print_progname();
+    } else {
+        fprintf(stderr, "%s:", program_invocation_name);
+    }
+    if (filename != NULL && linenum != 0) {
+        fprintf(stderr, "%s:%u:", filename, linenum);
+        if (error_print_progname) {
+            fprintf(stderr, " ");
+        }
+    }
+    if (!error_print_progname) {
+        fprintf(stderr, " ");
+    }
+
+
+    vfprintf(stderr, format, ap);
+
+    if (errnum != 0) {
+        fprintf(stderr, ": %s", strerror(errnum));
+    }
+
+    fprintf(stderr, "\n");
+
+    if (status != 0) {
+        exit(status);
+    }
+}
+void error_at_line(int status, int errnum,
+                   const char *filename, unsigned int linenum,
+                   const char *format, ...) {
+    va_list ap;
+
+    va_start(ap, format);
+    error_vararg(status, errnum, filename, linenum, format, ap);
+    va_end(ap);
+}
+void error(int status, int errnum, const char *format, ...) {
+    va_list ap;
+
+    va_start(ap, format);
+    error_vararg(status, errnum, NULL, 0, format, ap);
+    va_end(ap);
+}
+#endif
+
 
 /* Hook functions which duplicate file descriptors to track them. */
 
index 025fa8ad3bf9533fb2e454e9c0ba7444d28e0f65..bc3a9a93ae634714cf8850f9043fc9bb982eb2b5 100644 (file)
@@ -4,8 +4,14 @@ example_SOURCES = example.c
 example_exec_SOURCES = example_exec.c
 example_vfork_SOURCES = example_vfork.c
 
+if HAVE_ERROR_H
+    check_PROGRAMS += example_error
+    example_error_SOURCES = example_error.c
+endif
+
 dist_check_SCRIPTS = run.sh lib.sh
 dist_check_DATA = example.expected \
+                  example_error.expected \
                   example_exec.expected \
                   example_vfork.expected \
                   example-noforce.sh \
diff --git a/tests/example_error.c b/tests/example_error.c
new file mode 100644 (file)
index 0000000..04eca8d
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Test error() and error_at_line(). Non-standard, GNU only.
+ *
+ * Copyright (C) 2013  Simon Ruderich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define _GNU_SOURCE /* for program_invocation_name */
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <error.h>
+
+void (*error_print_progname)(void);
+
+
+static void print_prognmae(void) {
+    fprintf(stderr, "PROG");
+}
+
+
+int main(int argc, char **argv) {
+    program_invocation_name = "./example_error";
+
+    error(0, 0, "<message>");
+    error_at_line(0, 0, "file", 42, "<message>");
+
+    error(0, ENOMEM, "<message>");
+    error_at_line(0, ENOMEM, "file", 42, "<message>");
+    error_at_line(0, ENOMEM, "file", 42, "<message>");
+
+    error_print_progname = print_prognmae;
+    error_one_per_line = 1;
+
+    error(0, 0, "<message>");
+    error_at_line(0, 0, "file", 42, "<message>");
+
+    error(0, ENOMEM, "<message>");
+    error_at_line(0, ENOMEM, "file", 42, "<message>");
+    error_at_line(0, ENOMEM, "file", 42, "<message>");
+
+    /* Exit codes are not tested. */
+
+    return EXIT_SUCCESS;
+}
diff --git a/tests/example_error.expected b/tests/example_error.expected
new file mode 100644 (file)
index 0000000..463f343
--- /dev/null
@@ -0,0 +1,10 @@
+>STDERR>./example_error:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>
+<STDERR<>STDERR>./example_error:<STDERR<>STDERR>file:42:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>
+<STDERR<>STDERR>./example_error:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>: Cannot allocate memory<STDERR<>STDERR>
+<STDERR<>STDERR>./example_error:<STDERR<>STDERR>file:42:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>: Cannot allocate memory<STDERR<>STDERR>
+<STDERR<>STDERR>./example_error:<STDERR<>STDERR>file:42:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>: Cannot allocate memory<STDERR<>STDERR>
+<STDERR<>STDERR>PROG<STDERR<>STDERR><message><STDERR<>STDERR>
+<STDERR<>STDERR>PROG<STDERR<>STDERR>file:42:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>
+<STDERR<>STDERR>PROG<STDERR<>STDERR><message><STDERR<>STDERR>: Cannot allocate memory<STDERR<>STDERR>
+<STDERR<>STDERR>PROG<STDERR<>STDERR>file:42:<STDERR<>STDERR> <STDERR<>STDERR><message><STDERR<>STDERR>: Cannot allocate memory<STDERR<>STDERR>
+<STDERR<
\ No newline at end of file
index 0106d457d6f8ecb1a16f2463aca409f2b62c06c4..abd0e282377059509ecaf377ae6345cdc929917e 100755 (executable)
@@ -35,9 +35,14 @@ test_script example-redirects.sh
 test_program example
 test_program example_exec
 test_program example_vfork
+test -x "$builddir/example_error" && test_program example_error
 
 test_script_subshell example-simple.sh
 test_script_subshell example-redirects.sh
 test_program_subshell example
 test_program_subshell example_exec
 test_program_subshell example_vfork
+test -x "$builddir/example_error" && test_program_subshell example_error
+
+# Necessary in case the test -x evaluates to false.
+true