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

From: Pádraig Brady <[email-masked]>
Date: Mon, 30 Jan 2012 10:29:34 +0000

On 01/29/2012 10:34 PM, Jérémy Compostella wrote:
> 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.

Thanks again for looking at this.
It's a useful feature for the presented use case,
or for supporting multiple independent split invocations.

Note we rarely change an option to have optional args.
For optional args, no space is allowed between option name and value.
I.E. --numeric-suffixes=10 or -d10 is required, which is a little restrictive.
More problematically though, existing scripts using the short options -de or -du in
combination will break.  The -eu options are relatively new though, so I'm leaning
towards this being acceptable. Hmm, this unusual form would fail too, `split -da3 ...`.
The failure mode is immediate and obvious, but this worries me a bit.

I wonder might we have a separate option, --suffix-start,
and theoretically that could accept alphabetic options too?
I'm not suggesting we do this, but it's worth discussing.

>>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)

+  -d[FROM], --numeric-suffixes[FROM]  use numeric suffixes instead of alphabetic.\n\
+                           When specified, start counting from FROM, 0 otherwise\n\

s/-d[FROM], --numeric-suffixes[FROM]/-d, --numeric-suffixes[=FROM]

   -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)

Note the SIZE_MAX/sizeof(size_t) restriction was on the -a option,
as that is later used in a malloc. For -d there would be
no such restriction, so I'd just use xstrtoumax() != LONGINT_OK

cheers,
Pádraig.