Gitweb links:

...log 
http://git.netsurf-browser.org/libnsgif.git/shortlog/1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72
...commit 
http://git.netsurf-browser.org/libnsgif.git/commit/1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72
...tree 
http://git.netsurf-browser.org/libnsgif.git/tree/1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72

The branch, tlsa/ci-sanitize has been updated
  discards  622cf7e422a8ef0acabad1bc8a98731cb1a7f5a9 (commit)
       via  1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72 (commit)
       via  fbe9f636b08d86bc10427283e35d60d2900aa5cc (commit)
       via  d4e69fcebd776233c42ef044230ce3b5b83e61de (commit)
       via  68350cd5c6d73ad210e1ae9d1dd102f4295639c1 (commit)
       via  26dd4eae0c35b25d1f8cf9ce3896317cf04961ce (commit)
       via  ffec523aa0a938beab7def1893d41685e28d2b34 (commit)
       via  fde3d979ace97bd109fce443b49cbbfa5a9307a2 (commit)
       via  d63e9e479c63f8f0a1579ea58205862047297f1a (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (622cf7e422a8ef0acabad1bc8a98731cb1a7f5a9)
            \
             N -- N -- N (1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commitdiff 
http://git.netsurf-browser.org/libnsgif.git/commit/?id=1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72
commit 1c29a0d7ee6e525a5fe03f4818dafdcbffbd2e72
Author: Michael Drake <[email protected]>
Commit: Michael Drake <[email protected]>

    CI: Add sanitizer jobs

diff --git a/.github/workflows/sanitize.yaml b/.github/workflows/sanitize.yaml
new file mode 100644
index 0000000..70a2f3c
--- /dev/null
+++ b/.github/workflows/sanitize.yaml
@@ -0,0 +1,65 @@
+name: "Linux Sanitize"
+
+on: [push]
+
+jobs:
+  linux:
+    name: '${{ matrix.os }}: ${{ matrix.compiler.vendor }}'
+    runs-on: ${{ matrix.os }}
+    strategy:
+      fail-fast: false
+      matrix:
+        os:
+          - ubuntu-22.04
+        compiler:
+          # The NetSurf build system can't find LLVM AR (it looks for it
+          # in /usr/lib instead of /usr/bin:
+          #     `make: /usr/lib/llvm-ar: No such file or directory`).
+          # So we need to make it explicit for llvm.
+          - { vendor: gnu,  CC: gcc,   AR: ar }
+          - { vendor: llvm, CC: clang, AR: llvm-ar }
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v3
+      with:
+        fetch-depth: 1
+
+    - name: apt-get install packages
+      run: sudo apt-get update -qq &&
+           sudo apt-get install --no-install-recommends -y
+               bison
+               build-essential
+               check
+               clang
+               flex
+               git
+               gperf
+               llvm
+               pkg-config
+
+    - name: Get env.sh
+      run: |
+           mkdir projects
+           wget -O projects/env.sh 
https://git.netsurf-browser.org/netsurf.git/plain/docs/env.sh
+
+    - name: Build and install project deps
+      env:
+        CC: ${{ matrix.compiler.CC }}
+        AR: ${{ matrix.compiler.AR }}
+        TARGET: ${{ github.event.repository.name }}
+      run: |
+          export TARGET_WORKSPACE="$(pwd)/projects"
+          source projects/env.sh
+          ns-clone -d -s
+          ns-make-libs install
+
+    - name: Build and Sanitize
+      env:
+        CC: ${{ matrix.compiler.CC }}
+        AR: ${{ matrix.compiler.AR }}
+        TARGET: ${{ github.event.repository.name }}
+      run: |
+          export TARGET_WORKSPACE="$(pwd)/projects"
+          source projects/env.sh
+          make sanitize


-----------------------------------------------------------------------

Summary of changes:
 include/nsgif.h |   15 +--
 src/gif.c       |   14 +--
 test/cli.c      |  292 +++++++++++++++++++++++++++++++++----------------------
 test/cli.h      |   17 ++--
 test/nsgif.c    |   25 ++++-
 5 files changed, 225 insertions(+), 138 deletions(-)

diff --git a/include/nsgif.h b/include/nsgif.h
index 7e6aa83..7df8981 100644
--- a/include/nsgif.h
+++ b/include/nsgif.h
@@ -166,15 +166,14 @@ typedef enum nsgif_bitmap_fmt {
 /**
  * Client bitmap type.
  *
- * These are client-created and destroyed, via the \ref bitmap callbacks,
- * but they are owned by a \ref nsgif_t.
+ * These are client-created and destroyed, via the \ref nsgif_bitmap_cb_vt
+ * callbacks, but they are owned by a \ref nsgif_t.
  *
  * See \ref nsgif_bitmap_fmt for pixel format information.
  *
  * The bitmap may have a row_span greater than the bitmap width, but the
  * difference between row span and width must be a whole number of pixels
- * (a multiple of four bytes). If row span is greater than width, the
- * \ref get_rowspan callback must be provided.
+ * (a multiple of four bytes).
  */
 typedef void nsgif_bitmap_t;
 
@@ -238,6 +237,8 @@ typedef struct nsgif_bitmap_cb_vt {
         *
         * If this callback is not provided, LibNSGIF will use the width.
         *
+        * If row span is greater than width, this callback must be provided.
+        *
         * \param[in]  bitmap  The bitmap.
         */
        uint32_t (*get_rowspan)(nsgif_bitmap_t *bitmap);
@@ -485,7 +486,7 @@ void nsgif_global_palette(
  * Colours in same pixel format as \ref nsgif_bitmap_t.
  *
  * \param[in]  gif      The \ref nsgif_t object.
- * \param[in]  frame    The \ref frame to get the palette for.
+ * \param[in]  frame    The frame to get the palette for.
  * \param[out] table    Client buffer to hold the colour table.
  * \param[out] entries  The number of used entries in the colour table.
  * \return true if a palette is returned, false otherwise.
@@ -511,7 +512,7 @@ bool nsgif_local_palette(
  *
  * Both the minimum and the default values can be overridden for a given GIF
  * by the client. To get frame delays exactly as specified by the GIF file, set
- * \ref delay_min to zero.
+ * `delay_min` to zero.
  *
  * Note that this does not affect the frame delay in the frame info
  * (\ref nsgif_frame_info_t) structure, which will always contain values
@@ -520,7 +521,7 @@ bool nsgif_local_palette(
  * \param[in]  gif            The \ref nsgif_t object to configure.
  * \param[in]  delay_min      The minimum frame delay in centiseconds.
  * \param[in]  delay_default  The delay to use if a frame delay is less than
- *                            \ref delay_min.
+ *                            `delay_min`.
  */
 void nsgif_set_frame_delay_behaviour(
                nsgif_t *gif,
diff --git a/src/gif.c b/src/gif.c
index 688fe12..44c60a9 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -1068,7 +1068,7 @@ static nsgif_error nsgif__parse_image_descriptor(
  * \param[in] colour_table          The colour table to populate.
  * \param[in] layout                la.
  * \param[in] colour_table_entries  The number of colour table entries.
- * \param[in] Data                  Raw colour table data.
+ * \param[in] data                  Raw colour table data.
  */
 static void nsgif__colour_table_decode(
                uint32_t colour_table[NSGIF_MAX_COLOURS],
@@ -1097,11 +1097,13 @@ static void nsgif__colour_table_decode(
 /**
  * Extract a GIF colour table into a LibNSGIF colour table buffer.
  *
- * \param[in] gif                   The gif object we're decoding.
- * \param[in] colour_table          The colour table to populate.
- * \param[in] colour_table_entries  The number of colour table entries.
- * \param[in] pos                   Current position in data, updated on exit.
- * \param[in] decode                Whether to decode the colour table.
+ * \param[in]  colour_table          The colour table to populate.
+ * \param[in]  layout                The target pixel format to decode to.
+ * \param[in]  colour_table_entries  The number of colour table entries.
+ * \param[in]  data                  Current position in data.
+ * \param[in]  data_len              The available length of `data`.
+ * \param[out] used                  Number of colour table bytes read.
+ * \param[in]  decode                Whether to decode the colour table.
  * \return NSGIF_OK on success, appropriate error otherwise.
  */
 static inline nsgif_error nsgif__colour_table_extract(
diff --git a/test/cli.c b/test/cli.c
index 031cd97..9c095fe 100644
--- a/test/cli.c
+++ b/test/cli.c
@@ -1,7 +1,7 @@
 /*
  * SPDX-License-Identifier: ISC
  *
- * Copyright (C) 2021 Michael Drake <[email protected]>
+ * Copyright (C) 2021-2022 Michael Drake <[email protected]>
  */
 
 /**
@@ -18,6 +18,15 @@
 #include "cli.h"
 
 /**
+ * CLI parsing context.
+ */
+struct cli_ctx {
+       const struct cli_table *cli; /**< Client CLI spec. */
+       size_t pos_count; /**< The number of positional arguments found. */
+       bool no_pos; /**< Have an argument that negates min_positional. */
+};
+
+/**
  * Check whether a CLI argument type should have a numerical value.
  *
  * \param[in]  type  An argument type.
@@ -112,6 +121,8 @@ static bool cli__parse_value_enum(
                }
        }
 
+       fprintf(stderr, "ERROR: Unknown enum value '%s'.\n", str);
+
        return false;
 }
 
@@ -286,16 +297,82 @@ static bool cli__handle_arg_value(const struct 
cli_table_entry *entry,
        return true;
 }
 
+static inline bool cli__is_negative(const char *arg)
+{
+       int64_t i;
+       size_t pos = 0;
+
+       return cli__parse_value_int(arg, &i, &pos)
+                       && pos == strlen(arg)
+                       && i < 0;
+}
+
+/**
+ * Parse a positional argument according to the given CLI spec entry.
+ *
+ * \param[in] ctx    Command line interface parsing context.
+ * \param[in] entry  Client command line interface argument specification.
+ * \param[in] arg    Argument to parse.
+ * \return true on success, or false otherwise.
+ */
+static bool cli__parse_positional_entry(struct cli_ctx *ctx,
+               const struct cli_table_entry *entry,
+               const char *arg)
+{
+       size_t pos = 0;
+       bool ret;
+
+       ret = cli__parse_value(entry, arg, &pos);
+       if (ret != true) {
+               return ret;
+       } else if (arg[pos] != '\0') {
+               fprintf(stderr, "Failed to parse value '%s' for arg '%s'\n",
+                               arg, entry->l);
+               return false;
+       }
+
+       ctx->pos_count++;
+       return true;
+}
+
+/**
+ * Parse a positional argument.
+ *
+ * \param[in] ctx    Command line interface parsing context.
+ * \param[in] arg    Argument to parse.
+ * \return true on success, or false otherwise.
+ */
+static bool cli__parse_positional(struct cli_ctx *ctx,
+               const char *arg)
+{
+       const struct cli_table *cli = ctx->cli;
+       size_t positional = 0;
+
+       for (size_t i = 0; i < cli->count; i++) {
+               if (cli__entry_is_positional(&cli->entries[i])) {
+                       if (positional == ctx->pos_count) {
+                               return cli__parse_positional_entry(ctx,
+                                               &cli->entries[i], arg);
+                       }
+
+                       positional++;
+               }
+       }
+
+       fprintf(stderr, "Unexpected positional argument: '%s'\n", arg);
+       return false;
+}
+
 /**
  * Parse a flags argument.
  *
- * \param[in]  cli      Client command line interface specification.
+ * \param[in]  ctx      Command line interface parsing context.
  * \param[in]  argc     Number of command line arguments.
  * \param[in]  argv     String vector containing command line arguments.
  * \param[out] arg_pos  Current position in argv, updated on exit.
  * \return true on success, or false otherwise.
  */
-static bool cli__parse_short(const struct cli_table *cli,
+static bool cli__parse_short(struct cli_ctx *ctx,
                int argc, const char **argv, int *arg_pos)
 {
        const char *arg = argv[*arg_pos];
@@ -308,11 +385,18 @@ static bool cli__parse_short(const struct cli_table *cli,
        while (arg[pos] != '\0') {
                const struct cli_table_entry *entry;
 
-               entry = cli__lookup_short(cli, arg[pos]);
+               entry = cli__lookup_short(ctx->cli, arg[pos]);
                if (entry == NULL) {
+                       if (cli__is_negative(argv[pos])) {
+                               return cli__parse_positional(ctx, argv[pos]);
+                       }
                        return false;
                }
 
+               if (entry->no_pos) {
+                       ctx->no_pos = true;
+               }
+
                if (entry->t == CLI_BOOL) {
                        *entry->v.b = true;
                } else {
@@ -364,13 +448,13 @@ static const struct cli_table_entry *cli__lookup_long(
 /**
  * Parse a long argument.
  *
- * \param[in]  cli      Client command line interface specification.
+ * \param[in]  ctx      Command line interface parsing context.
  * \param[in]  argc     Number of command line arguments.
  * \param[in]  argv     String vector containing command line arguments.
  * \param[out] arg_pos  Current position in argv, updated on exit.
  * \return true on success, or false otherwise.
  */
-static bool cli__parse_long(const struct cli_table *cli,
+static bool cli__parse_long(struct cli_ctx *ctx,
                int argc, const char **argv, int *arg_pos)
 {
        const struct cli_table_entry *entry;
@@ -382,11 +466,15 @@ static bool cli__parse_long(const struct cli_table *cli,
                return false;
        }
 
-       entry = cli__lookup_long(cli, arg, &pos);
+       entry = cli__lookup_long(ctx->cli, arg, &pos);
        if (entry == NULL) {
                return false;
        }
 
+       if (entry->no_pos) {
+               ctx->no_pos = true;
+       }
+
        if (entry->t == CLI_BOOL) {
                if (arg[pos] != '\0') {
                        fprintf(stderr, "Unexpected value for argument '%s'\n",
@@ -408,60 +496,6 @@ static bool cli__parse_long(const struct cli_table *cli,
 }
 
 /**
- * Parse a positional argument according to the given CLI spec entry.
- *
- * \param[in] entry  Client command line interface argument specification.
- * \param[in] arg    Argument to parse.
- * \return true on success, or false otherwise.
- */
-static bool cli__parse_positional_entry(
-               const struct cli_table_entry *entry,
-               const char *arg)
-{
-       size_t pos = 0;
-       bool ret;
-
-       ret = cli__parse_value(entry, arg, &pos);
-       if (ret != true) {
-               return ret;
-       } else if (arg[pos] != '\0') {
-               fprintf(stderr, "Failed to parse value '%s' for arg '%s'\n",
-                               arg, entry->l);
-               return false;
-       }
-
-       return true;
-}
-
-/**
- * Parse a positional argument.
- *
- * \param[in] cli    Client command line interface specification.
- * \param[in] arg    Argument to parse.
- * \param[in] count  Number of positional arguments parsed already.
- * \return true on success, or false otherwise.
- */
-static bool cli__parse_positional(const struct cli_table *cli,
-               const char *arg, size_t count)
-{
-       size_t positional = 0;
-
-       for (size_t i = 0; i < cli->count; i++) {
-               if (cli__entry_is_positional(&cli->entries[i])) {
-                       if (positional == count) {
-                               return cli__parse_positional_entry(
-                                               &cli->entries[i], arg);
-                       }
-
-                       positional++;
-               }
-       }
-
-       fprintf(stderr, "Unexpected positional argument: '%s'\n", arg);
-       return false;
-}
-
-/**
  * Get the string to indicate type of value expected for an argument.
  *
  * \param[in] type  The argument type.
@@ -553,20 +587,12 @@ static void cli__count(const struct cli_table *cli,
        }
 }
 
-static inline bool cli__is_negative(const char *arg)
-{
-       int64_t i;
-       size_t pos = 0;
-
-       return cli__parse_value_int(arg, &i, &pos)
-                       && pos == strlen(arg)
-                       && i < 0;
-}
-
 /* Documented in cli.h */
 bool cli_parse(const struct cli_table *cli, int argc, const char **argv)
 {
-       size_t pos_count = 0;
+       struct cli_ctx ctx = {
+               .cli = cli,
+       };
        enum {
                ARG_PROG_NAME,
                ARG_FIRST,
@@ -574,36 +600,24 @@ bool cli_parse(const struct cli_table *cli, int argc, 
const char **argv)
 
        for (int i = ARG_FIRST; i < argc; i++) {
                const char *arg = argv[i];
-               size_t pos_inc = 0;
                bool ret;
 
                if (arg[0] == '-') {
                        if (arg[1] == '-') {
-                               ret = cli__parse_long(cli, argc, argv, &i);
+                               ret = cli__parse_long(&ctx, argc, argv, &i);
                        } else {
-                               ret = cli__parse_short(cli, argc, argv, &i);
-                               if (ret != true) {
-                                       if (cli__is_negative(argv[i])) {
-                                               pos_inc = 1;
-                                               ret = cli__parse_positional(
-                                                               cli, argv[i],
-                                                               pos_count);
-                                       }
-                               }
+                               ret = cli__parse_short(&ctx, argc, argv, &i);
                        }
                } else {
-                       pos_inc = 1;
-                       ret = cli__parse_positional(cli, argv[i], pos_count);
+                       ret = cli__parse_positional(&ctx, argv[i]);
                }
 
                if (ret != true) {
                        return ret;
                }
-
-               pos_count += pos_inc;
        }
 
-       if (pos_count < cli->min_positional) {
+       if (ctx.no_pos == false && ctx.pos_count < cli->min_positional) {
                fprintf(stderr, "Insufficient positional arguments found.\n");
                return false;
        }
@@ -622,46 +636,90 @@ static size_t cli__terminal_width(void)
 }
 
 /**
- * Print an entry's description, with a given indent.
+ * Print a wrapped string, with a given indent.
  *
  * The indent is assumed to already be applied for the first line of the
  * output by the caller.
- * 
- * \param[in] entry   The entry to print the description for.
+ *
+ * \param[in] str     The string to print.
  * \param[in] indent  The number of spaces to pad the left margin with.
  */
-static void cli__print_description(const struct cli_table_entry *entry,
-               size_t indent)
+static void cli__print_wrapping_string(const char *str, size_t indent)
 {
        size_t terminal_width = cli__terminal_width();
        size_t avail = (indent > terminal_width) ? 0 : terminal_width - indent;
        size_t space = avail;
-       const char *desc = entry->d;
-
-       if (desc != NULL) {
-               while (*desc != '\0') {
-                       size_t word_len = strcspn(desc, " \n\t");
-                       if (word_len <= space || space == avail) {
-                               fprintf(stderr, "%*.*s",
-                                               (int)word_len,
-                                               (int)word_len, desc);
-                               desc += word_len;
-                               if (word_len <= space) {
-                                       space -= word_len;
-                               }
-                               if (space > 0) {
-                                       fprintf(stderr, " ");
-                                       space--;
-                               }
-                       } else {
-                               fprintf(stderr, "\n%*s", (int)indent, "");
-                               space = avail;
+
+       while (*str != '\0') {
+               size_t word_len = strcspn(str, " \n\t");
+               if (word_len <= space || space == avail) {
+                       fprintf(stderr, "%*.*s",
+                                       (int)word_len,
+                                       (int)word_len, str);
+                       str += word_len;
+                       if (word_len <= space) {
+                               space -= word_len;
+                       }
+                       if (space > 0) {
+                               fprintf(stderr, " ");
+                               space--;
                        }
-                       desc += strspn(desc, " \n\t");
+               } else {
+                       fprintf(stderr, "\n%*s", (int)indent, "");
+                       space = avail;
                }
+               str += strspn(str, " \n\t");
+       }
+}
+
+/**
+ * Print an entry's description, with a given indent.
+ *
+ * The indent is assumed to already be applied for the first line of the
+ * output by the caller.
+ *
+ * \param[in] entry   The entry to print the description for.
+ * \param[in] indent  The number of spaces to pad the left margin with.
+ */
+static void cli__print_description(const struct cli_table_entry *entry,
+               size_t indent)
+{
+       if (entry->d != NULL) {
+               cli__print_wrapping_string(entry->d, indent);
        }
 
        fprintf(stderr, "\n");
+
+       if (entry->t == CLI_ENUM) {
+               size_t max_len = 0;
+
+               for (const struct cli_str_val *e = entry->v.e.desc;
+                               e->str != NULL; e++) {
+                       size_t len = strlen(e->str);
+                       if (max_len < len) {
+                               max_len = len;
+                       }
+               }
+
+               fprintf(stderr, "\n");
+
+               for (const struct cli_str_val *e = entry->v.e.desc;
+                               e->str != NULL; e++) {
+                       fprintf(stderr, "        ");
+
+                       if (e->d == NULL || e->d[0] == '\0') {
+                               fprintf(stderr, "%s\n",
+                                               e->str);
+                       } else {
+                               fprintf(stderr, "%-*s - ",
+                                               (int)(max_len),
+                                               e->str);
+                               cli__print_wrapping_string(e->d,
+                                               8 + max_len + 3);
+                               fprintf(stderr, "\n");
+                       }
+               }
+       }
 }
 
 /* Documented in cli.h */
@@ -679,6 +737,12 @@ void cli_help(const struct cli_table *cli, const char 
*prog_name)
 
        cli__count(cli, &count, &pcount, &max_len, &pmax_len, &phas_desc);
 
+       if (cli->d != NULL) {
+               fprintf(stderr, "\n");
+               cli__print_wrapping_string(cli->d, 0);
+               fprintf(stderr, "\n");
+       }
+
        fprintf(stderr, "\nUsage: %s", prog_name);
 
        if (pcount > 0) {
diff --git a/test/cli.h b/test/cli.h
index 91db086..ffcd272 100644
--- a/test/cli.h
+++ b/test/cli.h
@@ -1,7 +1,7 @@
 /*
  * SPDX-License-Identifier: ISC
  *
- * Copyright (C) 2021 Michael Drake <[email protected]>
+ * Copyright (C) 2021-2022 Michael Drake <[email protected]>
  */
 
 /**
@@ -34,13 +34,16 @@ enum cli_arg_type {
        CLI_STRING, /**< Has string value. */
 };
 
+/** Enum value descriptor. */
 struct cli_str_val {
-       const char *str;
-       int64_t val;
+       const char *str; /**< String for the enum value name. */
+       int64_t val;     /**< The value for this string. */
+       const char *d;   /**< Description of this value for help output. */
 };
 
+/** Enum data. */
 struct cli_enum {
-       const struct cli_str_val *desc;
+       const struct cli_str_val *desc; /**< Array describing enum values. */
        int64_t *e; /**< Location to store \ref CLI_ENUM value. */
 };
 
@@ -51,15 +54,16 @@ struct cli_table_entry {
        const char *l; /**< Long argument name. */
        const char  s; /**< Short flag name. (Non-positional arguments.) */
        bool p; /**< Whether the argument is a positional argument. */
+       bool no_pos; /**< When present, no positional arguments are required. */
        enum cli_arg_type t; /**< Argument type. */
        union {
                bool *b;        /**< Location to store \ref CLI_BOOL value. */
                int64_t *i;     /**< Location to store \ref CLI_INT value. */
                uint64_t *u;    /**< Location to store \ref CLI_UINT value. */
                const char **s; /**< Location to store \ref CLI_STRING value. */
-               struct cli_enum e;
+               struct cli_enum e; /**< \ref CLI_ENUM value details. */
        } v; /**< Where to store type-specific values. */
-       const char *d; /**< Description. */
+       const char *d; /**< Description of this argument for help output. */
 };
 
 /**
@@ -69,6 +73,7 @@ struct cli_table {
        const struct cli_table_entry *entries;
        size_t count;
        size_t min_positional;
+       const char *d; /**< Description of this application for help output. */
 };
 
 /**
diff --git a/test/nsgif.c b/test/nsgif.c
index 7d61504..f873bab 100644
--- a/test/nsgif.c
+++ b/test/nsgif.c
@@ -29,15 +29,17 @@ static struct nsgif_options {
        uint64_t loops;
        bool palette;
        bool info;
+       bool help;
 } nsgif_options;
 
 static const struct cli_table_entry cli_entries[] = {
        {
-               .s = 'm',
-               .l = "ppm",
-               .t = CLI_STRING,
-               .v.s = &nsgif_options.ppm,
-               .d = "Convert frames to PPM image at given path."
+               .s = 'h',
+               .l = "help",
+               .t = CLI_BOOL,
+               .no_pos = true,
+               .v.b = &nsgif_options.help,
+               .d = "Print this text.",
        },
        {
                .s = 'i',
@@ -55,6 +57,13 @@ static const struct cli_table_entry cli_entries[] = {
                     "The default is 1."
        },
        {
+               .s = 'm',
+               .l = "ppm",
+               .t = CLI_STRING,
+               .v.s = &nsgif_options.ppm,
+               .d = "Convert frames to PPM image at given path."
+       },
+       {
                .s = 'p',
                .l = "palette",
                .t = CLI_BOOL,
@@ -74,6 +83,7 @@ const struct cli_table cli = {
        .entries = cli_entries,
        .count = (sizeof(cli_entries))/(sizeof(*cli_entries)),
        .min_positional = 1,
+       .d = "NSGIF - A utility for inspecting and decoding GIFs with libnsgif",
 };
 
 static void *bitmap_create(int width, int height)
@@ -357,6 +367,11 @@ int main(int argc, char *argv[])
                return EXIT_FAILURE;
        }
 
+       if (nsgif_options.help) {
+               cli_help(&cli, argv[0]);
+               return EXIT_SUCCESS;
+       }
+
        if (nsgif_options.ppm != NULL) {
                ppm = fopen(nsgif_options.ppm, "w+");
                if (ppm == NULL) {


-- 
NetSurf GIF Decoder
_______________________________________________
netsurf-commits mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to