summaryrefslogtreecommitdiff
path: root/gphoto-m4/gp-set.m4
diff options
context:
space:
mode:
Diffstat (limited to 'gphoto-m4/gp-set.m4')
-rw-r--r--gphoto-m4/gp-set.m4725
1 files changed, 725 insertions, 0 deletions
diff --git a/gphoto-m4/gp-set.m4 b/gphoto-m4/gp-set.m4
new file mode 100644
index 000000000..0168a263d
--- /dev/null
+++ b/gphoto-m4/gp-set.m4
@@ -0,0 +1,725 @@
+dnl ######################################################################
+dnl Set operations using shell
+dnl ######################################################################
+dnl
+dnl This implements a set of set operations ('set' in the sense of
+dnl 'set theory') as shell code for use at configure time. At m4 time
+dnl (aka autoreconf time), there already exists a set of m4_set_*
+dnl macros, but we cannot use those for user specified and
+dnl autodetected changes at configure time.
+dnl
+dnl Not all set operations are implemented, but a few basic ones we
+dnl need for gp-camlibs.m4 are.
+dnl
+dnl * Basic definitions:
+dnl
+dnl * GP_SET_DEFINE
+dnl * GP_SET_UNDEFINE
+dnl
+dnl * Operations on sets:
+dnl
+dnl * GP_SET_ADD
+dnl * GP_SET_ADD_ALL
+dnl * GP_SET_REMOVE
+dnl
+dnl * GP_SET_CARDINALITY
+dnl * GP_SET_DIFFERENCE
+dnl * GP_SET_UNION
+dnl
+dnl * GP_SET_FOREACH
+dnl
+dnl * Conditionals:
+dnl
+dnl * GP_SET_CONTAINS_IFELSE
+dnl * GP_SET_EMPTY_IFELSE
+dnl * GP_SET_EQUAL_IFELSE
+dnl
+dnl * GP_SET_CLEAN_FILES
+dnl
+dnl * Internals and debugging help:
+dnl
+dnl * GP_SET_CANONICALIZE
+dnl * GP_SET_DUMP_ALL
+dnl * GP_SET_TESTSUITE
+dnl
+dnl * Fill shell variables with set contents:
+dnl
+dnl * GP_SET_DEBUG_VAR
+dnl * GP_SET_SPACE_VAR
+dnl
+dnl * Output AC_MSG_* for GP_SET_* sets:
+dnl
+dnl * GP_SET_DEBUG_MSG
+dnl * GP_SET_MSG_DEBUG_RESULT
+dnl
+dnl * GP_SET_SPACE_MSG
+dnl * GP_SET_MSG_SPACE_RESULT
+dnl
+dnl ######################################################################
+dnl Remarks on usage and implementation of GP_SET_*
+dnl
+dnl * Sets are stored in text files, one element per line. An empty
+dnl file is an empty set, and empty lines mean empty elements.
+dnl Non-empty files not ending with a newline are undefined behaviour.
+dnl
+dnl * At this time, GP_SET_* functions work with set elements
+dnl consisting of a limited set of characters, but the storage
+dnl format allows for a future code cleanup to allow for handling
+dnl more arbitrarily called elements.
+dnl
+dnl * Set names given to GP_SET_ macros must be defined at m4
+dnl (autoreconf) time, not at sh (configure) time.
+dnl
+dnl * Every set must be declared before use with GP_SET_DEFINE so we
+dnl can create an empty file for them and keep track of the name of
+dnl that file for cleaning up later.
+dnl
+dnl * Use GP_SET_CLEAN_FILES after your last set operations to remove
+dnl all left over set files.
+dnl
+dnl * Set text files may contain set elements in any order, and in
+dnl any number. There is no difference between a set text file
+dnl containing the same line seven times and one which only contains
+dnl it one time.
+dnl
+dnl * Some set operations work better or require on sorted files, so
+dnl sometimes the implementation sorts the set text files. If you
+dnl need a set text file sorted for some another reason, use
+dnl GP_SET_CANONICALIZE([set-name]).
+dnl
+dnl
+dnl ######################################################################
+dnl
+dnl FIXME: Do we need to test ${COMM} works before using it?
+dnl FIXME: Do we need a sh-based replacement for ${COMM} if it is not present?
+dnl FIXME: Abort if _DIFFERENCE is called with ${COMM} not found/not working.
+dnl FIXME: Do we need to stop using shell functions?
+dnl
+dnl
+dnl ######################################################################
+dnl Try catching unexpanded macros in the output.
+dnl ######################################################################
+m4_pattern_forbid([GP_SET_])dnl
+m4_pattern_forbid([_GP_SET_])dnl
+m4_pattern_allow([GP_SET_EOF])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_INIT
+dnl Called internally before any set operation.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_INIT], [dnl
+AC_REQUIRE([AC_PROG_GREP])dnl
+AC_REQUIRE([GP_PROG_COMM])dnl
+AC_REQUIRE([GP_PROG_SORT])dnl
+AC_REQUIRE([GP_PROG_UNIQ])dnl
+m4_set_empty([gp_set_all_sets], [], [dnl
+ m4_set_foreach([gp_set_all_sets], [elt], [dnl
+ m4_errprintn(__file__: __line__:[ Set gp_set_all_sets contains element ]elt)dnl
+ ])dnl
+ m4_errprintn(__file__:__line__:[ Error: gp_set_all_sets already defined])dnl
+ dnl m4_exit(1)dnl
+])dnl
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_FILENAME([set_name])
+dnl _GP_SET_FILENAME([set_name], [extra-extension])
+dnl Convert set name to set file name. If present, add the given
+dnl extra-extension to the file name in some position.
+dnl ######################################################################
+AC_DEFUN([_GP_SET_FILENAME], [dnl
+[gp-set-file--][$1]m4_if([$2],[],[],[.$2])])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_CHECK_INIT
+dnl Implement the gp_set_shfn_check() shell function which checks that the
+dnl given set exists and is in general working order.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_CHECK_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+gp_set_shfn_check ()
+{
+ if test -f "[$]1"; then :; else
+ AC_MSG_ERROR(["Error: set [$]1 has not been defined yet"])
+ fi
+} # gp_set_shfn_check
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_CHECK([set_name])
+dnl Check that the given set exists and is in general working order.
+dnl Works by calling the gp_set_shfn_check() shell function.
+dnl ######################################################################
+AC_DEFUN([_GP_SET_CHECK], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
+gp_set_shfn_check "_GP_SET_FILENAME([$1])"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_DUMP_ALL
+dnl Dump all sets to stdout. Intended for helping with debugging.
+dnl ######################################################################
+AC_DEFUN([GP_SET_DUMP_ALL], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+for setfile in gp-set-file--*
+do
+ AS_ECHO(["Set file: ${setfile}"])
+ ${SED} 's/^/ * <</; s/$/>>/' "${setfile}"
+done
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_DEFINE([set_name])
+dnl Declare a set of given name, initializing it to an empty set.
+dnl Not a shell function, as the emitted shell code is shorter than
+dnl calling a shell function.
+dnl ######################################################################
+AC_DEFUN([GP_SET_DEFINE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+m4_set_add([gp_set_all_sets], [$1])dnl
+: > "_GP_SET_FILENAME([$1])"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_UNDEFINE([set_name])
+dnl Undefine a set of given name, removing its file.
+dnl Not a shell function, as the emitted shell code is shorter than
+dnl calling a shell function.
+dnl ######################################################################
+AC_DEFUN([GP_SET_UNDEFINE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+_GP_SET_CHECK([$1])dnl
+rm -f "_GP_SET_FILENAME([$1])"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_ADD_INIT
+dnl Implement the gp_set_shfn_set_add() shell function which adds a given
+dnl element to a given set.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_ADD_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
+gp_set_shfn_set_add ()
+{
+ gp_set_shfn_check "[$]1"
+ AS_ECHO(["[$]2"]) >> "[$]1"
+} # gp_set_shfn_set_add
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_ADD([set_name], [element])
+dnl Add the given element to the given set. Implemented by calling the
+dnl gp_set_shfn_set_add() shell function.
+dnl Note: Unlike m4_set_add, this does not handle IF-UNIQ and IF-DUP
+dnl macro parameters.
+dnl ######################################################################
+AC_DEFUN([GP_SET_ADD], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_ADD_INIT])dnl
+gp_set_shfn_set_add "_GP_SET_FILENAME([$1])" "$2"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_ADD_ALL([set_name], [element]...)
+dnl Add the given elements to the given set, similar to m4_set_add_all.
+dnl This can be very useful for initializing a GP_SET_* set from a
+dnl m4_set_* in one go.
+dnl Not a shell function, as the emitted shell code is shorter than
+dnl calling a shell function.
+dnl ######################################################################
+AC_DEFUN([GP_SET_ADD_ALL], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+_GP_SET_CHECK([$1])dnl
+cat>>"_GP_SET_FILENAME([$1])"<<_GP_EOF
+m4_foreach([myvar], [m4_shift($@)], [dnl
+myvar
+])dnl
+_GP_EOF
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_REMOVE_INIT
+dnl Implement the gp_set_shfn_remove() shell function removing a given
+dnl element from a given set.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_REMOVE_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+gp_set_shfn_remove ()
+{
+ gp_set_shfn_check "[$]1"
+ ${GREP} -v "^[$]2$" < "[$]1" > "[$]1.tmp"
+ mv -f "[$]1.tmp" "[$]1"
+} # gp_set_shfn_remove
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_REMOVE([set_name], [element])
+dnl Remove a given element from a given set.
+dnl Calls the gp_set_shfn_remove() shell function for the actual work.
+dnl ######################################################################
+AC_DEFUN([GP_SET_REMOVE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_REMOVE_INIT])dnl
+gp_set_shfn_remove "_GP_SET_FILENAME([$1])" "$2"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_UNION_INIT
+dnl Define the gp_set_shfn_union() shell function which defines a
+dnl result set as the union of 0 or more sets.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_UNION_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+dnl This functions uses the shell builtin 'shift', so it needs to store
+dnl the original $1 in a local variable.
+gp_set_shfn_union ()
+{
+ local result_fname="[$]1"
+ gp_set_shfn_check "[$]result_fname"
+ if shift; then
+ cat "[$]@" > "[$]{result_fname}.tmp"
+ mv -f "[$]{result_fname}.tmp" "[$]{result_fname}"
+ fi
+} # gp_set_shfn_union
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_UNION([result_set], [setname]...)
+dnl Define result_set as the union of 0 or more setnames.
+dnl Calls the gp_set_shfn_union() shell function for the actual work.
+dnl ######################################################################
+AC_DEFUN([GP_SET_UNION], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_UNION_INIT])dnl
+m4_set_add([gp_set_all_sets], [$1])dnl
+gp_set_shfn_union m4_foreach([setname], [$@], [ "_GP_SET_FILENAME(setname)"])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_DIFFERENCE_INIT([result_set_fname], [set_fname]...)
+dnl This uses comm(1), which is a POSIX command. We can always
+dnl re-implement comm(1) with a lot of speed penalties in a bunch
+dnl of nested sh loops if we run into a system which does not have
+dnl comm(1) installed.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_DIFFERENCE_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_CHECK_INIT])dnl
+AC_REQUIRE([_GP_SET_CANONICALIZE_INIT])dnl
+dnl This functions uses the shell builtin 'shift', so it needs to store
+dnl the original $1 and $2 in local variables.
+gp_set_shfn_difference ()
+{
+ local result_fname="[$]1"
+ gp_set_shfn_check "[$]result_fname"
+ if shift; then
+ gp_set_shfn_canonicalize "[$]1"
+ cat "[$]1" > "[$]result_fname"
+ if shift; then
+ for gp_s
+ do
+ gp_set_shfn_canonicalize "[$]gp_s"
+ ${COMM} -23 "[$]{result_fname}" "[$]gp_s" > "[$]{result_fname}.tmp"
+ mv -f "[$]{result_fname}.tmp" "[$]{result_fname}"
+ done
+ fi
+ fi
+} # gp_set_shfn_difference
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_DIFFERENCE([result_set], [setname]...)
+dnl Define result_set as the first setname with the element of all
+dnl the other sets removed from it.
+dnl ######################################################################
+AC_DEFUN([GP_SET_DIFFERENCE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_DIFFERENCE_INIT])dnl
+m4_set_add([gp_set_all_sets], [$1])dnl
+gp_set_shfn_difference m4_foreach([setname], [$@], [ "_GP_SET_FILENAME(setname)"])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_CARDINALITY_INIT
+dnl Define gp_set_shfn_cardinality() shell function which writes
+dnl set cardinality to stdout.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_CARDINALITY_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+gp_set_shfn_cardinality ()
+{
+ gp_set_shfn_check "[$]1"
+ wc -l < "[$]1"
+} # gp_set_shfn_cardinality
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_CARDINALITY([set_name])
+dnl Write set cardinality to stdout.
+dnl ######################################################################
+AC_DEFUN([GP_SET_CARDINALITY], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_CARDINALITY_INIT])dnl
+gp_set_shfn_cardinality "_GP_SET_FILENAME([$1])"])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_EMPTY_IFELSE([set_name], [if-empty], [if-not-empty])
+dnl Run if-empty block or if-not-empty block, depending on whether
+dnl the named set is empty or not.
+dnl ######################################################################
+AC_DEFUN([GP_SET_EMPTY_IFELSE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+_GP_SET_CHECK([$1])dnl
+AS_IF([test "0" -eq "$(wc -l < "_GP_SET_FILENAME([$1])")"], m4_shift($@))
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_EQUAL_IFELSE([set_a], [set_b], [if-equal], [if-not-equal])
+dnl When set_a and set_b are equal, run the if-equal block. Otherwise,
+dnl run the if-not-equal block.
+dnl ######################################################################
+AC_DEFUN([GP_SET_EQUAL_IFELSE], [dnl
+gp_set_shfn_canonicalize "_GP_SET_FILENAME([$1])"
+gp_set_shfn_canonicalize "_GP_SET_FILENAME([$2])"
+AS_IF([${CMP} "_GP_SET_FILENAME([$1])" "_GP_SET_FILENAME([$2])" > /dev/null 2>&1],
+ m4_shift2($@))
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_CONTAINS_IFELSE([set_name], [element], [yes-block], [no-block])
+dnl If set_name contains element, run the yes-block. Otherwise,
+dnl run the no-block.
+dnl ######################################################################
+AC_DEFUN([GP_SET_CONTAINS_IFELSE], [dnl
+_GP_SET_CHECK([$1])dnl
+AS_IF([test "0" -lt "$(${GREP} -c "^$2\$" < "_GP_SET_FILENAME([$1])")"],
+ m4_shift2($@))
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_DEBUG_VAR_INIT
+dnl Define gp_set_shfn_debug_var() shell function which sets a shell
+dnl variable to a string representing a human readable form for of
+dnl the given set.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_DEBUG_VAR_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+gp_set_shfn_debug_var ()
+{
+ gp_set_shfn_check "[$]1"
+ gp_set_shfn_canonicalize "[$]1"
+ local element
+ local gp_set_is_first=:
+ local gp_set_saved_ifs="$IFS"
+ IFS=""
+ while read element
+ do
+ if "$gp_set_is_first"
+ then
+ eval "[$]2=\"{ \""
+ gp_set_is_first=false
+ else
+ eval "[$]2=\"\${[$]2}, \""
+ fi
+ if test "x$element" = "x"
+ then
+ eval "[$]2=\"\${[$]2}''\""
+ else
+ eval "[$]2=\"\${[$]2}'\$element'\""
+ fi
+ done < "[$]1"
+ IFS="$gp_set_saved_ifs"
+ if "$gp_set_is_first"
+ then
+ eval "[$]2=\"{ }\""
+ else
+ eval "[$]2=\"\${[$]2} }\""
+ fi
+} # gp_set_shfn_debug_var
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_DEBUG_VAR([set_name], [shell_var_name])
+dnl Set shell variable shell_var_name to a string representing a human
+dnl readable for of the given set.
+dnl ######################################################################
+AC_DEFUN([GP_SET_DEBUG_VAR], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_DEBUG_VAR_INIT])dnl
+gp_set_shfn_debug_var "_GP_SET_FILENAME([$1])" "$2"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_DEBUG_MSG([set-name])
+dnl For a given set, expand to a simple pair of AC_MSG_CHECKING and
+dnl AC_MSG_RESULT showing the GP_SET_DEBUG_VAR, mostly to help with
+dnl debugging.
+dnl ######################################################################
+AC_DEFUN([GP_SET_DEBUG_MSG], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_MSG_CHECKING([value of set ]$1)
+GP_SET_MSG_DEBUG_RESULT([$1])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_SPACE_MSG([set-name])
+dnl For a given set, expand to a simple pair of AC_MSG_CHECKING and
+dnl AC_MSG_RESULT showing the GP_SET_SPACE_VAR, both to help with
+dnl debugging gp-set.m4 and possibly for produnction use.
+dnl ######################################################################
+AC_DEFUN([GP_SET_MSG], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_MSG_CHECKING([value of set ]$1)
+GP_SET_MSG_RESULT([$1])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_SPACE_VAR([set-name], [var-name])
+dnl ######################################################################
+AC_DEFUN([GP_SET_SPACE_VAR], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+$2=""
+GP_SET_FOREACH([$1], [element], [dnl
+AS_IF([test "x[$]$2" = "x"], [dnl
+ $2="[$]element"
+], [dnl
+ $2="[$]$2 [$]element"
+])
+])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_MSG_RESULT([set-name])
+dnl Shortcut for setting a shell variable to a space separated list of
+dnl elements, and then expanding to AC_MSG_RESULT([$shellvar]).
+dnl ######################################################################
+AC_DEFUN([GP_SET_MSG_RESULT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+GP_SET_SPACE_VAR([$1], [gp_set_msg_result_var])dnl
+AC_MSG_RESULT([${gp_set_msg_result_var}])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_MSG_DEBUG_RESULT([set-name])
+dnl Shortcut for setting a shell variable to a human readable list of
+dnl elements, and then expanding to AC_MSG_RESULT([$shellvar]).
+dnl ######################################################################
+AC_DEFUN([GP_SET_MSG_DEBUG_RESULT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+GP_SET_DEBUG_VAR([$1], [gp_set_msg_result_var])dnl
+AC_MSG_RESULT([${gp_set_msg_result_var}])
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl _GP_SET_CANONICALIZE_INIT
+dnl Implement the gp_set_shfn_canonicalize() shell function.
+dnl ######################################################################
+AC_DEFUN_ONCE([_GP_SET_CANONICALIZE_INIT], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+gp_set_shfn_canonicalize ()
+{
+ gp_set_shfn_check "[$]1"
+ { set -e
+ [$]{SORT} < "[$]1" | [$]{UNIQ} > "[$]1.tmp"
+ mv -f "[$]1.tmp" "[$]1"; }
+} # gp_set_shfn_canonicalize
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_CANONICALIZE([set_name])
+dnl Convert the set file for set_name into a canonical form.
+dnl
+dnl Implementation detail: Sorts the lines, and makes them unique.
+dnl ######################################################################
+AC_DEFUN([GP_SET_CANONICALIZE], [dnl
+AC_REQUIRE([_GP_SET_INIT])dnl
+AC_REQUIRE([_GP_SET_CANONICALIZE_INIT])dnl
+gp_set_shfn_canonicalize "_GP_SET_FILENAME([$1])"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_FOREACH([set_name], [shell-var], [shell-block])
+dnl For each element in set_name, run the shell-block with the given
+dnl shell variable set to every element in turn.
+dnl ######################################################################
+AC_DEFUN([GP_SET_FOREACH], [dnl
+_GP_SET_CHECK([$1])dnl
+gp_set_saved_ifs="$IFS"
+IFS=""
+while read $2
+do
+ IFS="$gp_set_saved_ifs"
+ $3
+done < "_GP_SET_FILENAME([$1])"
+IFS="$gp_set_saved_ifs"
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_CLEAN_FILES
+dnl Remove all the files used for storing sets. Invoke this macro near
+dnl the end of configure.ac after you have finished doing anything with
+dnl GP_SET_* sets.
+dnl ######################################################################
+AC_DEFUN([GP_SET_CLEAN_FILES], [dnl
+AC_BEFORE([_GP_SET_INIT], [$0])dnl
+AC_BEFORE([GP_SET_DEFINE], [$0])dnl
+AC_BEFORE([GP_SET_UNDEFINE], [$0])dnl
+AC_BEFORE([GP_SET_ADD], [$0])dnl
+AC_BEFORE([GP_SET_ADD_ALL], [$0])dnl
+AC_BEFORE([GP_SET_REMOVE], [$0])dnl
+AC_BEFORE([GP_SET_EMPTY_IFELSE], [$0])dnl
+AC_BEFORE([GP_SET_EQUAL_IFELSE], [$0])dnl
+AC_BEFORE([GP_SET_CONTAINS_IFELSE], [$0])dnl
+AC_BEFORE([GP_SET_DEBUG_VAR], [$0])dnl
+AC_BEFORE([GP_SET_SPACE_VAR], [$0])dnl
+dnl
+dnl GP_SET_DUMP_ALL()dnl
+dnl
+dnl m4_set_foreach([gp_set_all_sets], [set_name], [dnl
+dnl AS_ECHO(["Set defined somewhere: set_name"])
+dnl ])dnl
+dnl
+[rm -f]m4_set_foreach([gp_set_all_sets], [setname],
+ [ "_GP_SET_FILENAME(setname)"])dnl
+])dnl
+dnl
+dnl
+dnl ######################################################################
+dnl GP_SET_TESTSUITE()
+dnl Does a number of tests for the GP_SET_* macros.
+dnl
+dnl Should be mostly useful while debugging gp-set.m4 itself.
+dnl ######################################################################
+AC_DEFUN([GP_SET_TESTSUITE], [dnl
+# BEGIN $0
+_GP_SET_INIT
+
+GP_SET_DEFINE([foo])
+GP_SET_DEFINE([bar])
+GP_SET_DEFINE([foobar])
+GP_SET_DEFINE([everything])
+
+GP_SET_DEBUG_MSG([foo])
+
+GP_SET_DEFINE([bax])
+GP_SET_UNDEFINE([bax])
+
+GP_SET_UNDEFINE([bar])
+GP_SET_DEFINE([bar])
+
+dnl GP_SET_ADD([moo], [meh])
+GP_SET_ADD_ALL([everything], [foo], [bar], [bar ], [bla])
+
+GP_SET_DUMP_ALL
+
+m4_set_add_all([m4testset], [a], [b c], [d e], [f], [g])
+AC_MSG_CHECKING([for value of m4 testset])
+AC_MSG_RESULT([m4_set_contents([m4testset], [, ])])
+
+GP_SET_ADD_ALL([everything]m4_set_listc([m4testset]))
+
+GP_SET_DUMP_ALL
+
+GP_SET_ADD([foo], [barfoo])
+GP_SET_ADD([foo], [foobar])
+GP_SET_ADD([foo], [fox])
+GP_SET_ADD([foo], [fux])
+GP_SET_ADD([foo], [fox])
+GP_SET_ADD([foo], [])
+GP_SET_ADD([foo], [fox])
+GP_SET_ADD([foo], [barfoo])
+GP_SET_ADD([foo], [ barfoo])
+GP_SET_ADD([foo], ["barfoo "])
+GP_SET_ADD([foo], [])
+GP_SET_REMOVE([foo], [fox])
+GP_SET_ADD([foo], [barfoo])
+
+GP_SET_ADD([foobar], [bar])
+GP_SET_ADD([foobar], [foobar])
+GP_SET_ADD([foobar], [barfoo])
+
+GP_SET_DEBUG_MSG([foo])
+
+GP_SET_MSG([bar])
+GP_SET_MSG([foo])
+GP_SET_MSG([foobar])
+GP_SET_MSG([everything])
+
+GP_SET_DEFINE([union])
+GP_SET_UNION([union], [foo], [bar], [foobar])
+AC_MSG_CHECKING([value of union of foo bar foobar])
+GP_SET_MSG_RESULT([union])
+
+GP_SET_DEFINE([difference])
+GP_SET_DIFFERENCE([difference], [foo], [bar], [foobar])
+GP_SET_MSG([difference])
+
+AC_MSG_CHECKING([whether sets foo and bar are equal])
+GP_SET_EQUAL_IFELSE([foo], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+
+AC_MSG_CHECKING([whether set foo is empty])
+GP_SET_EMPTY_IFELSE([foo], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+
+AC_MSG_CHECKING([whether set bar is empty])
+GP_SET_EMPTY_IFELSE([bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+
+AC_MSG_CHECKING([whether set foo contains element bar])
+GP_SET_CONTAINS_IFELSE([foo], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+
+AC_MSG_CHECKING([whether set foobar contains element bar])
+GP_SET_CONTAINS_IFELSE([foobar], [bar], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])])
+
+GP_SET_FOREACH([foobar], [gp_set_var], [dnl
+ AC_MSG_CHECKING([foobar element])
+ AC_MSG_RESULT([${gp_set_var}])
+])dnl
+GP_SET_FOREACH([foobar], [gp_set_var], [dnl
+ AS_ECHO([" * element ${gp_set_var}"])
+])dnl
+GP_SET_FOREACH([foobar], [gp_set_var], [echo " * ELEMENT ${gp_set_var}"])dnl
+AS_ECHO(["Moo."])
+
+GP_SET_DUMP_ALL
+# END $0
+])dnl
+dnl
+dnl
+dnl ####################################################################
+dnl
+dnl Local Variables:
+dnl mode: autoconf
+dnl End: