]> git.draconx.ca Git - dxcommon.git/commitdiff
Add "md5" detection macro.
authorNick Bowler <nbowler@draconx.ca>
Wed, 22 Sep 2021 00:39:39 +0000 (20:39 -0400)
committerNick Bowler <nbowler@draconx.ca>
Wed, 22 Sep 2021 00:39:39 +0000 (20:39 -0400)
This macro locates a program that can be used to compute MD5 digests
from shell scripts.  Many systems have such a program, but there are
a handful of variations in the wild.

m4/md5.m4 [new file with mode: 0644]
t/md5.sh [new file with mode: 0755]
tests/programs.at

diff --git a/m4/md5.m4 b/m4/md5.m4
new file mode 100644 (file)
index 0000000..ee95794
--- /dev/null
+++ b/m4/md5.m4
@@ -0,0 +1,65 @@
+dnl Copyright © 2021 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_PROG_MD5
+dnl
+dnl Search PATH for a command-line md5 digest utility, such as GNU md5sum,
+dnl FreeBSD md5 or openssl md5.  If found, the MD5 variable (which is
+dnl substituted by AC_SUBST) is set to the result and the cache variable
+dnl dx_cv_md5_works is set to "yes".  Otherwise, dx_cv_md5_works is set to
+dnl "no".
+dnl
+dnl The utilities that can be found have slightly different options and
+dnl output formats.  For example, GNU md5sum prints each line with the
+dnl digest followed by the filename, whereas openssl md5 prints the filename
+dnl followed by the digest.  The MD5 setting will include the -r option, when
+dnl supported, to prefer a command that prints the digest first as this is
+dnl easier to parse by shell code.  The cache variable dx_cv_md5_outpos will
+dnl be set to "front" if the digest appears at the beginning of the line,
+dnl and "back" if the digest appears at the end of the line.  Portable usage
+dnl should handle both scenarios.
+AC_DEFUN([DX_PROG_MD5], [AC_PREREQ([2.62])dnl
+AC_ARG_VAR([MD5], [MD5 digest command])dnl
+eval ': >conftest.in'
+AC_CACHE_CHECK([for utility to compute MD5 digests], [ac_cv_path_MD5],
+[dx_cv_md5_found=:
+AC_PATH_PROGS_FEATURE_CHECK([MD5], [md5sum md5 openssl],
+[DX_BASENAME([md5_relcmd], ["$ac_path_MD5"])
+set x '-r' ''; shift
+AS_CASE([$md5_relcmd], [openssl], [ac_path_MD5="$ac_path_MD5 md5"],
+                       [md5sum], [shift])
+eval ': >conftest.in'
+for md5_arg
+do
+_DX_MD5_DO_TEST([$ac_path_MD5 $md5_arg],
+  [ac_path_MD5="$ac_path_MD5 $md5_arg"; break])
+done
+AS_IF([test x"$dx_cv_md5_works" = x"yes"],
+[md5_bypath=`{ command -v "$md5_relcmd"; } 2>/dev/null` #''
+ac_cv_path_MD5=$ac_path_MD5
+set x $ac_path_MD5; shift
+if test x"$md5_bypath" = x"$[1]"; then
+  shift; set x $md5_relcmd "$[@]"; shift;
+  ac_cv_path_MD5=$[*]
+fi
+ac_path_MD5_found=:])], [ac_cv_path_MD5='none found' dx_cv_md5_found=false])])
+AS_IF([$dx_cv_md5_found],
+[MD5=$ac_cv_path_MD5
+AC_CACHE_CHECK([for $MD5 digest position], [dx_cv_md5_outpos],
+[_DX_MD5_DO_TEST([$MD5])])])
+rm -f conftest.in conftest.out])
+
+AC_DEFUN([_DX_MD5_DO_TEST],
+[AS_IF([$1 conftest.in >conftest.out],
+[read a b <conftest.out
+AS_IF([test x"$a" = x"d41d8cd98f00b204e9800998ecf8427e"],
+  [dx_cv_md5_works=yes dx_cv_md5_outpos=front
+$2],
+[set x $b; shift; eval "a=\$$[#]"
+AS_IF([test x"$a" = x"d41d8cd98f00b204e9800998ecf8427e"],
+  [dx_cv_md5_works=yes dx_cv_md5_outpos=back
+$2], [dx_cv_md5_works=no dx_cv_md5_outpos='not found'])])],
+[dx_cv_md5_works=no dx_cv_md5_outpos='not found'])])
diff --git a/t/md5.sh b/t/md5.sh
new file mode 100755 (executable)
index 0000000..0f3395e
--- /dev/null
+++ b/t/md5.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# Copyright © 2021 Nick Bowler
+#
+# Fake md5sum-like program for testing the md5 detection macro.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+: "${MD5_NO_R=}"
+: "${MD5_HASH=d41d8cd98f00b204e9800998ecf8427e}"
+: "${MD5_DIRECTION=forward}"
+
+stdin=true
+
+print_hash () {
+  case $MD5_DIRECTION in
+  forward) printf '%s  %s\n' "$MD5_HASH" "$1" ;;
+  reverse) printf '%s = %s\n' "$1" "$MD5_HASH" ;;
+  *) printf 'invalid direction %s\n' "$MD5_DIRECTION" 1>&2; exit 1 ;;
+  esac
+}
+
+for arg
+do
+  case $arg in
+  -r)
+    test x"$MD5_NO_R" = x"" || exit
+    MD5_DIRECTION=forward
+    continue ;;
+  md5)
+    continue ;;
+  esac
+
+  stdin=false
+  print_hash $arg
+done
+
+if $stdin; then
+  cat >/dev/null
+  print_hash stdin
+fi
index 5460b5ccd5dc7cf9b676edcc6995db0af3196aa3..90262ef458a819a57afb313ed48243efcde2aaa6 100644 (file)
@@ -6,6 +6,18 @@ dnl There is NO WARRANTY, to the extent permitted by law.
 
 AT_BANNER([Program tests])
 
+dnl TEST_PATH_LOOKUP(var, program, [abspath=`pwd`/bin])
+dnl
+dnl If "command -v program" returns abspath/program, then set var=program.
+dnl Otherwise, set var=abspath/program.  This helps compute the expected
+dnl program name from path lookups as certain older shells (e.g., Solaris
+dnl 10 /bin/sh) do not implement "command".
+m4_define([TEST_PATH_LOOKUP],
+[AS_VAR_SET([$1], [$2])
+val=`$TEST_SHELL -c 'command -v $2'`
+AS_IF([test x"$val" != x"m4_default([$3], [`pwd`/bin])/$2"],
+  [AS_VAR_SET([$1], [m4_default([$3], [`pwd`/bin])/$2])])])
+
 m4_define([TEST_SIMPLE_PROGRAM_PROBES],
   [TEST_SIMPLE_PROGRAM_PROBES_([$1], m4_toupper($1))])
 m4_define([TEST_SIMPLE_PROGRAM_PROBES_],
@@ -39,12 +51,7 @@ TEST_AUTORECONF
 save_PATH=$PATH
 PATH=`pwd`/bin${PATH:+":$PATH"}
 
-# Sanity test on PATH lookup; configure will substitute absolute path if
-# "command" does not work (e.g., heirloom-sh).
-expected=$1
-val=`$TEST_SHELL -c 'command -v $1'`
-test x"$val" = x"`pwd`/bin/$1" || expected=`pwd`/bin/$1
-
+TEST_PATH_LOOKUP([expected], [$1])
 TEST_CONFIGURE
 AT_CHECK_UNQUOTED([cat test], [0], [yes
 $expected
@@ -99,3 +106,72 @@ AT_CLEANUP
 TEST_SIMPLE_PROGRAM_PROBES([gob2])
 TEST_SIMPLE_PROGRAM_PROBES([flex])
 TEST_SIMPLE_PROGRAM_PROBES([bison])
+
+AT_SETUP([md5 probes])
+AT_KEYWORDS([DX_PROG_MD5 program])
+AT_CAPTURE_FILE([config.log])
+
+mkdir bin
+cp -P "$srcdir/t/md5.sh" bin/md5sum
+
+AT_DATA([test.in],
+[[MD5=@MD5@
+dx_cv_md5_works=@dx_cv_md5_works@
+dx_cv_md5_outpos=@dx_cv_md5_outpos@
+]])
+
+TEST_CONFIGURE_AC([[DX_PROG_MD5
+AC_SUBST([dx_cv_md5_works])
+AC_SUBST([dx_cv_md5_outpos])
+
+set x conftest*; shift
+if test -f $[]1; then
+  AC_MSG_ERROR([$[]1 left behind by [D@@&t@&t@X_PROG_MD5]])
+fi
+
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+
+# Check the search via path lookup
+save_PATH=$PATH
+PATH=`pwd`/bin${PATH:+":$PATH"}
+
+TEST_PATH_LOOKUP([expected], [md5sum])
+TEST_CONFIGURE
+AT_CHECK_UNQUOTED([cat test], [0], [MD5=$expected
+dx_cv_md5_works=yes
+dx_cv_md5_outpos=front
+])
+
+mv bin/md5sum bin/md5
+TEST_PATH_LOOKUP([expected], [md5])
+TEST_CONFIGURE([MD5_DIRECTION=reverse])
+AT_CHECK_UNQUOTED([cat test], [0], [MD5=$expected -r
+dx_cv_md5_works=yes
+dx_cv_md5_outpos=front
+])
+
+mv bin/md5 bin/openssl
+TEST_PATH_LOOKUP([expected], [openssl])
+TEST_CONFIGURE([MD5_DIRECTION=reverse MD5_NO_R=true])
+AT_CHECK_UNQUOTED([cat test], [0], [MD5=$expected md5
+dx_cv_md5_works=yes
+dx_cv_md5_outpos=back
+])
+
+PATH=$save_PATH
+
+# Check the search via user override
+TEST_CONFIGURE([MD5_DIRECTION=reverse MD5="$srcdir/t/md5.sh"])
+AT_CHECK_UNQUOTED([cat test], [0], [MD5=$srcdir/t/md5.sh
+dx_cv_md5_works=yes
+dx_cv_md5_outpos=back
+])
+
+# Check that a bogus program doesn't come back as valid.
+TEST_CONFIGURE([MD5=true])
+AT_CHECK([grep dx_cv_md5_works test], [0], [dx_cv_md5_works=no
+])
+
+AT_CLEANUP