bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] argv-iter: new module


From: Jim Meyering
Subject: [PATCH] argv-iter: new module
Date: Sat, 04 Jul 2009 17:38:22 +0200

FYI, I've just moved the argv-iter module and its tests from coreutils/gl
into gnulib, because I'm teaching mkid and xtokid (from the GNU idutils
package) the --files0-from option, so that package will also use this module.

>From 675fbd30d44edd7ecfca9e9013424b187eb3db70 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Sat, 4 Jul 2009 16:44:19 +0200
Subject: [PATCH] argv-iter: new module

* MODULES.html.sh: Add argv-iter.
* lib/argv-iter.c, lib/argv-iter.h: New files.
* modules/argv-iter: New file.
* modules/argv-iter-tests: New file.
* tests/test-argv-iter.c: Test it.
---
 ChangeLog               |    9 ++++
 MODULES.html.sh         |    1 +
 lib/argv-iter.c         |  111 +++++++++++++++++++++++++++++++++++++++++++++
 lib/argv-iter.h         |   47 +++++++++++++++++++
 modules/argv-iter       |   24 ++++++++++
 modules/argv-iter-tests |   10 ++++
 tests/test-argv-iter.c  |  114 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 316 insertions(+), 0 deletions(-)
 create mode 100644 lib/argv-iter.c
 create mode 100644 lib/argv-iter.h
 create mode 100644 modules/argv-iter
 create mode 100644 modules/argv-iter-tests
 create mode 100644 tests/test-argv-iter.c

diff --git a/ChangeLog b/ChangeLog
index 2531307..1dc20c0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2009-07-04  Jim Meyering  <address@hidden>
+
+       argv-iter: new module
+       * MODULES.html.sh: Add argv-iter.
+       * lib/argv-iter.c, lib/argv-iter.h: New files.
+       * modules/argv-iter: New file.
+       * modules/argv-iter-tests: New file.
+       * tests/test-argv-iter.c: Test it.
+
 2009-07-04  Bruno Haible  <address@hidden>

        Fix assertion.
diff --git a/MODULES.html.sh b/MODULES.html.sh
index f74b724..6adef20 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -1869,6 +1869,7 @@ func_all_modules ()

   func_begin_table
   func_module argmatch
+  func_module argv-iter
   func_module version-etc
   func_module version-etc-fsf
   func_module long-options
diff --git a/lib/argv-iter.c b/lib/argv-iter.c
new file mode 100644
index 0000000..05b06ef
--- /dev/null
+++ b/lib/argv-iter.c
@@ -0,0 +1,111 @@
+/* Iterate over arguments from argv or --files0-from=FILE
+   Copyright (C) 2008-2009 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Written by Jim Meyering.  */
+
+#include <config.h>
+#include "argv-iter.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct argv_iterator
+{
+  /* Test FP to determine whether in read-mode or argv-mode. */
+  /* file-mode: fp records position */
+  FILE *fp;
+  size_t item_idx;
+  char *tok;
+  size_t buf_len;
+
+  /* argv-mode: record just argv and current pointer */
+  char **arg_list;
+  char **p;
+};
+
+struct argv_iterator *
+argv_iter_init_argv (char **argv)
+{
+  struct argv_iterator *ai = malloc (sizeof *ai);
+  if (!ai)
+    return NULL;
+  ai->fp = NULL;
+  ai->arg_list = argv;
+  ai->p = argv;
+  return ai;
+}
+
+/* Initialize to read from the stream, FP.
+   The input is expected to contain a list of NUL-delimited tokens.  */
+struct argv_iterator *
+argv_iter_init_stream (FILE *fp)
+{
+  struct argv_iterator *ai = malloc (sizeof *ai);
+  if (!ai)
+    return NULL;
+  ai->fp = fp;
+  ai->tok = NULL;
+  ai->buf_len = 0;
+
+  ai->item_idx = 0;
+  ai->arg_list = NULL;
+  return ai;
+}
+
+char *
+argv_iter (struct argv_iterator *ai, enum argv_iter_err *err)
+{
+  if (ai->fp)
+    {
+      ssize_t len = getdelim (&ai->tok, &ai->buf_len, '\0', ai->fp);
+      if (len < 0)
+        {
+          *err = feof (ai->fp) ? AI_ERR_EOF : AI_ERR_READ;
+          return NULL;
+        }
+
+      *err = AI_ERR_OK;
+      ai->item_idx++;
+      return ai->tok;
+    }
+  else
+    {
+      if (*(ai->p) == NULL)
+        {
+          *err = AI_ERR_EOF;
+          return NULL;
+        }
+      else
+        {
+          *err = AI_ERR_OK;
+          return *(ai->p++);
+        }
+    }
+}
+
+size_t
+argv_iter_n_args (struct argv_iterator const *ai)
+{
+  return ai->fp ? ai->item_idx : ai->p - ai->arg_list;
+}
+
+void
+argv_iter_free (struct argv_iterator *ai)
+{
+  if (ai->fp)
+    free (ai->tok);
+  free (ai);
+}
diff --git a/lib/argv-iter.h b/lib/argv-iter.h
new file mode 100644
index 0000000..537fb1e
--- /dev/null
+++ b/lib/argv-iter.h
@@ -0,0 +1,47 @@
+/* Iterate over arguments from argv or --files0-from=FILE
+   Copyright (C) 2008-2009 Free Software Foundation, Inc.
+
+   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/>.  */
+
+#include <stdio.h>
+#include <stdbool.h>
+
+struct argv_iterator;
+enum argv_iter_err;
+
+#undef _ATTRIBUTE_NONNULL_
+#if __GNUC__ == 3 && __GNUC_MINOR__ >= 3 || 3 < __GNUC__
+# define _ATTRIBUTE_NONNULL_(m) __attribute__ ((__nonnull__ (m)))
+#else
+# define _ATTRIBUTE_NONNULL_(m)
+#endif
+
+enum argv_iter_err
+{
+  AI_ERR_OK = 1,
+  AI_ERR_EOF,
+  AI_ERR_MEM,
+  AI_ERR_READ
+};
+
+struct argv_iterator *argv_iter_init_argv (char **argv)
+  _ATTRIBUTE_NONNULL_ (1);
+struct argv_iterator *argv_iter_init_stream (FILE *fp)
+  _ATTRIBUTE_NONNULL_ (1);
+char *argv_iter (struct argv_iterator *, enum argv_iter_err *)
+  _ATTRIBUTE_NONNULL_ (1) _ATTRIBUTE_NONNULL_ (2);
+size_t argv_iter_n_args (struct argv_iterator const *)
+  _ATTRIBUTE_NONNULL_ (1);
+void argv_iter_free (struct argv_iterator *)
+  _ATTRIBUTE_NONNULL_ (1);
diff --git a/modules/argv-iter b/modules/argv-iter
new file mode 100644
index 0000000..e9fc633
--- /dev/null
+++ b/modules/argv-iter
@@ -0,0 +1,24 @@
+Description:
+iterate through argv or a --files0-from=-specified file
+
+Files:
+lib/argv-iter.c
+lib/argv-iter.h
+
+Depends-on:
+getdelim
+stdbool
+
+configure.ac:
+
+Makefile.am:
+lib_SOURCES += argv-iter.c argv-iter.h
+
+Include:
+"argv-iter.h"
+
+License
+GPL
+
+Maintainer:
+Jim Meyering
diff --git a/modules/argv-iter-tests b/modules/argv-iter-tests
new file mode 100644
index 0000000..af0405b
--- /dev/null
+++ b/modules/argv-iter-tests
@@ -0,0 +1,10 @@
+Files:
+tests/test-argv-iter.c
+
+Depends-on:
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-argv-iter
+check_PROGRAMS += test-argv-iter
diff --git a/tests/test-argv-iter.c b/tests/test-argv-iter.c
new file mode 100644
index 0000000..7682c4a
--- /dev/null
+++ b/tests/test-argv-iter.c
@@ -0,0 +1,114 @@
+/* Test argv iterator
+   Copyright (C) 2008-2009 Free Software Foundation, Inc.
+
+   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/>.  */
+
+/* Written by Jim Meyering.  */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+#define ASSERT(expr) \
+  do                                                                         \
+    {                                                                        \
+      if (!(expr))                                                           \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
+    }                                                                        \
+  while (0)
+
+#include "argv-iter.h"
+
+static FILE *
+write_nul_delimited_argv (char **argv)
+{
+  FILE *fp = tmpfile ();
+  ASSERT (fp);
+  while (*argv)
+    {
+      size_t len = strlen (*argv) + 1;
+      ASSERT (fwrite (*argv, len, 1, fp) == 1);
+      argv++;
+    }
+  ASSERT (fflush (fp) == 0);
+  rewind (fp);
+  return fp;
+}
+
+int
+main ()
+{
+  /* set_program_name (argv[0]); placate overzealous "syntax-check" test.  */
+  static char *av[][4] = {
+    {NULL},
+    {"1", NULL},
+    {"1", "2", NULL},
+    {"1", "2", "3", NULL}
+  };
+
+  int use_stream;
+  for (use_stream = 0; use_stream < 2; use_stream++)
+    {
+      size_t i;
+      for (i = 0; i < ARRAY_CARDINALITY (av); i++)
+        {
+          FILE *fp;
+          struct argv_iterator *ai;
+          size_t n_found = 0;
+          if (use_stream)
+            {
+              /* Generate an identical list to be read via FP.  */
+              ASSERT ((fp = write_nul_delimited_argv (av[i])) != NULL);
+              ai = argv_iter_init_stream (fp);
+            }
+          else
+            {
+              fp = NULL;
+              ai = argv_iter_init_argv (av[i]);
+            }
+          ASSERT (ai);
+
+          while (1)
+            {
+              enum argv_iter_err ai_err;
+              char *s = argv_iter (ai, &ai_err);
+              ASSERT ((i == n_found) == (ai_err == AI_ERR_EOF));
+              ASSERT ((s == NULL) ^ (ai_err == AI_ERR_OK));
+              ASSERT (ai_err == AI_ERR_OK || ai_err == AI_ERR_EOF);
+              if (ai_err == AI_ERR_OK)
+                ++n_found;
+              if (ai_err == AI_ERR_EOF)
+                break;
+              /* In stream mode, the strings are equal, but
+                 in argv mode the actual pointers are equal.  */
+              ASSERT (use_stream
+                      ? STREQ (s, av[i][n_found - 1])
+                      : s == av[i][n_found - 1]);
+            }
+          ASSERT (argv_iter_n_args (ai) == i);
+          argv_iter_free (ai);
+          if (fp)
+            ASSERT (fclose (fp) == 0);
+        }
+    }
+
+  return 0;
+}
--
1.6.3.3.507.gc6b5a




reply via email to

[Prev in Thread] Current Thread [Next in Thread]