Subject: Re: 'split' feature request: an option to uses e.g. '.001' as first suffix.

From: Jérémy Compostella <[email-masked]>
Date: Sun, 29 Jan 2012 23:34:09 +0100

Pádraig, Sci-Fi, others,

I made an implementation of the requested feature. With the attached
patch applied the split command accepts a new optional "from" argument
for the --numeric-suffixes (aka -d) option. If this argument is
specified, the numeric suffix counts from this value, otherwise, like
before, it counts from 0.

I've tried to not impact the performance, to not break anything and to
respect the coding rules but feel free to comment this patch. I will
take into account whatever you may want.

Cheers,

Jérémy
---
>From 82cbcf36e1fc9901964b6a348b495739357f28ee Mon Sep 17 00:00:00 2001
From: Jeremy Compostella <[email-masked]>
Date: Sun, 29 Jan 2012 15:20:31 +0100
Subject: [PATCH] split: --numeric-suffixes new optional "from" argument (bug#9085)

The split command now accepts a new optional "from" argument for the
--numeric-suffixes (aka -d) option. When this argument is specified,
the numeric suffix counts from this value, otherwise, like before, it
counts from 0.

Signed-off-by: Jeremy Compostella <[email-masked]>
---
 NEWS               |    6 +++++
 doc/coreutils.texi |    7 +++--
 src/split.c        |   63 +++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/NEWS b/NEWS
index 2b0926f..2f46707 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,12 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** New features
+
+   split now accept an optional "from" value for the
+   --numeric-suffixes (aka -d) option. When this argument is
+   specified, the numeric suffix counts from this value, otherwise,
+   like before, it counts from 0.
 
 * Noteworthy changes in release 8.15 (2012-01-06) [stable]
 
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 0d3b739..53ab356 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -3083,11 +3083,12 @@ and so can be a pipe for example.
 @opindex --suffix-length
 Use suffixes of length @var{length}.  The default @var{length} is 2.
 
-@item -d
-@itemx --numeric-suffixes
+@item -d[@var{from}]
+@itemx --numeric-suffixes[=@var{from}]
 @opindex -d
 @opindex --numeric-suffixes
-Use digits in suffixes rather than lower-case letters.
+Use digits in suffixes rather than lower-case letters. The numerical
+suffix counts from @var{from} if specified, 0 otherwise.
 
 @item -e
 @itemx --elide-empty-files
diff --git a/src/split.c b/src/split.c
index 5fbce0e..7454bc2 100644
--- a/src/split.c
+++ b/src/split.c
@@ -80,6 +80,9 @@ static size_t suffix_length;
 /* Alphabet of characters to use in suffix.  */
 static char const *suffix_alphabet = "abcdefghijklmnopqrstuvwxyz";
 
+/* Numerical suffix count from value.  */
+static size_t suffix_count_from;
+
 /* Name of input file.  May be "-".  */
 static char *infile;
 
@@ -122,7 +125,7 @@ static struct option const longopts[] =
   {"elide-empty-files", no_argument, NULL, 'e'},
   {"unbuffered", no_argument, NULL, 'u'},
   {"suffix-length", required_argument, NULL, 'a'},
-  {"numeric-suffixes", no_argument, NULL, 'd'},
+  {"numeric-suffixes", optional_argument, NULL, 'd'},
   {"filter", required_argument, NULL, FILTER_OPTION},
   {"verbose", no_argument, NULL, VERBOSE_OPTION},
   {"-io-blksize", required_argument, NULL,
@@ -195,7 +198,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
   -a, --suffix-length=N   use suffixes of length N (default %d)\n\
   -b, --bytes=SIZE        put SIZE bytes per output file\n\
   -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file\n\
-  -d, --numeric-suffixes  use numeric suffixes instead of alphabetic\n\
+  -d[FROM], --numeric-suffixes[FROM]  use numeric suffixes instead of alphabetic.\n\
+                           When specified, start counting from FROM, 0 otherwise\n\
   -e, --elide-empty-files  do not generate empty output files with '-n'\n\
       --filter=COMMAND    write to shell COMMAND; file name is $FILE\n\
   -l, --lines=NUMBER      put NUMBER lines per output file\n\
@@ -231,6 +235,7 @@ next_file_name (void)
 {
   /* Index in suffix_alphabet of each character in the suffix.  */
   static size_t *sufindex;
+  size_t i = suffix_length;
 
   if (! outfile)
     {
@@ -243,9 +248,23 @@ next_file_name (void)
       outfile = xmalloc (outfile_length + 1);
       outfile_mid = outfile + outbase_length;
       memcpy (outfile, outbase, outbase_length);
-      memset (outfile_mid, suffix_alphabet[0], suffix_length);
-      outfile[outfile_length] = 0;
       sufindex = xcalloc (suffix_length, sizeof *sufindex);
+      /* Initialize the suffix index accordingly to the count from
+         value.  */
+      {
+        size_t left = suffix_count_from;
+        while (i-- != 0)
+          {
+            if (left)
+              {
+                sufindex[i] = left % 10;
+                left /= 10;
+              }
+            outfile_mid[i] = suffix_alphabet[sufindex[i]];
+          }
+      }
+
+      outfile[outfile_length] = 0;
 
 #if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
       /* POSIX requires that if the output file name is too long for
@@ -265,7 +284,6 @@ next_file_name (void)
     {
       /* Increment the suffix in place, if possible.  */
 
-      size_t i = suffix_length;
       while (i-- != 0)
         {
           sufindex[i]++;
@@ -1016,7 +1034,7 @@ main (int argc, char **argv)
       int this_optind = optind ? optind : 1;
       char *slash;
 
-      c = getopt_long (argc, argv, "0123456789C:a:b:del:n:u",
+      c = getopt_long (argc, argv, "0123456789C:a:b:d::el:n:u",
                        longopts, NULL);
       if (c == -1)
         break;
@@ -1142,6 +1160,19 @@ main (int argc, char **argv)
 
         case 'd':
           suffix_alphabet = "0123456789";
+          if (optarg)
+            {
+              unsigned long tmp;
+              if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
+                  || SIZE_MAX / sizeof (size_t) < tmp)
+                {
+                  error (0, 0, _("%s: invalid count from numerical suffix number"),
+                         optarg);
+                  usage (EXIT_FAILURE);
+                }
+              else
+                suffix_count_from = tmp;
+            }
           break;
 
         case 'e':
@@ -1212,6 +1243,26 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
+  /* Check that the suffix length is greater enough for the numerical
+     suffix count from value.  */
+  if (suffix_count_from)
+    {
+      size_t start = suffix_count_from;
+      size_t length = suffix_length;
+
+      while (start)
+        {
+          if (length == 0)
+            {
+              error (0, 0, _("numerical suffix FROM number too hight\
+ for the suffix length"));
+              usage (EXIT_FAILURE);
+            }
+          start /= 10;
+          length--;
+        }
+    }
+
   /* Open the input file.  */
   if (! STREQ (infile, "-")
       && fd_reopen (STDIN_FILENO, infile, O_RDONLY, 0) < 0)
-- 
1.7.2.5