]> git.ozlabs.org Git - ccan/blobdiff - ccan/opt/usage.c
opt: print usage correctly for early args.
[ccan] / ccan / opt / usage.c
index d9b2ee59cc3e4ba9a10df5a5eb358a74b5b4fb89..12f44a48752e0e0d4e0d722c74b7513561334733 100644 (file)
@@ -1,10 +1,17 @@
-/* Licensed under GPLv3+ - see LICENSE file for details */
+/* Licensed under GPLv2+ - see LICENSE file for details */
 #include <ccan/opt/opt.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. */
@@ -15,42 +22,57 @@ const char opt_hidden[1];
 
 static unsigned int get_columns(void)
 {
-       struct winsize w;
+       int ws_col = 0;
        const char *env = getenv("COLUMNS");
 
-       w.ws_col = 0;
        if (env)
-               w.ws_col = atoi(env);
-       if (!w.ws_col)
-               if (ioctl(0, TIOCGWINSZ, &w) == -1)
-                       w.ws_col = 0;
-       if (!w.ws_col)
-               w.ws_col = 80;
-
-       return w.ws_col;
+               ws_col = atoi(env);
+
+#ifdef TIOCGWINSZ
+       if (!ws_col)
+       {
+               struct winsize w;
+               if (ioctl(0, TIOCGWINSZ, &w) != -1)
+                       ws_col = w.ws_col;
+       }
+#endif
+       if (!ws_col)
+               ws_col = 80;
+
+       return ws_col;
 }
 
 /* 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;
 }
 
@@ -58,7 +80,7 @@ static char *add_str_len(char *base, size_t *len, size_t *max,
                         const char *str, size_t slen)
 {
        if (slen >= *max - *len)
-               base = realloc(base, *max = (*max * 2 + slen + 1));
+               base = opt_alloc.realloc(base, *max = (*max * 2 + slen + 1));
        memcpy(base + *len, str, slen);
        *len += slen;
        return base;
@@ -72,7 +94,7 @@ static char *add_str(char *base, size_t *len, size_t *max, const char *str)
 static char *add_indent(char *base, size_t *len, size_t *max, size_t indent)
 {
        if (indent >= *max - *len)
-               base = realloc(base, *max = (*max * 2 + indent + 1));
+               base = opt_alloc.realloc(base, *max = (*max * 2 + indent + 1));
        memset(base + *len, ' ', indent);
        *len += indent;
        return base;
@@ -84,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>");
@@ -107,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;
@@ -208,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);
+}