Hi all,
I hope it's the right place to propose a patch. (I tried to register an
account on https://savannah.gnu.org/account/register.php but I cannot
beyond that page due to http://savannah.gnu.org/support/?108658 )
find in attachement a patch for a function ($md5 ) that compute the md5
checksum string of the arguments.
It can be used to create filenames.
My sources are also available at https://github.com/lindenb/make/compare/md5
I've added a test, two sources md5.c and md5.h, updated the manual,
Makefile.am, ...
The original MD5 code comes from
http://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/lxr/source/src/util/md5.cpp
released in the public domain.
$ cat Makefile
SRC=file.c load.c
$(md5 ${SRC}): ${SRC}
echo $@
$ make
echo 6102b17725943449a8a77bf6cf05e023
6102b17725943449a8a77bf6cf05e023
$ echo -n "file.c load.c" | md5sum
6102b17725943449a8a77bf6cf05e023 -
Pierre L
diff --git a/Makefile.am b/Makefile.am
index d2451b8..5ab1893 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -41,7 +41,7 @@ endif
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c \
function.c getopt.c getopt1.c guile.c implicit.c job.c load.c \
- loadapi.c main.c misc.c output.c read.c remake.c rule.c \
+ loadapi.c main.c md5.c misc.c output.c read.c remake.c rule.c \
signame.c strcache.c variable.c version.c vpath.c hash.c \
$(remote)
diff --git a/Makefile.ami b/Makefile.ami
index 7c561a3..07acc6b 100644
--- a/Makefile.ami
+++ b/Makefile.ami
@@ -119,10 +119,10 @@ CTAGS = ctags -w
#guile = guile.o
-objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \
- rule.o implicit.o default.o variable.o expand.o function.o \
- vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \
- remote-$(REMOTE).o $(GETOPT) $(ALLOCA) $(extras) $(guile)
+objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \
+ rule.o implicit.o default.o variable.o expand.o function.o \
+ vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \
+ md5.o remote-$(REMOTE).o $(GETOPT) $(ALLOCA) $(extras) $(guile)
srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
$(srcdir)file.c $(srcdir)getloadavg.c $(srcdir)misc.c \
@@ -130,7 +130,7 @@ srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
$(srcdir)rule.c $(srcdir)implicit.c $(srcdir)default.c \
$(srcdir)variable.c $(srcdir)expand.c $(srcdir)function.c \
$(srcdir)vpath.c $(srcdir)version.c $(srcdir)hash.c \
- $(srcdir)guile.c $(srcdir)remote-$(REMOTE).c \
+ $(srcdir)guile.c $(srcdir)md5.c $(srcdir)remote-$(REMOTE).c \
$(srcdir)ar.c $(srcdir)arscan.c $(srcdir)strcache.c \
$(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \
$(srcdir)commands.h $(srcdir)dep.h $(srcdir)filedep.h \
@@ -306,3 +306,4 @@ getopt.o: getopt.c
getopt1.o : getopt1.c getopt.h
getloadavg.o: getloadavg.c
amiga.o: amiga.c makeint.h variable.h amiga.h
+md5.o: md5.c md5.h
diff --git a/SMakefile.template b/SMakefile.template
index 4af89ae..2c04c97 100644
--- a/SMakefile.template
+++ b/SMakefile.template
@@ -128,7 +128,7 @@ CTAGS = ctags -w
objs = commands.o job.o dir.o file.o misc.o main.o read.o remake.o \
rule.o implicit.o default.o variable.o expand.o function.o \
vpath.o version.o ar.o arscan.o signame.o strcache.o hash.o \
- output.o remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) \
+ output.o md5.o remote-$(REMOTE).o $(GLOB) $(GETOPT) $(ALLOCA) \
$(extras) $(guile)
srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
@@ -142,7 +142,7 @@ srcs = $(srcdir)commands.c $(srcdir)job.c $(srcdir)dir.c \
$(srcdir)signame.c $(srcdir)signame.h $(GETOPT_SRC) \
$(srcdir)commands.h $(srcdir)dep.h $(srcdir)file.h \
$(srcdir)job.h $(srcdir)makeint.h $(srcdir)rule.h \
- $(srcdir)output.c $(srcdir)output.h \
+ $(srcdir)output.c $(srcdir)output.h $(srcdir)md5.c \
$(srcdir)variable.h $(ALLOCA_SRC) $(srcdir)config.h.in
diff --git a/doc/make.texi b/doc/make.texi
index b0f5af7..19a2b85 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -6991,6 +6991,23 @@ Replacing the variable reference @w{@samp{$(needs_made)}} with the
function call @w{@samp{$(strip $(needs_made))}} in the @code{ifneq}
directive would make it more robust.@refill
+
+@item $(md5 @var{string})
+@cindex md5
+@cindex checksum
+@cindex md5sum
+@cindex hash
+@findex md5
+Computes the MD5 sum of the words in @var{string}.
+
+The function @code{md5} can be useful to generate filenames.
+
+@example
+SRC=file.c load.c
+$(md5 ${SRC}): ${SRC}
+ touch $@@
+@end example
+
@item $(findstring @var{find},@var{in})
@findex findstring
@cindex searching for strings
@@ -11798,6 +11815,10 @@ Replace words matching @var{pattern} with @var{replacement} in @var{text}.@*
Remove excess whitespace characters from @var{string}.@*
@xref{Text Functions, , Functions for String Substitution and Analysis}.
+@item $(md5 @var{string})
+compute the md5 checksums in @var{string}.@*
+@xref{Text Functions, , Functions for String Substitution and Analysis}.
+
@item $(findstring @var{find},@var{text})
Locate @var{find} in @var{text}.@*
@xref{Text Functions, , Functions for String Substitution and Analysis}.
diff --git a/function.c b/function.c
index 169c3a1..850cbab 100644
--- a/function.c
+++ b/function.c
@@ -21,6 +21,7 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#include "job.h"
#include "commands.h"
#include "debug.h"
+#include "md5.h"
#ifdef _AMIGA
#include "amiga.h"
@@ -452,6 +453,33 @@ func_join (char *o, char **argv, const char *funcname UNUSED)
static char *
+func_md5 (char *o, char **argv, const char *funcname UNUSED)
+{
+ const char *list_iterator = argv[0];
+ unsigned char digest[16];
+ const char *p;
+ unsigned int i,len, n=0;
+ CMD5* md5ptr = CMD5New();
+
+ while ((p = find_next_token (&list_iterator, &len)) != 0)
+ {
+ if( n > 0 ) CMD5Update(md5ptr," ",1);
+ CMD5Update(md5ptr,p,len);
+ ++n;
+ }
+ CMD5Finalize(md5ptr,digest);
+ for(i=0;i< 16;++i)
+ {
+ char tmp[3];
+ sprintf(tmp, "%02x", digest[i]);
+ o = variable_buffer_output (o, tmp,2);
+ }
+
+ free(md5ptr);
+ return o;
+}
+
+static char *
func_origin (char *o, char **argv, const char *funcname UNUSED)
{
/* Expand the argument. */
@@ -2281,6 +2309,7 @@ static struct function_table_entry function_table_init[] =
FT_ENTRY ("flavor", 0, 1, 1, func_flavor),
FT_ENTRY ("join", 2, 2, 1, func_join),
FT_ENTRY ("lastword", 0, 1, 1, func_lastword),
+ FT_ENTRY ("md5", 0, 1, 1, func_md5),
FT_ENTRY ("patsubst", 3, 3, 1, func_patsubst),
FT_ENTRY ("realpath", 0, 1, 1, func_realpath),
FT_ENTRY ("shell", 0, 1, 1, func_shell),
diff --git a/md5.c b/md5.c
new file mode 100644
index 0000000..0790ee7
--- /dev/null
+++ b/md5.c
@@ -0,0 +1,271 @@
+/* MD5 for GNU make
+
+This file is part of GNU Make.
+
+GNU Make 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.
+
+GNU Make 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/>.
+
+Orignal C++ code from Aaron Ucko / NCBI(National Center for Biotechnology Information) /Public Domain
+Converted back to C by Pierre Lindenbaum
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include "makeint.h"
+#include "md5.h"
+
+
+
+#ifdef __BIG_ENDIAN__
+static void s_ByteReverse(unsigned char* buf, size_t longs)
+ {
+ uint32_t t;
+ do {
+ t = (uint32_t ) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *((uint32_t*)(buf)) = t;
+ buf += 4;
+ } while (--longs);
+ }
+#endif
+
+
+
+// The four core functions - F1 is optimized somewhat
+
+// #define F1(x, y, z) (x & y | ~x & z)
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((z & x) | (~z & y))
+#define F3(x, y, z) (x ^ (y ^ z))
+#define F4(x, y, z) (y ^ (x | ~z))
+
+// This is the central step in the MD5 algorithm.
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+// The core of the MD5 algorithm, this alters an existing MD5 hash to
+// reflect the addition of 16 longwords of new data. MD5Update blocks
+// the data and converts bytes into longwords for this routine.
+static
+void CMD5Transform(CMD5* ptr)
+{
+ uint32_t a, b, c, d;
+ uint32_t* inw = (uint32_t*)(ptr->m_In);
+
+ a = ptr->m_Buf[0];
+ b = ptr->m_Buf[1];
+ c = ptr->m_Buf[2];
+ d = ptr->m_Buf[3];
+
+ MD5STEP(F1, a, b, c, d, inw[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, inw[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, inw[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, inw[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, inw[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, inw[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, inw[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, inw[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, inw[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, inw[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, inw[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, inw[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, inw[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, inw[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, inw[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, inw[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, inw[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, inw[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, inw[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, inw[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, inw[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, inw[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, inw[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, inw[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, inw[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, inw[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, inw[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, inw[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, inw[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, inw[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, inw[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, inw[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, inw[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, inw[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, inw[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, inw[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, inw[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, inw[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, inw[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, inw[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, inw[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, inw[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, inw[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, inw[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, inw[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, inw[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, inw[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, inw[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, inw[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, inw[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, inw[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, inw[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, inw[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, inw[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, inw[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, inw[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, inw[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, inw[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, inw[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, inw[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, inw[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, inw[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, inw[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, inw[9] + 0xeb86d391, 21);
+
+ ptr->m_Buf[0] += a;
+ ptr->m_Buf[1] += b;
+ ptr->m_Buf[2] += c;
+ ptr->m_Buf[3] += d;
+}
+
+
+
+// Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+// initialization constants.
+CMD5* CMD5New(void)
+{
+ CMD5* p = (CMD5*)xmalloc(sizeof(CMD5));
+ p->m_Bits = 0;
+ p->m_Buf[0] = 0x67452301;
+ p->m_Buf[1] = 0xefcdab89;
+ p->m_Buf[2] = 0x98badcfe;
+ p->m_Buf[3] = 0x10325476;
+ p->m_Finalized = 0;
+ return p;
+}
+
+
+// Update state to reflect the concatenation of another buffer full of bytes.
+void CMD5Update(CMD5* ptr,const char* buf, size_t length)
+{
+ unsigned int tmp;
+ if ( ptr->m_Finalized )
+ {
+ O (fatal, NILF, _("attempt to update a finalized MD5 instance"));
+ }
+
+ // Number of leftover bytes in m_In
+ tmp = (unsigned int)((ptr->m_Bits >> 3) % (sizeof(ptr->m_In)) );
+
+ // Update bit count
+ ptr->m_Bits += length << 3;
+
+ // Handle any leading odd-sized chunks
+ if ( tmp )
+ {
+ unsigned char* p = ptr->m_In + tmp;
+
+ tmp = kBlockSize - tmp;
+ if (length < tmp)
+ {
+ memcpy(p, buf, length);
+ return;
+ }
+ memcpy(p, buf, tmp);
+ #ifdef __BIG_ENDIAN__
+ s_ByteReverse(ptr->m_In, 16);
+ #endif
+ CMD5Transform(ptr);
+ buf += tmp;
+ length -= tmp;
+ }
+
+ // Process remaining data in kBlockSize-byte chunks
+ while (length >= kBlockSize)
+ {
+ memcpy(ptr->m_In, buf, kBlockSize);
+ #ifdef __BIG_ENDIAN__
+ s_ByteReversep->(ptr->m_In, 16);
+ #endif
+ CMD5Transform(ptr);
+ buf += kBlockSize;
+ length -= kBlockSize;
+ }
+
+ // Handle any remaining bytes of data
+ memcpy(ptr->m_In, buf, length);
+}
+
+
+// Final wrapup - pad to kBlockSize-byte boundary with the bit pattern
+// 1 0* (64-bit count of bits processed, MSB-first).
+void CMD5Finalize(CMD5* ptr,unsigned char digest[16])
+{
+ int count;
+ unsigned char *p;
+ if ( ptr->m_Finalized )
+ {
+ memcpy(digest, ptr->m_Buf, 16);
+ return;
+ }
+
+ // Compute number of bytes mod kBlockSize
+ count = (int)((ptr->m_Bits >> 3) % kBlockSize);
+
+ // Set the first char of padding to 0x80. This is safe since there is
+ // always at least one byte free.
+ p = ptr->m_In + count;
+ *p++ = 0x80;
+
+ // Bytes of padding needed to make kBlockSize bytes
+ count = kBlockSize - 1 - count;
+
+ // Pad out to 56 mod kBlockSize
+ if (count < 8)
+ {
+ // Two lots of padding: Pad the first block to kBlockSize bytes
+ memset(p, 0, count);
+ #ifdef __BIG_ENDIAN__
+ s_ByteReverse(ptr->m_In, 16);
+ #endif
+ CMD5Transform(ptr);
+
+ // Now fill the next block with 56 bytes
+ memset(ptr->m_In, 0, kBlockSize - 8);
+ }
+ else
+ {
+ // Pad block to 56 bytes
+ memset(p, 0, count - 8);
+ #ifdef __BIG_ENDIAN__
+ s_ByteReverse(ptr->m_In, 14);
+ #endif
+ }
+
+ // Append length in bits and transform
+ ((uint32_t*)ptr->m_In)[14] = (uint32_t)(ptr->m_Bits);
+ ((uint32_t*)ptr->m_In)[15] = (uint32_t)(ptr->m_Bits >> 32);
+
+ CMD5Transform(ptr);
+ #ifdef __BIG_ENDIAN__
+ s_ByteReverse((unsigned char*)(ptr->m_Buf), 4);
+ #endif
+ memcpy(digest, ptr->m_Buf, 16);
+ memset(ptr->m_In, 0, kBlockSize); // may be sensitive
+ ptr->m_Finalized = 1;
+ }
+
diff --git a/md5.h b/md5.h
new file mode 100644
index 0000000..5046e1f
--- /dev/null
+++ b/md5.h
@@ -0,0 +1,41 @@
+/* MD5 for GNU make
+Copyright (C) 2013-2015 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make 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.
+
+GNU Make 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/>. */
+
+#ifndef MAKE_MD5_H
+#define MAKE_MD5_H
+#include <stddef.h>
+
+
+ // Block size defined by algorithm;
+#define kBlockSize ((int)64)
+
+/* struct for computing Message Digest version 5 checksums */
+typedef struct CMD5_t
+ {
+ uint32_t m_Buf[4];
+ int64_t m_Bits; // must be a 64-bit count
+ unsigned char m_In[kBlockSize];
+ int m_Finalized;
+ } CMD5;
+
+/* create a new CMD5 */
+CMD5* CMD5New(void);
+/* Update state to reflect the concatenation of another buffer full of bytes. */
+void CMD5Update(CMD5* ptr,const char* buf, size_t length);
+/* // Final wrapup - pad to kBlockSize-byte boundary with the bit pattern */
+void CMD5Finalize(CMD5* ptr,unsigned char digest[16]);
+
+#endif
diff --git a/tests/scripts/functions/md5 b/tests/scripts/functions/md5
new file mode 100644
index 0000000..db13db8
--- /dev/null
+++ b/tests/scripts/functions/md5
@@ -0,0 +1,44 @@
+$description = "The following test creates a makefile to test the md5 "
+ ."function.";
+
+$details = "";
+
+# IF YOU NEED >1 MAKEFILE FOR THIS TEST, USE &get_tmpfile; TO GET
+# THE NAME OF THE MAKEFILE. THIS INSURES CONSISTENCY AND KEEPS TRACK OF
+# HOW MANY MAKEFILES EXIST FOR EASY DELETION AT THE END.
+# EXAMPLE: $makefile2 = &get_tmpfile;
+
+
+open(MAKEFILE,"> $makefile");
+
+# The Contents of the MAKEFILE ...
+
+print MAKEFILE "string := \$(md5 A 12345) \n"
+ ."all: \n"
+ ."\t\@echo \$(string) \n";
+
+# END of Contents of MAKEFILE
+
+close(MAKEFILE);
+
+&run_make_with_options($makefile,"",&get_logfile,0);
+
+# Create the answer to what should be produced by this Makefile
+$answer = "2cbf53c02fc13ff6f3dfc4621c2e2455\n";
+
+# COMPARE RESULTS
+
+# In this call to compare output, you should use the call &get_logfile(1)
+# to send the name of the last logfile created. You may also use
+# the special call &get_logfile(1) which returns the same as &get_logfile(1).
+
+&compare_output($answer,&get_logfile(1));
+
+# This tells the test driver that the perl test script executed properly.
+1;
+
+
+
+
+
+
_______________________________________________
Help-make mailing list
Help-make@gnu.org
https://lists.gnu.org/mailman/listinfo/help-make