ccan: import err module.from ccan revision 5add556a1cb64b49a664506aa76216d885b22c97
authorRusty Russell <rusty@rustcorp.com.au>
Sat, 9 Jun 2012 06:07:20 +0000 (15:37 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Sat, 9 Jun 2012 06:11:18 +0000 (15:41 +0930)
This allows us to avoid err.h in failtest.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
lib/ccan/err/.depends [new file with mode: 0644]
lib/ccan/err/_info [new file with mode: 0644]
lib/ccan/err/err.c [new file with mode: 0644]
lib/ccan/err/err.h [new file with mode: 0644]
lib/ccan/err/test/run.c [new file with mode: 0644]
lib/ccan/wscript

diff --git a/lib/ccan/err/.depends b/lib/ccan/err/.depends
new file mode 100644 (file)
index 0000000..ee4f1e4
--- /dev/null
@@ -0,0 +1 @@
+ccan/compiler
diff --git a/lib/ccan/err/_info b/lib/ccan/err/_info
new file mode 100644 (file)
index 0000000..97bc0f9
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <string.h>
+#include "config.h"
+
+/**
+ * err - err(), errx(), warn() and warnx(), as per BSD's err.h.
+ *
+ * A few platforms don't provide err.h; for those, this provides replacements.
+ * For most, it simple includes the system err.h.
+ *
+ * Unfortunately, you have to call err_set_progname() to tell the replacements
+ * your program name, otherwise it prints "unknown program".
+ *
+ * Example:
+ *     #include <ccan/err/err.h>
+ *
+ *     int main(int argc, char *argv[])
+ *     {
+ *             err_set_progname(argv[0]);
+ *             if (argc != 1)
+ *                     errx(1, "Expect no arguments");
+ *             exit(0);
+ *     }
+ *
+ * License: Public domain
+ * Author: Rusty Russell <rusty@rustcorp.com.au>
+ */
+int main(int argc, char *argv[])
+{
+       if (argc != 2)
+               return 1;
+
+       if (strcmp(argv[1], "depends") == 0) {
+#if !HAVE_ERR_H
+               printf("ccan/compiler\n");
+#endif
+               return 0;
+       }
+
+       return 1;
+}
diff --git a/lib/ccan/err/err.c b/lib/ccan/err/err.c
new file mode 100644 (file)
index 0000000..9e0e20c
--- /dev/null
@@ -0,0 +1,64 @@
+#include "err.h"
+
+#if !HAVE_ERR_H
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+static const char *progname = "unknown program";
+
+void err_set_progname(const char *name)
+{
+       progname = name;
+}
+
+void NORETURN err(int eval, const char *fmt, ...)
+{
+       int err_errno = errno;
+       va_list ap;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fprintf(stderr, ": %s\n", strerror(err_errno));
+       exit(eval);
+}
+
+void NORETURN errx(int eval, const char *fmt, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+       exit(eval);
+}
+
+void warn(const char *fmt, ...)
+{
+       int err_errno = errno;
+       va_list ap;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fprintf(stderr, ": %s\n", strerror(err_errno));
+}
+
+void warnx(const char *fmt, ...)
+{
+       va_list ap;
+
+       fprintf(stderr, "%s: ", progname);
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       va_end(ap);
+       fprintf(stderr, "\n");
+}
+#endif
diff --git a/lib/ccan/err/err.h b/lib/ccan/err/err.h
new file mode 100644 (file)
index 0000000..58ad91c
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef CCAN_ERR_H
+#define CCAN_ERR_H
+#include "config.h"
+
+#if HAVE_ERR_H
+#include <err.h>
+
+/* This is unnecessary with a real err.h.  See below */
+#define err_set_progname(name) ((void)name)
+
+#else
+#include <ccan/compiler/compiler.h>
+
+/**
+ * err_set_progname - set the program name
+ * @name: the name to use for err, errx, warn and warnx
+ *
+ * The BSD err.h calls know the program name, unfortunately there's no
+ * portable way for the CCAN replacements to do that on other systems.
+ *
+ * If you don't call this with argv[0], it will be "unknown program".
+ *
+ * Example:
+ *     err_set_progname(argv[0]);
+ */
+void err_set_progname(const char *name);
+
+/**
+ * err - exit(eval) with message based on format and errno.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *     <executable name>: <format>: <strerror(errno)>\n
+ *
+ * Example:
+ *     char *p = strdup("hello");
+ *     if (!p)
+ *             err(1, "Failed to strdup 'hello'");
+ */
+void NORETURN err(int eval, const char *fmt, ...);
+
+/**
+ * errx - exit(eval) with message based on format.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *     <executable name>: <format>\n
+ *
+ * Example:
+ *     if (argc != 1)
+ *             errx(1, "I don't expect any arguments");
+ */
+void NORETURN errx(int eval, const char *fmt, ...);
+
+/**
+ * warn - print a message to stderr based on format and errno.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *     <executable name>: <format>: <strerror(errno)>\n
+ *
+ * Example:
+ *     char *p = strdup("hello");
+ *     if (!p)
+ *             warn("Failed to strdup 'hello'");
+ */
+void warn(const char *fmt, ...);
+
+/**
+ * warnx - print a message to stderr based on format.
+ * @eval: the exit code
+ * @fmt: the printf-style format string
+ *
+ * The format string is printed to stderr like so:
+ *     <executable name>: <format>\n
+ *
+ * Example:
+ *     if (argc != 1)
+ *             warnx("I don't expect any arguments (ignoring)");
+ */
+void warnx(const char *fmt, ...);
+#endif
+
+#endif /* CCAN_ERR_H */
diff --git a/lib/ccan/err/test/run.c b/lib/ccan/err/test/run.c
new file mode 100644 (file)
index 0000000..242e93f
--- /dev/null
@@ -0,0 +1,153 @@
+#include <ccan/err/err.c>
+#include <ccan/tap/tap.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define BUFFER_MAX 1024
+
+int main(int argc, char *argv[])
+{
+       int pfd[2];
+       const char *base;
+
+       plan_tests(24);
+
+       err_set_progname(argv[0]);
+
+       /* In case it only prints out the basename of argv[0]. */
+       base = strrchr(argv[0], '/');
+       if (base)
+               base++;
+       else
+               base = argv[0];
+
+       /* Test err() in child */
+       pipe(pfd);
+       fflush(stdout);
+       if (fork()) {
+               char buffer[BUFFER_MAX+1];
+               unsigned int i;
+               int status;
+
+               /* We are parent. */
+               close(pfd[1]);
+               for (i = 0; i < BUFFER_MAX; i++) {
+                       if (read(pfd[0], buffer + i, 1) == 0) {
+                               buffer[i] = '\0';
+                               ok1(strstr(buffer, "running err:"));
+                               ok1(strstr(buffer, strerror(ENOENT)));
+                               ok1(strstr(buffer, base));
+                               ok1(buffer[i-1] == '\n');
+                               break;
+                       }
+               }
+               close(pfd[0]);
+               ok1(wait(&status) != -1);
+               ok1(WIFEXITED(status));
+               ok1(WEXITSTATUS(status) == 17);
+       } else {
+               close(pfd[0]);
+               dup2(pfd[1], STDERR_FILENO);
+               errno = ENOENT;
+               err(17, "running %s", "err");
+               abort();
+       }
+
+       /* Test errx() in child */
+       pipe(pfd);
+       fflush(stdout);
+       if (fork()) {
+               char buffer[BUFFER_MAX+1];
+               unsigned int i;
+               int status;
+
+               /* We are parent. */
+               close(pfd[1]);
+               for (i = 0; i < BUFFER_MAX; i++) {
+                       if (read(pfd[0], buffer + i, 1) == 0) {
+                               buffer[i] = '\0';
+                               ok1(strstr(buffer, "running errx\n"));
+                               ok1(strstr(buffer, base));
+                               break;
+                       }
+               }
+               close(pfd[0]);
+               ok1(wait(&status) != -1);
+               ok1(WIFEXITED(status));
+               ok1(WEXITSTATUS(status) == 17);
+       } else {
+               close(pfd[0]);
+               dup2(pfd[1], STDERR_FILENO);
+               errx(17, "running %s", "errx");
+               abort();
+       }
+
+
+       /* Test warn() in child */
+       pipe(pfd);
+       fflush(stdout);
+       if (fork()) {
+               char buffer[BUFFER_MAX+1];
+               unsigned int i;
+               int status;
+
+               /* We are parent. */
+               close(pfd[1]);
+               for (i = 0; i < BUFFER_MAX; i++) {
+                       if (read(pfd[0], buffer + i, 1) == 0) {
+                               buffer[i] = '\0';
+                               ok1(strstr(buffer, "running warn:"));
+                               ok1(strstr(buffer, strerror(ENOENT)));
+                               ok1(strstr(buffer, base));
+                               ok1(buffer[i-1] == '\n');
+                               break;
+                       }
+               }
+               close(pfd[0]);
+               ok1(wait(&status) != -1);
+               ok1(WIFEXITED(status));
+               ok1(WEXITSTATUS(status) == 17);
+       } else {
+               close(pfd[0]);
+               dup2(pfd[1], STDERR_FILENO);
+               errno = ENOENT;
+               warn("running %s", "warn");
+               exit(17);
+       }
+
+       /* Test warnx() in child */
+       pipe(pfd);
+       fflush(stdout);
+       if (fork()) {
+               char buffer[BUFFER_MAX+1];
+               unsigned int i;
+               int status;
+
+               /* We are parent. */
+               close(pfd[1]);
+               for (i = 0; i < BUFFER_MAX; i++) {
+                       if (read(pfd[0], buffer + i, 1) == 0) {
+                               buffer[i] = '\0';
+                               ok1(strstr(buffer, "running warnx\n"));
+                               ok1(strstr(buffer, base));
+                               break;
+                       }
+               }
+               close(pfd[0]);
+               ok1(wait(&status) != -1);
+               ok1(WIFEXITED(status));
+               ok1(WEXITSTATUS(status) == 17);
+       } else {
+               close(pfd[0]);
+               dup2(pfd[1], STDERR_FILENO);
+               warnx("running %s", "warnx");
+               exit(17);
+       }
+       return exit_status();
+}
+
index 8a2b3e79b72d6a26f41aacc7aed0f36d3b248e1d..24c9550121bac604471dfcb0731c403214ba4426 100644 (file)
@@ -122,14 +122,14 @@ def configure(conf):
 
 def build(bld):
 
-    for ccan_dir in ["hash", "htable", "ilog", "likely", "list", "read_write_all", "str", "tally", "time"]:
+    for ccan_dir in ["err", "hash", "htable", "ilog", "likely", "list", "read_write_all", "str", "tally", "time"]:
         bld.SAMBA_SUBSYSTEM('ccan-%s' % ccan_dir,
                             source=bld.path.ant_glob('%s/*.c' % ccan_dir))
 
     if bld.env.DEVELOPER_MODE:
         bld.SAMBA_LIBRARY('ccan-failtest',
                           source=bld.path.ant_glob('failtest/*.c'),
-                          deps='execinfo ccan ccan-failtest ccan-htable ccan-list ccan-read_write_all ccan-time',
+                          deps='execinfo ccan ccan-err ccan-htable ccan-list ccan-read_write_all ccan-time',
                           private_library=True)
 
     bld.SAMBA_LIBRARY('ccan',