]> git.ozlabs.org Git - ccan/blobdiff - ccan/opt/usage.c
opt: print usage correctly for early args.
[ccan] / ccan / opt / usage.c
index ef33f9188dd304f41b12f19c6bbd29b3f8a69849..12f44a48752e0e0d4e0d722c74b7513561334733 100644 (file)
@@ -1,14 +1,17 @@
-/* Licensed under GPLv3+ - see LICENSE file for details */
+/* Licensed under GPLv2+ - see LICENSE file for details */
 #include <ccan/opt/opt.h>
-#ifdef HAVE_SYS_TERMIOS_H
+#if HAVE_SYS_TERMIOS_H
 #include <sys/ioctl.h>
 #include <sys/termios.h> /* Required on Solaris for struct winsize */
 #endif
+#if HAVE_SYS_UNISTD_H
 #include <sys/unistd.h> /* Required on Solaris for ioctl */
+#endif
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdarg.h>
 #include "private.h"
 
 /* We only use this for pointer comparisons. */
@@ -24,7 +27,8 @@ static unsigned int get_columns(void)
 
        if (env)
                ws_col = atoi(env);
-#ifdef HAVE_SYS_TERMIOS_H
+
+#ifdef TIOCGWINSZ
        if (!ws_col)
        {
                struct winsize w;
@@ -40,25 +44,35 @@ static unsigned int get_columns(void)
 
 /* Return number of chars of words to put on this line.
  * Prefix is set to number to skip at start, maxlen is max width, returns
- * length (after prefix) to put on this line. */
-static size_t consume_words(const char *words, size_t maxlen, size_t *prefix)
+ * length (after prefix) to put on this line.
+ * start is set if we start a new line in the source description. */
+static size_t consume_words(const char *words, size_t maxlen, size_t *prefix,
+                           bool *start)
 {
        size_t oldlen, len;
 
-       /* Swallow leading whitespace. */
-       *prefix = strspn(words, " ");
+       /* Always swollow leading whitespace. */
+       *prefix = strspn(words, " \n");
        words += *prefix;
 
-       /* Use at least one word, even if it takes us over maxlen. */
-       oldlen = len = strcspn(words, " ");
-       while (len <= maxlen) {
-               oldlen = len;
-               len += strspn(words+len, " ");
-               len += strcspn(words+len, " ");
-               if (len == oldlen)
-                       break;
+       /* Leading whitespace at start of line means literal. */
+       if (*start && *prefix) {
+               oldlen = strcspn(words, "\n");
+       } else {
+               /* Use at least one word, even if it takes us over maxlen. */
+               oldlen = len = strcspn(words, " ");
+               while (len <= maxlen) {
+                       oldlen = len;
+                       len += strspn(words+len, " ");
+                       if (words[len] == '\n')
+                               break;
+                       len += strcspn(words+len, " \n");
+                       if (len == oldlen)
+                               break;
+               }
        }
 
+       *start = (words[oldlen - 1] == '\n');
        return oldlen;
 }
 
@@ -92,11 +106,11 @@ static char *add_desc(char *base, size_t *len, size_t *max,
 {
        size_t off, prefix, l;
        const char *p;
-       bool same_line = false;
+       bool same_line = false, start = true;
 
        base = add_str(base, len, max, opt->names);
        off = strlen(opt->names);
-       if (opt->type == OPT_HASARG
+       if ((opt->type & OPT_HASARG)
            && !strchr(opt->names, ' ')
            && !strchr(opt->names, '=')) {
                base = add_str(base, len, max, " <arg>");
@@ -115,7 +129,7 @@ static char *add_desc(char *base, size_t *len, size_t *max,
 
        /* Indent description. */
        p = opt->desc;
-       while ((l = consume_words(p, width - indent, &prefix)) != 0) {
+       while ((l = consume_words(p, width - indent, &prefix, &start)) != 0) {
                if (!same_line)
                        base = add_indent(base, len, max, indent);
                p += prefix;
@@ -216,3 +230,17 @@ char *opt_usage(const char *argv0, const char *extra)
        ret[len] = '\0';
        return ret;
 }
+
+void opt_usage_exit_fail(const char *msg, ...)
+{
+       va_list ap;
+
+       if (opt_argv0)
+               fprintf(stderr, "%s: ", opt_argv0);
+       va_start(ap, msg);
+       vfprintf(stderr, msg, ap);
+       va_end(ap);
+       fprintf(stderr, "\n%s",
+               opt_usage(opt_argv0 ? opt_argv0 : "<program>", NULL));
+       exit(1);
+}