Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package mmv for openSUSE:Factory checked in 
at 2024-07-08 19:08:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/mmv (Old)
 and      /work/SRC/openSUSE:Factory/.mmv.new.2080 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "mmv"

Mon Jul  8 19:08:22 2024 rev:22 rq:1186034 version:2.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/mmv/mmv.changes  2024-01-03 12:30:38.143854950 
+0100
+++ /work/SRC/openSUSE:Factory/.mmv.new.2080/mmv.changes        2024-07-08 
19:08:43.059743772 +0200
@@ -1,0 +2,8 @@
+Sat Jul  6 08:17:50 UTC 2024 - Andrea Manzini <[email protected]>
+
+- update to 2.6:
+  * This release re-adds the “mad” (“append”) command, and fixes how 
+    the program name is checked when deciding which mode to run in.
+  * There is also a build system fix.
+
+-------------------------------------------------------------------

Old:
----
  mmv-2.5.1.tar.gz

New:
----
  mmv-2.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ mmv.spec ++++++
--- /var/tmp/diff_new_pack.HHlkZs/_old  2024-07-08 19:08:43.695767033 +0200
+++ /var/tmp/diff_new_pack.HHlkZs/_new  2024-07-08 19:08:43.699767178 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package mmv
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           mmv
-Version:        2.5.1
+Version:        2.6
 Release:        0
 Summary:        Move/Copy/Append/Link Multiple Files by Wildcard Patterns
 License:        GPL-1.0-or-later

++++++ mmv-2.5.1.tar.gz -> mmv-2.6.tar.gz ++++++
++++ 1857 lines of diff (skipped)
++++    retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/Makefile.am new/mmv-2.6/Makefile.am
--- old/mmv-2.5.1/Makefile.am   2023-08-08 12:44:11.000000000 +0200
+++ new/mmv-2.6/Makefile.am     2024-02-09 16:13:51.000000000 +0100
@@ -33,7 +33,7 @@
 mmv_SOURCES = mmv.c cmdline.c cmdline.h
 mmv_LDADD = $(LDADD)
 
-SYMLINKS = mcp$(EXEEXT) mln$(EXEEXT)
+SYMLINKS = mcp$(EXEEXT) mln$(EXEEXT) mad$(EXEEXT)
 MAKELINKS = for n in $(SYMLINKS); do $(RM) $$n$(EXEEXT) && $(LN_S) 
mmv$(EXEEXT) $$n; done
 
 EXTRA_SRCS = opts.ggo
@@ -52,8 +52,8 @@
 
 mmv.o: cmdline.h
 
-cmdline.h cmdline.c: opts.ggo
-       gengetopt < opts.ggo --unamed-opts
+cmdline.h cmdline.c: $(top_srcdir)/opts.ggo
+       gengetopt < $(top_srcdir)/opts.ggo --unamed-opts
 
 all-local: mmv$(EXEEXT)
        $(MAKELINKS)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/cmdline.c new/mmv-2.6/cmdline.c
--- old/mmv-2.5.1/cmdline.c     2023-08-08 12:45:57.000000000 +0200
+++ new/mmv-2.6/cmdline.c       2024-02-09 16:14:38.000000000 +0100
@@ -25,7 +25,7 @@
 
 #include "cmdline.h"
 
-const char *gengetopt_args_info_purpose = "move/copy/link multiple files by 
wildcard patterns";
+const char *gengetopt_args_info_purpose = "move/copy/append/link multiple 
files by wildcard patterns";
 
 const char *gengetopt_args_info_usage = "Usage: " CMDLINE_PARSER_PACKAGE " 
[-m|-x|-r|-c|-o|-a|-l|-s] [-h] [-d|-p] [-g|-t] [-v|-n] FROM TO";
 
@@ -44,6 +44,7 @@
   "  -r, --rename     rename source to target in same directory",
   "  -c, --copy       copy source to target, preserving source permissions",
   "  -o, --overwrite  overwrite target with source, preserving target 
permissions",
+  "  -a, --append     append contents of source file to target",
   "  -l, --hardlink   link target name to source file",
   "  -s, --symlink    symlink target name to source file",
   "\n Group: delete\n  How to handle file deletions and overwrites",
@@ -87,6 +88,7 @@
   args_info->rename_given = 0 ;
   args_info->copy_given = 0 ;
   args_info->overwrite_given = 0 ;
+  args_info->append_given = 0 ;
   args_info->hardlink_given = 0 ;
   args_info->symlink_given = 0 ;
   args_info->force_given = 0 ;
@@ -124,14 +126,15 @@
   args_info->rename_help = gengetopt_args_info_help[7] ;
   args_info->copy_help = gengetopt_args_info_help[8] ;
   args_info->overwrite_help = gengetopt_args_info_help[9] ;
-  args_info->hardlink_help = gengetopt_args_info_help[10] ;
-  args_info->symlink_help = gengetopt_args_info_help[11] ;
-  args_info->force_help = gengetopt_args_info_help[13] ;
-  args_info->protect_help = gengetopt_args_info_help[14] ;
-  args_info->go_help = gengetopt_args_info_help[16] ;
-  args_info->terminate_help = gengetopt_args_info_help[17] ;
-  args_info->verbose_help = gengetopt_args_info_help[19] ;
-  args_info->dryrun_help = gengetopt_args_info_help[20] ;
+  args_info->append_help = gengetopt_args_info_help[10] ;
+  args_info->hardlink_help = gengetopt_args_info_help[11] ;
+  args_info->symlink_help = gengetopt_args_info_help[12] ;
+  args_info->force_help = gengetopt_args_info_help[14] ;
+  args_info->protect_help = gengetopt_args_info_help[15] ;
+  args_info->go_help = gengetopt_args_info_help[17] ;
+  args_info->terminate_help = gengetopt_args_info_help[18] ;
+  args_info->verbose_help = gengetopt_args_info_help[20] ;
+  args_info->dryrun_help = gengetopt_args_info_help[21] ;
   
 }
 
@@ -268,6 +271,8 @@
     write_into_file(outfile, "copy", 0, 0 );
   if (args_info->overwrite_given)
     write_into_file(outfile, "overwrite", 0, 0 );
+  if (args_info->append_given)
+    write_into_file(outfile, "append", 0, 0 );
   if (args_info->hardlink_given)
     write_into_file(outfile, "hardlink", 0, 0 );
   if (args_info->symlink_given)
@@ -366,6 +371,7 @@
   args_info->rename_given = 0 ;
   args_info->copy_given = 0 ;
   args_info->overwrite_given = 0 ;
+  args_info->append_given = 0 ;
   args_info->hardlink_given = 0 ;
   args_info->symlink_given = 0 ;
 
@@ -585,6 +591,7 @@
         { "rename",    0, NULL, 'r' },
         { "copy",      0, NULL, 'c' },
         { "overwrite", 0, NULL, 'o' },
+        { "append",    0, NULL, 'a' },
         { "hardlink",  0, NULL, 'l' },
         { "symlink",   0, NULL, 's' },
         { "force",     0, NULL, 'd' },
@@ -596,7 +603,7 @@
         { 0,  0, 0, 0 }
       };
 
-      c = getopt_long (argc, argv, "VhDmxrcolsdpgtvn", long_options, 
&option_index);
+      c = getopt_long (argc, argv, "VhDmxrcoalsdpgtvn", long_options, 
&option_index);
 
       if (c == -1) break;      /* Exit from `while (1)' loop.  */
 
@@ -701,6 +708,21 @@
               additional_error))
             goto failure;
         
+          break;
+        case 'a':      /* append contents of source file to target.  */
+        
+          if (args_info->mode_group_counter && override)
+            reset_group_mode (args_info);
+          args_info->mode_group_counter += 1;
+        
+          if (update_arg( 0 , 
+               0 , &(args_info->append_given),
+              &(local_args_info.append_given), optarg, 0, 0, ARG_NO,
+              check_ambiguity, override, 0, 0,
+              "append", 'a',
+              additional_error))
+            goto failure;
+        
           break;
         case 'l':      /* link target name to source file.  */
         
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/cmdline.h new/mmv-2.6/cmdline.h
--- old/mmv-2.5.1/cmdline.h     2023-08-08 12:45:57.000000000 +0200
+++ new/mmv-2.6/cmdline.h       2024-02-09 16:14:38.000000000 +0100
@@ -52,6 +52,7 @@
   const char *rename_help; /**< @brief rename source to target in same 
directory help description.  */
   const char *copy_help; /**< @brief copy source to target, preserving source 
permissions help description.  */
   const char *overwrite_help; /**< @brief overwrite target with source, 
preserving target permissions help description.  */
+  const char *append_help; /**< @brief append contents of source file to 
target help description.  */
   const char *hardlink_help; /**< @brief link target name to source file help 
description.  */
   const char *symlink_help; /**< @brief symlink target name to source file 
help description.  */
   const char *force_help; /**< @brief perform file deletes and overwrites 
without confirmation help description.  */
@@ -70,6 +71,7 @@
   unsigned int rename_given ;  /**< @brief Whether rename was given.  */
   unsigned int copy_given ;    /**< @brief Whether copy was given.  */
   unsigned int overwrite_given ;       /**< @brief Whether overwrite was 
given.  */
+  unsigned int append_given ;  /**< @brief Whether append was given.  */
   unsigned int hardlink_given ;        /**< @brief Whether hardlink was given. 
 */
   unsigned int symlink_given ; /**< @brief Whether symlink was given.  */
   unsigned int force_given ;   /**< @brief Whether force was given.  */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/config.h.in new/mmv-2.6/config.h.in
--- old/mmv-2.5.1/config.h.in   2023-08-08 13:08:18.000000000 +0200
+++ new/mmv-2.6/config.h.in     2024-02-09 16:14:34.000000000 +0100
@@ -70,6 +70,10 @@
 #undef GNULIB_CANONICALIZE_LGPL
 
 /* Define to a C preprocessor expression that evaluates to 1 or 0, depending
+   whether the gnulib module dirname shall be considered present. */
+#undef GNULIB_DIRNAME
+
+/* Define to a C preprocessor expression that evaluates to 1 or 0, depending
    whether the gnulib module fscanf shall be considered present. */
 #undef GNULIB_FSCANF
 
@@ -197,6 +201,12 @@
 /* Define to 1 when the gnulib module strerror should be tested. */
 #undef GNULIB_TEST_STRERROR
 
+/* Define to 1 when the gnulib module strndup should be tested. */
+#undef GNULIB_TEST_STRNDUP
+
+/* Define to 1 when the gnulib module strnlen should be tested. */
+#undef GNULIB_TEST_STRNLEN
+
 /* Define to 1 when the gnulib module symlink should be tested. */
 #undef GNULIB_TEST_SYMLINK
 
@@ -298,6 +308,14 @@
    don't. */
 #undef HAVE_DECL_STRERROR_R
 
+/* Define to 1 if you have the declaration of `strndup', and to 0 if you
+   don't. */
+#undef HAVE_DECL_STRNDUP
+
+/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
+   don't. */
+#undef HAVE_DECL_STRNLEN
+
 /* Define to 1 if you have the declaration of `wcsdup', and to 0 if you don't.
    */
 #undef HAVE_DECL_WCSDUP
@@ -488,6 +506,9 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
+/* Define to 1 if you have the `strndup' function. */
+#undef HAVE_STRNDUP
+
 /* Define to 1 if you have the `strnlen' function. */
 #undef HAVE_STRNLEN
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/configure.ac new/mmv-2.6/configure.ac
--- old/mmv-2.5.1/configure.ac  2023-08-08 13:05:25.000000000 +0200
+++ new/mmv-2.6/configure.ac    2024-02-09 16:11:58.000000000 +0100
@@ -20,7 +20,7 @@
 AC_PREREQ([2.71])
 
 dnl Initialise autoconf and automake
-AC_INIT([mmv],[2.5.1],[[email protected]],[],[https://github.com/rrthomas/mmv])
+AC_INIT([mmv],[2.6],[[email protected]],[],[https://github.com/rrthomas/mmv])
 AC_CONFIG_AUX_DIR([build-aux])
 AM_INIT_AUTOMAKE([-Wall])
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/Makefile.am new/mmv-2.6/lib/Makefile.am
--- old/mmv-2.5.1/lib/Makefile.am       2023-08-08 13:02:52.000000000 +0200
+++ new/mmv-2.6/lib/Makefile.am 2023-11-01 18:32:20.000000000 +0100
@@ -35,6 +35,7 @@
 #  binary-io \
 #  bootstrap \
 #  close \
+#  dirname \
 #  fprintf-posix \
 #  getopt-gnu \
 #  ignore-value \
@@ -166,6 +167,16 @@
 
 ## end   gnulib module close
 
+## begin gnulib module dirname
+
+libgnu_a_SOURCES += dirname.c basename.c
+
+EXTRA_DIST += stripslash.c
+
+EXTRA_libgnu_a_SOURCES += stripslash.c
+
+## end   gnulib module dirname
+
 ## begin gnulib module dirname-lgpl
 
 libgnu_a_SOURCES += dirname-lgpl.c stripslash.c
@@ -1759,6 +1770,24 @@
 
 ## end   gnulib module string
 
+## begin gnulib module strndup
+
+
+EXTRA_DIST += strndup.c
+
+EXTRA_libgnu_a_SOURCES += strndup.c
+
+## end   gnulib module strndup
+
+## begin gnulib module strnlen
+
+
+EXTRA_DIST += strnlen.c
+
+EXTRA_libgnu_a_SOURCES += strnlen.c
+
+## end   gnulib module strnlen
+
 ## begin gnulib module symlink
 
 
@@ -2324,6 +2353,12 @@
 
 ## end   gnulib module xsize
 
+## begin gnulib module xstrndup
+
+libgnu_a_SOURCES += xstrndup.h xstrndup.c
+
+## end   gnulib module xstrndup
+
 
 mostlyclean-local: mostlyclean-generic
        @for dir in '' $(MOSTLYCLEANDIRS); do \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/basename.c new/mmv-2.6/lib/basename.c
--- old/mmv-2.5.1/lib/basename.c        1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/basename.c  2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,58 @@
+/* basename.c -- return the last element in a file name
+
+   Copyright (C) 1990, 1998-2001, 2003-2006, 2009-2021 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "dirname.h"
+
+#include <string.h>
+#include "xalloc.h"
+#include "xstrndup.h"
+
+char *
+base_name (char const *name)
+{
+  char const *base = last_component (name);
+  size_t length;
+
+  /* If there is no last component, then name is a file system root or the
+     empty string.  */
+  if (! *base)
+    return xstrndup (name, base_len (name));
+
+  /* Collapse a sequence of trailing slashes into one.  */
+  length = base_len (base);
+  if (ISSLASH (base[length]))
+    length++;
+
+  /* On systems with drive letters, "a/b:c" must return "./b:c" rather
+     than "b:c" to avoid confusion with a drive letter.  On systems
+     with pure POSIX semantics, this is not an issue.  */
+  if (FILE_SYSTEM_PREFIX_LEN (base))
+    {
+      char *p = xmalloc (length + 3);
+      p[0] = '.';
+      p[1] = '/';
+      memcpy (p + 2, base, length);
+      p[length + 2] = '\0';
+      return p;
+    }
+
+  /* Finally, copy the basename.  */
+  return xstrndup (base, length);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/dirname.c new/mmv-2.6/lib/dirname.c
--- old/mmv-2.5.1/lib/dirname.c 1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/dirname.c   2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,38 @@
+/* dirname.c -- return all but the last element in a file name
+
+   Copyright (C) 1990, 1998, 2000-2001, 2003-2006, 2009-2021 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include "dirname.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "xalloc.h"
+
+/* Just like mdir_name (dirname-lgpl.c), except, rather than
+   returning NULL upon malloc failure, here, we report the
+   "memory exhausted" condition and exit.  */
+
+char *
+dir_name (char const *file)
+{
+  char *result = mdir_name (file);
+  if (!result)
+    xalloc_die ();
+  return result;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/strndup.c new/mmv-2.6/lib/strndup.c
--- old/mmv-2.5.1/lib/strndup.c 1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/strndup.c   2023-11-01 18:32:12.000000000 +0100
@@ -0,0 +1,36 @@
+/* A replacement function, for systems that lack strndup.
+
+   Copyright (C) 1996-1998, 2001-2003, 2005-2007, 2009-2021 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, 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <stdlib.h>
+
+char *
+strndup (char const *s, size_t n)
+{
+  size_t len = strnlen (s, n);
+  char *new = malloc (len + 1);
+
+  if (new == NULL)
+    return NULL;
+
+  new[len] = '\0';
+  return memcpy (new, s, len);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/strnlen.c new/mmv-2.6/lib/strnlen.c
--- old/mmv-2.5.1/lib/strnlen.c 1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/strnlen.c   2023-11-01 18:32:12.000000000 +0100
@@ -0,0 +1,30 @@
+/* Find the length of STRING, but scan at most MAXLEN characters.
+   Copyright (C) 2005-2007, 2009-2021 Free Software Foundation, Inc.
+   Written by Simon Josefsson.
+
+   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, 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#include <string.h>
+
+/* Find the length of STRING, but scan at most MAXLEN characters.
+   If no '\0' terminator is found in that many characters, return MAXLEN.  */
+
+size_t
+strnlen (const char *string, size_t maxlen)
+{
+  const char *end = memchr (string, '\0', maxlen);
+  return end ? (size_t) (end - string) : maxlen;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/xstrndup.c new/mmv-2.6/lib/xstrndup.c
--- old/mmv-2.5.1/lib/xstrndup.c        1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/xstrndup.c  2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,36 @@
+/* Duplicate a bounded initial segment of a string, with out-of-memory
+   checking.
+   Copyright (C) 2003, 2006-2007, 2009-2021 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 <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include "xstrndup.h"
+
+#include <string.h>
+#include "xalloc.h"
+
+/* Return a newly allocated copy of at most N bytes of STRING.
+   In other words, return a copy of the initial segment of length N of
+   STRING.  */
+char *
+xstrndup (const char *string, size_t n)
+{
+  char *s = strndup (string, n);
+  if (! s)
+    xalloc_die ();
+  return s;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/lib/xstrndup.h new/mmv-2.6/lib/xstrndup.h
--- old/mmv-2.5.1/lib/xstrndup.h        1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/lib/xstrndup.h  2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,23 @@
+/* Duplicate a bounded initial segment of a string, with out-of-memory
+   checking.
+   Copyright (C) 2003, 2009-2021 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 <https://www.gnu.org/licenses/>.  */
+
+#include <stddef.h>
+
+/* Return a newly allocated copy of at most N bytes of STRING.
+   In other words, return a copy of the initial segment of length N of
+   STRING.  */
+extern char *xstrndup (const char *string, size_t n) _GL_ATTRIBUTE_MALLOC;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/m4/gnulib-cache.m4 new/mmv-2.6/m4/gnulib-cache.m4
--- old/mmv-2.5.1/m4/gnulib-cache.m4    2023-08-08 13:03:25.000000000 +0200
+++ new/mmv-2.6/m4/gnulib-cache.m4      2023-11-01 18:32:20.000000000 +0100
@@ -40,6 +40,7 @@
 #  binary-io \
 #  bootstrap \
 #  close \
+#  dirname \
 #  fprintf-posix \
 #  getopt-gnu \
 #  ignore-value \
@@ -65,6 +66,7 @@
   binary-io
   bootstrap
   close
+  dirname
   fprintf-posix
   getopt-gnu
   ignore-value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/m4/gnulib-comp.m4 new/mmv-2.6/m4/gnulib-comp.m4
--- old/mmv-2.5.1/m4/gnulib-comp.m4     2023-08-08 13:02:53.000000000 +0200
+++ new/mmv-2.6/m4/gnulib-comp.m4       2023-11-01 18:32:22.000000000 +0100
@@ -54,6 +54,7 @@
   # Code from module chdir:
   # Code from module cloexec:
   # Code from module close:
+  # Code from module dirname:
   # Code from module dirname-lgpl:
   # Code from module double-slash-root:
   # Code from module dup2:
@@ -148,6 +149,8 @@
   # Code from module strerror:
   # Code from module strerror-override:
   # Code from module string:
+  # Code from module strndup:
+  # Code from module strnlen:
   # Code from module symlink:
   # Code from module sys_stat:
   # Code from module sys_types:
@@ -163,6 +166,7 @@
   # Code from module xalloc-die:
   # Code from module xalloc-oversized:
   # Code from module xsize:
+  # Code from module xstrndup:
 ])
 
 # This macro should be invoked from ./configure.ac, in the section
@@ -196,6 +200,7 @@
     AC_LIBOBJ([close])
   fi
   gl_UNISTD_MODULE_INDICATOR([close])
+  gl_MODULE_INDICATOR([dirname])
   gl_DOUBLE_SLASH_ROOT
   gl_FUNC_DUP2
   if test $REPLACE_DUP2 = 1; then
@@ -448,6 +453,17 @@
     gl_PREREQ_SYS_H_WINSOCK2
   fi
   gl_HEADER_STRING_H
+  gl_FUNC_STRNDUP
+  if test $HAVE_STRNDUP = 0 || test $REPLACE_STRNDUP = 1; then
+    AC_LIBOBJ([strndup])
+  fi
+  gl_STRING_MODULE_INDICATOR([strndup])
+  gl_FUNC_STRNLEN
+  if test $HAVE_DECL_STRNLEN = 0 || test $REPLACE_STRNLEN = 1; then
+    AC_LIBOBJ([strnlen])
+    gl_PREREQ_STRNLEN
+  fi
+  gl_STRING_MODULE_INDICATOR([strnlen])
   gl_FUNC_SYMLINK
   if test $HAVE_SYMLINK = 0 || test $REPLACE_SYMLINK = 1; then
     AC_LIBOBJ([symlink])
@@ -477,6 +493,7 @@
   gl_MODULE_INDICATOR([xalloc])
   gl_MODULE_INDICATOR([xalloc-die])
   gl_XSIZE
+  gl_XSTRNDUP
   # End of code from modules
   m4_ifval(gl_LIBSOURCES_LIST, [
     m4_syscmd([test ! -d ]m4_defn([gl_LIBSOURCES_DIR])[ ||
@@ -629,6 +646,7 @@
   lib/attribute.h
   lib/basename-lgpl.c
   lib/basename-lgpl.h
+  lib/basename.c
   lib/binary-io.c
   lib/binary-io.h
   lib/c++defs.h
@@ -638,6 +656,7 @@
   lib/cloexec.h
   lib/close.c
   lib/dirname-lgpl.c
+  lib/dirname.c
   lib/dirname.h
   lib/dup2.c
   lib/eloop-threshold.h
@@ -755,6 +774,8 @@
   lib/strerror.c
   lib/string.in.h
   lib/stripslash.c
+  lib/strndup.c
+  lib/strnlen.c
   lib/symlink.c
   lib/sys_stat.in.h
   lib/sys_types.in.h
@@ -774,6 +795,8 @@
   lib/xmalloc.c
   lib/xsize.c
   lib/xsize.h
+  lib/xstrndup.c
+  lib/xstrndup.h
   m4/00gnulib.m4
   m4/__inline.m4
   m4/absolute-header.m4
@@ -865,6 +888,8 @@
   m4/strdup.m4
   m4/strerror.m4
   m4/string_h.m4
+  m4/strndup.m4
+  m4/strnlen.m4
   m4/symlink.m4
   m4/sys_socket_h.m4
   m4/sys_stat_h.m4
@@ -881,5 +906,6 @@
   m4/write.m4
   m4/xalloc.m4
   m4/xsize.m4
+  m4/xstrndup.m4
   m4/zzgnulib.m4
 ])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/m4/strndup.m4 new/mmv-2.6/m4/strndup.m4
--- old/mmv-2.5.1/m4/strndup.m4 1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/m4/strndup.m4   2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,58 @@
+# strndup.m4 serial 22
+dnl Copyright (C) 2002-2003, 2005-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRNDUP],
+[
+  dnl Persuade glibc <string.h> to declare strndup().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+  AC_CHECK_DECLS_ONCE([strndup])
+  AC_CHECK_FUNCS_ONCE([strndup])
+  if test $ac_cv_have_decl_strndup = no; then
+    HAVE_DECL_STRNDUP=0
+  fi
+
+  if test $ac_cv_func_strndup = yes; then
+    HAVE_STRNDUP=1
+    # AIX 4.3.3, AIX 5.1 have a function that fails to add the terminating 
'\0'.
+    AC_CACHE_CHECK([for working strndup], [gl_cv_func_strndup_works],
+      [AC_RUN_IFELSE([
+         AC_LANG_PROGRAM([[#include <string.h>
+                           #include <stdlib.h>]], [[
+#if !HAVE_DECL_STRNDUP
+  extern
+  #ifdef __cplusplus
+  "C"
+  #endif
+  char *strndup (const char *, size_t);
+#endif
+  int result;
+  char *s;
+  s = strndup ("some longer string", 15);
+  free (s);
+  s = strndup ("shorter string", 13);
+  result = s[13] != '\0';
+  free (s);
+  return result;]])],
+         [gl_cv_func_strndup_works=yes],
+         [gl_cv_func_strndup_works=no],
+         [
+changequote(,)dnl
+          case $host_os in
+            aix | aix[3-6]*) gl_cv_func_strndup_works="guessing no";;
+            *)               gl_cv_func_strndup_works="guessing yes";;
+          esac
+changequote([,])dnl
+         ])])
+    case $gl_cv_func_strndup_works in
+      *no) REPLACE_STRNDUP=1 ;;
+    esac
+  else
+    HAVE_STRNDUP=0
+  fi
+])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/m4/strnlen.m4 new/mmv-2.6/m4/strnlen.m4
--- old/mmv-2.5.1/m4/strnlen.m4 1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/m4/strnlen.m4   2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,30 @@
+# strnlen.m4 serial 13
+dnl Copyright (C) 2002-2003, 2005-2007, 2009-2021 Free Software Foundation,
+dnl Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_STRNLEN],
+[
+  AC_REQUIRE([gl_HEADER_STRING_H_DEFAULTS])
+
+  dnl Persuade glibc <string.h> to declare strnlen().
+  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
+
+  AC_CHECK_DECLS_ONCE([strnlen])
+  if test $ac_cv_have_decl_strnlen = no; then
+    HAVE_DECL_STRNLEN=0
+  else
+    m4_pushdef([AC_LIBOBJ], [:])
+    dnl Note: AC_FUNC_STRNLEN does AC_LIBOBJ([strnlen]).
+    AC_FUNC_STRNLEN
+    m4_popdef([AC_LIBOBJ])
+    if test $ac_cv_func_strnlen_working = no; then
+      REPLACE_STRNLEN=1
+    fi
+  fi
+])
+
+# Prerequisites of lib/strnlen.c.
+AC_DEFUN([gl_PREREQ_STRNLEN], [:])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/m4/xstrndup.m4 new/mmv-2.6/m4/xstrndup.m4
--- old/mmv-2.5.1/m4/xstrndup.m4        1970-01-01 01:00:00.000000000 +0100
+++ new/mmv-2.6/m4/xstrndup.m4  2023-11-01 18:22:09.000000000 +0100
@@ -0,0 +1,15 @@
+# xstrndup.m4 serial 2
+dnl Copyright (C) 2003, 2009-2021 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_XSTRNDUP],
+[
+  gl_PREREQ_XSTRNDUP
+])
+
+# Prerequisites of lib/xstrndup.c.
+AC_DEFUN([gl_PREREQ_XSTRNDUP], [
+  :
+])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/mmv-include.man new/mmv-2.6/mmv-include.man
--- old/mmv-2.5.1/mmv-include.man       2023-02-04 23:43:50.000000000 +0100
+++ new/mmv-2.6/mmv-include.man 2024-02-09 16:11:58.000000000 +0100
@@ -1,10 +1,10 @@
 [NAME]
-mmv - move/copy/link multiple files by wildcard patterns
+mmv - move/copy/append/link multiple files by wildcard patterns
 
 [>DESCRIPTION]
 .PP
 .I Mmv
-moves (or copies or links, as specified)
+moves (or copies, appends, or links, as specified)
 each source file matching a
 .I from
 pattern to the target name specified by the
@@ -40,7 +40,7 @@
 .PP
 Whether
 .I mmv
-moves, copies, or links
+moves, copies, appends, or links
 is governed by the first set of options given
 above.
 If none of these are specified,
@@ -54,6 +54,8 @@
 .br
         mcp                    \-\-copy
 .br
+        mad                    \-\-append
+.br
         mln                    \-\-hardlink
 .PP
 The task option choices are:
@@ -94,6 +96,16 @@
 and the execute permission bits copied from the source file.
 In either case, the file modification time is set to the current time.
 .TP
+\fB\-\-append\fR:
+append contents of source file to target name.
+Target file modification time is set to the current time.
+If target file does not exist,
+it is created with permission bits
+set as under \-\-overwrite.
+Unlike all other options, \-\-append allows multiple source files to have the
+same target name, e.g. "mmv \-a \\*.c big" will append all ".c" files to "big".
+Chains and cycles are also allowed, so "mmv \-a f f" will double up "f".
+.TP
 \fB\-\-hardlink\fR:
 link target name to source file.
 Both must be on the same device,
@@ -272,10 +284,11 @@
 .I Mmv
 detects chains and cycles regardless of the order in which
 their constituent actions are actually given.
-Where allowed, i.e. in moving and renaming files,
+Where allowed, i.e. in moving, renaming, and appending files,
 chains and cycles are handled gracefully, by performing them in the proper
 order.
-Cycles are broken by first renaming one of the files to a temporary name.
+Cycles are broken by first renaming one of the files to a temporary name
+(or just remembering its original size when doing appends).
 
 .ce
 Collisions and Deletions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/mmv.1 new/mmv-2.6/mmv.1
--- old/mmv-2.5.1/mmv.1 2023-08-08 12:51:57.000000000 +0200
+++ new/mmv-2.6/mmv.1   2024-02-09 16:14:38.000000000 +0100
@@ -1,7 +1,7 @@
 .\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.49.1.
-.TH MMV "1" "August 2023" "mmv 2.5" "User Commands"
+.TH MMV "1" "February 2024" "mmv 2.5" "User Commands"
 .SH NAME
-mmv - move/copy/link multiple files by wildcard patterns
+mmv - move/copy/append/link multiple files by wildcard patterns
 .SH SYNOPSIS
 .B mmv
 [\fI\,-m|-x|-r|-c|-o|-a|-l|-s\/\fR] [\fI\,-h\/\fR] [\fI\,-d|-p\/\fR] 
[\fI\,-g|-t\/\fR] [\fI\,-v|-n\/\fR] \fI\,FROM TO\/\fR
@@ -68,7 +68,7 @@
 only report which actions would be performed
 .PP
 .I Mmv
-moves (or copies or links, as specified)
+moves (or copies, appends, or links, as specified)
 each source file matching a
 .I from
 pattern to the target name specified by the
@@ -104,7 +104,7 @@
 .PP
 Whether
 .I mmv
-moves, copies, or links
+moves, copies, appends, or links
 is governed by the first set of options given
 above.
 If none of these are specified,
@@ -118,6 +118,8 @@
 .br
         mcp                    \-\-copy
 .br
+        mad                    \-\-append
+.br
         mln                    \-\-hardlink
 .PP
 The task option choices are:
@@ -158,6 +160,16 @@
 and the execute permission bits copied from the source file.
 In either case, the file modification time is set to the current time.
 .TP
+\fB\-\-append\fR:
+append contents of source file to target name.
+Target file modification time is set to the current time.
+If target file does not exist,
+it is created with permission bits
+set as under \-\-overwrite.
+Unlike all other options, \-\-append allows multiple source files to have the
+same target name, e.g. "mmv \-a \\*.c big" will append all ".c" files to "big".
+Chains and cycles are also allowed, so "mmv \-a f f" will double up "f".
+.TP
 \fB\-\-hardlink\fR:
 link target name to source file.
 Both must be on the same device,
@@ -336,10 +348,11 @@
 .I Mmv
 detects chains and cycles regardless of the order in which
 their constituent actions are actually given.
-Where allowed, i.e. in moving and renaming files,
+Where allowed, i.e. in moving, renaming, and appending files,
 chains and cycles are handled gracefully, by performing them in the proper
 order.
-Cycles are broken by first renaming one of the files to a temporary name.
+Cycles are broken by first renaming one of the files to a temporary name
+(or just remembering its original size when doing appends).
 
 .ce
 Collisions and Deletions
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/mmv.c new/mmv-2.6/mmv.c
--- old/mmv-2.5.1/mmv.c 2023-08-08 12:51:50.000000000 +0200
+++ new/mmv-2.6/mmv.c   2024-02-09 16:11:58.000000000 +0100
@@ -54,6 +54,7 @@
 
 #include "progname.h"
 #include "binary-io.h"
+#include "dirname.h"
 #include "pathmax.h"
 #include "xalloc.h"
 #ifndef _WIN32
@@ -78,6 +79,7 @@
 #define NORMMOVE 0x008
 #define XMOVE 0x010
 #define DIRMOVE 0x020
+#define APPEND 0x040
 #define HARDLINK 0x100
 #define SYMLINK 0x200
 
@@ -86,6 +88,7 @@
 #define LINK (HARDLINK | SYMLINK)
 
 static char COPYNAME[] = "mcp";
+static char APPENDNAME[] = "mad";
 static char LINKNAME[] = "mln";
 
 #define ASKDEL 0
@@ -865,7 +868,7 @@
        if ((ffrom->fi_stflags & FI_LINKERR) && !(op & (MOVE | SYMLINK)))
                printf("%s -> %s : source file is a badly aimed symbolic 
link.\n",
                        pathbuf, fullrep);
-       else if ((op & COPY) && access(pathbuf, R_OK))
+       else if ((op & (COPY | APPEND)) && access(pathbuf, R_OK))
                printf("%s -> %s : no read permission for source file.\n",
                        pathbuf, fullrep);
        else if (
@@ -1408,7 +1411,7 @@
        char *t = fto->fi_name, *f = p->r_ffrom->fi_name;
        char *hnf = hfrom->h_name, *hnt = hto->h_name;
 
-       if (delstyle == NODEL && !(p->r_flags & R_DELOK))
+       if (delstyle == NODEL && !(p->r_flags & R_DELOK) && !(op & APPEND))
                printf("%s%s -> %s%s : old %s%s would have to be %s.\n",
                        hnf, f, hnt, t, hnt, t,
                        (op & OVERWRITE) ? "overwritten" : "deleted");
@@ -1419,12 +1422,12 @@
                fto->fi_stflags & FI_ISDIR
        )
                printf("%s%s -> %s%s : %s%s%s is a directory.\n",
-                       hnf, f, hnt, t, "old ", hnt, t);
-       else if ((fto->fi_stflags & FI_NODEL) && !(op & OVERWRITE))
+                      hnf, f, hnt, t, (op & APPEND) ? "" : "old ", hnt, t);
+       else if ((fto->fi_stflags & FI_NODEL) && !(op & (APPEND | OVERWRITE)))
                printf("%s%s -> %s%s : old %s%s lacks delete permission.\n",
                        hnf, f, hnt, t, hnt, t);
        else if (
-               (op & OVERWRITE) &&
+               (op & (APPEND | OVERWRITE)) &&
                !fwritable(hnt, fto)
        ) {
                printf("%s%s -> %s%s : %s%s %s.\n",
@@ -1471,7 +1474,7 @@
                                p->r_flags & R_ISALIASED ? '=' : '-',
                                p->r_flags & R_ISCYCLE ? '^' : '>',
                                p->r_hto->h_name, p->r_nto,
-                               (p->r_fdel != NULL) ? " (*)" : "");
+                               (p->r_fdel != NULL && !(op & APPEND)) ? " (*)" 
: "");
                }
 }
 
@@ -1489,6 +1492,22 @@
        return(first != p);
 }
 
+static long appendalias(REP *first, REP *p, int *pprintaliased)
+{
+       long ret = 0l;
+
+       struct stat fstat;
+
+       if (stat(fullrep, &fstat)) {
+               fprintf(stderr, "append cycle stat on %s has failed.\n", 
fullrep);
+               *pprintaliased = snap(first, p);
+       }
+       else
+               ret = fstat.st_size;
+
+       return(ret);
+}
+
 static int movealias(REP *first, REP *p, int *pprintaliased)
 {
        char *fstart;
@@ -1515,7 +1534,7 @@
 #define IRWMASK (S_IRUSR | S_IWUSR)
 #define RWMASK (IRWMASK | (IRWMASK >> 3) | (IRWMASK >> 6))
 
-static int copy(FILEINFO *ff)
+static int copy(FILEINFO *ff, off_t len)
 {
        char buf[BUFSIZ];
        int f, t, mode;
@@ -1526,19 +1545,32 @@
 
        if ((f = open(pathbuf, O_RDONLY | O_BINARY, 0)) < 0)
                return(-1);
-       perm = (op & OVERWRITE) ?
+       perm = (op & (APPEND | OVERWRITE)) ?
                (~oldumask & RWMASK) | (ff->fi_mode & (mode_t)~RWMASK) :
                ff->fi_mode;
 
-       mode = O_CREAT | O_TRUNC | O_WRONLY;
+       mode = O_CREAT | (op & APPEND ? 0 : O_TRUNC) | O_WRONLY;
        t = open(fullrep, mode, perm);
        if (t < 0) {
                close(f);
                return(-1);
        }
-       while ((k = read(f, buf, BUFSIZ)) > 0 && write(t, buf, (size_t)k) == k)
-               ;
-       if (!(op & OVERWRITE))
+       if (op & APPEND)
+               lseek(t, (off_t)0, SEEK_END);
+       if ((op & APPEND) && len != (off_t)-1) {
+               while (
+                       len != 0 &&
+                       (k = read(f, buf, (len > BUFSIZ) ? BUFSIZ : 
(size_t)len)) > 0 &&
+                       write(t, buf, (size_t)k) == k
+               )
+                       len -= k;
+               if (len == 0)
+                       k = 0;
+       }
+       else
+               while ((k = read(f, buf, BUFSIZ)) > 0 && write(t, buf, 
(size_t)k) == k)
+                       ;
+       if (!(op & (APPEND | OVERWRITE)))
                if (
                        stat(pathbuf, &fstat) ||
                        (
@@ -1553,7 +1585,8 @@
        close(f);
        close(t);
        if (k != 0) {
-               unlink(fullrep);
+               if (!(op & APPEND))
+                       unlink(fullrep);
                return(-1);
        }
        return(0);
@@ -1570,7 +1603,7 @@
 
 static int copymove(REP *p)
 {
-       return(copy(p->r_ffrom) || myunlink(pathbuf));
+       return(copy(p->r_ffrom, -1L) || myunlink(pathbuf));
 }
 
 static void doreps(void)
@@ -1579,6 +1612,7 @@
        unsigned k;
        int printaliased = 0, alias = 0;
        REP *first, *p;
+       long aliaslen = 0l;
 
        signal(SIGINT, breakrep);
 
@@ -1600,20 +1634,25 @@
                                p->r_hto->h_di->di_flags &= ~DI_NONEXISTENT;
                        }
                        strcat(fullrep, p->r_nto);
-                       if (!noex && (p->r_flags & R_ISCYCLE))
-                               alias = movealias(first, p, &printaliased);
+                       if (!noex && (p->r_flags & R_ISCYCLE)) {
+                               if (op & APPEND)
+                                       aliaslen = appendalias(first, p, 
&printaliased);
+                               else
+                                       alias = movealias(first, p, 
&printaliased);
+                       }
                        strcpy(pathbuf, p->r_hfrom->h_name);
                        fstart = pathbuf + strlen(pathbuf);
-                       if (p->r_flags & R_ISALIASED)
+                       if ((p->r_flags & R_ISALIASED) && !(op & APPEND))
                                sprintf(fstart, "%s%03d", TEMP, alias);
                        else
                                strcpy(fstart, p->r_ffrom->fi_name);
                        if (!noex) {
-                               if (p->r_fdel != NULL && !(op & OVERWRITE))
+                               if (p->r_fdel != NULL && !(op & (APPEND | 
OVERWRITE)))
                                        myunlink(fullrep);
                                if (
-                                       (op & COPY) ?
-                                               copy(p->r_ffrom) :
+                                       (op & (COPY | APPEND)) ?
+                                               copy(p->r_ffrom,
+                                                       p->r_flags & 
R_ISALIASED ? aliaslen : -1L) :
                                        (op & HARDLINK) ?
                                                link(pathbuf, fullrep) :
                                        (op & SYMLINK) ?
@@ -1637,7 +1676,7 @@
                                        p->r_flags & R_ISALIASED ? '=' : '-',
                                        p->r_flags & R_ISCYCLE ? '^' : '>',
                                        fullrep,
-                                       (p->r_fdel != NULL) ? " (*)" : "",
+                                       (p->r_fdel != NULL && !(op & APPEND)) ? 
" (*)" : "",
                                        noex ? "" : " : done");
                        }
                }
@@ -1711,14 +1750,20 @@
                op = NORMCOPY;
        else if (args_info.overwrite_given != 0)
                op = OVERWRITE;
+       else if (args_info.append_given != 0)
+               op = APPEND;
        else if (args_info.hardlink_given != 0)
                op = HARDLINK;
        else if (args_info.symlink_given != 0)
                op = SYMLINK;
        else {
-               if (strcmp(program_name, COPYNAME) == 0)
+               const char *name = basename(program_name);
+
+               if (strcmp(name, COPYNAME) == 0)
                        op = NORMCOPY;
-               else if (strcmp(program_name, LINKNAME) == 0)
+               else if (strcmp(name, APPENDNAME) == 0)
+                       op = APPEND;
+               else if (strcmp(name, LINKNAME) == 0)
                        op = HARDLINK;
                else
                        op = XMOVE;
@@ -1747,13 +1792,14 @@
        }
 
        domatch(frompat, topat);
-       checkcollisions();
+       if (!(op & APPEND))
+               checkcollisions();
        findorder();
        if (op & (COPY | LINK))
                nochains();
        scandeletes(baddel);
        goonordie();
-       if (delstyle == ASKDEL)
+       if (!(op & APPEND) && delstyle == ASKDEL)
                scandeletes(skipdel);
        doreps();
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/mmv-2.5.1/opts.ggo new/mmv-2.6/opts.ggo
--- old/mmv-2.5.1/opts.ggo      2023-08-08 12:44:11.000000000 +0200
+++ new/mmv-2.6/opts.ggo        2024-02-09 16:11:58.000000000 +0100
@@ -1,5 +1,5 @@
 # gengetopt for mmv
-purpose "move/copy/link multiple files by wildcard patterns"
+purpose "move/copy/append/link multiple files by wildcard patterns"
 usage " [-m|-x|-r|-c|-o|-a|-l|-s] [-h] [-d|-p] [-g|-t] [-v|-n] FROM TO"
 
 description "The FROM pattern is a shell glob pattern, in which `*' stands for 
any number
@@ -25,6 +25,7 @@
 groupoption "rename"     r "rename source to target in same directory"         
           group="mode"
 groupoption "copy"       c "copy source to target, preserving source 
permissions"         group="mode"
 groupoption "overwrite"  o "overwrite target with source, preserving target 
permissions"  group="mode"
+groupoption "append"     a "append contents of source file to target"          
           group="mode"
 groupoption "hardlink"   l "link target name to source file"                   
           group="mode"
 groupoption "symlink"    s "symlink target name to source file"                
           group="mode"
 

Reply via email to