> Thanks for continuing with this.
> One general thing that might both improve
> and simplify the implementation, is to
> not to convert from string to int at all.
>
> I.E. when processing the arg, just validate like:
> if (strlen (optarg) != strspn (optarg, suffix_alphabet))
>  error()
> else
>   /* skip over any leading 0, and use this as the start directly. */
>
> Then the subsequent check for length and
> the initialization of the file name should be simplified.
This is more like my first implementation indeed. But since I didn't
know about the strspn() function the code was a little bit more complex
without converting to int.

I attached the new patch. I tried to make it as simple as possible but
feel free to comment.

> Also this removes the limitation of size of an unsigned int,
> though that's not really a practical concern I suppose.
Fair point. IMHO, even if it's not a really practical concern
it's stupid to have such an easy to avoid restriction.

> I've also attached some string and test cleanups,
> to --amend into your patch.
Applied.

Cheers,

Jérémy
From e844b474ce1a5a35330e2598ceb271b2a22e002d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Compostella?= <[email protected]>
Date: Sun, 29 Jan 2012 15:20:31 +0100
Subject: [PATCH] split: --numeric-suffixes new optional "from" argument (bug#9085)

split now accepts an optional "from" argument to --numeric-suffixes,
which changes the start number from the default of 0.

* src/split.c (next_file_name): Initialize the suffix index
and the output filename according to start value.
(main): Check that the suffix length is large enough for the
numerical suffix start value.
* doc/coreutils.texi (split invocation): Mention it.
* NEWS (New features): Mention it.
* tests/split/numeric: New file. --numeric-suffixes[=FROM] option
  tests.
* tests/Makefile.am (TESTS): Add it.
---
 NEWS                |    3 ++
 doc/coreutils.texi  |    5 ++-
 src/split.c         |   46 +++++++++++++++++++++++++++++++++--
 tests/Makefile.am   |    1 +
 tests/split/numeric |   65 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 115 insertions(+), 5 deletions(-)
 create mode 100755 tests/split/numeric

diff --git a/NEWS b/NEWS
index 2080790..4662919 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   dd now accepts the count_bytes, skip_bytes iflags and the count_bytes
   oflag, to more easily allow processing portions of a file.
 
+  split now accepts an optional "from" argument to --numeric-suffixes,
+  which changes the start number from the default of 0.
+
 ** Bug fixes
 
   mv now lets you move a symlink onto a same-inode destination file that
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 8c6a287..9f378e8 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -3084,10 +3084,11 @@ and so can be a pipe for example.
 Use suffixes of length @var{length}.  The default @var{length} is 2.
 
 @item -d
-@itemx --numeric-suffixes
+@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 1d0310c..8266cfd 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 start value.  */
+static const char *numeric_suffix_start;
+
 /* 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, --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\
@@ -243,9 +247,19 @@ next_file_name (void)
       outfile = xmalloc (outfile_length + 1);
       outfile_mid = outfile + outbase_length;
       memcpy (outfile, outbase, outbase_length);
+      sufindex = xcalloc (suffix_length, sizeof *sufindex);
       memset (outfile_mid, suffix_alphabet[0], suffix_length);
+      if (numeric_suffix_start)
+        {
+          /* Initialize the suffix index and the output filename
+             according to start value.  */
+          size_t i = strlen (numeric_suffix_start);
+          size_t *sufindex_end = sufindex + suffix_length;
+          memcpy (outfile_mid + suffix_length - i, numeric_suffix_start, i);
+          while (i-- != 0)
+            *--sufindex_end = numeric_suffix_start[i] - '0';
+        }
       outfile[outfile_length] = 0;
-      sufindex = xcalloc (suffix_length, sizeof *sufindex);
 
 #if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
       /* POSIX requires that if the output file name is too long for
@@ -1142,6 +1156,23 @@ main (int argc, char **argv)
 
         case 'd':
           suffix_alphabet = "0123456789";
+          if (optarg)
+            {
+              if (strlen (optarg) != strspn (optarg, suffix_alphabet))
+                {
+                  error (0, 0,
+                         _("%s: invalid start value for numerical suffix"),
+                         optarg);
+                  usage (EXIT_FAILURE);
+                }
+              else
+                {
+                  /* Skip any leading zero.  */
+                  while (*optarg == '0' && *(optarg + 1) != '\0')
+                    optarg++;
+                  numeric_suffix_start = optarg;
+                }
+            }
           break;
 
         case 'e':
@@ -1212,6 +1243,15 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
+  /* Check that the suffix length is large enough for the numerical
+     suffix start value.  */
+  if (numeric_suffix_start && strlen (numeric_suffix_start) > suffix_length)
+    {
+      error (0, 0, _("numerical suffix start value is too large "
+                     "for the suffix length"));
+      usage (EXIT_FAILURE);
+    }
+
   /* Open the input file.  */
   if (! STREQ (infile, "-")
       && fd_reopen (STDIN_FILENO, infile, O_RDONLY, 0) < 0)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7b53681..eed6ed6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -259,6 +259,7 @@ TESTS =						\
   split/lines					\
   split/l-chunk					\
   split/r-chunk					\
+  split/numeric					\
   misc/stat-birthtime				\
   misc/stat-fmt					\
   misc/stat-hyphen				\
diff --git a/tests/split/numeric b/tests/split/numeric
new file mode 100755
index 0000000..ad22df6
--- /dev/null
+++ b/tests/split/numeric
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Show that split --numeric-suffixes[=from] works.
+
+# Copyright (C) 2012 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 <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/init.sh"; path_prepend_ ../src
+print_ver_ split
+
+# Check default start from 0
+printf '1\n2\n3\n4\n5\n' > in || framework_failure_
+split --numeric-suffixes --lines=2 in || fail=1
+cat <<\EOF > exp-1
+1
+2
+EOF
+cat <<\EOF > exp-2
+3
+4
+EOF
+cat <<\EOF > exp-3
+5
+EOF
+compare exp-1 x00 || fail=1
+compare exp-2 x01 || fail=1
+compare exp-3 x02 || fail=1
+
+# Check --numeric-suffixes=X
+split --numeric-suffixes=1 --lines=2 in || fail=1
+cat <<\EOF > exp-1
+1
+2
+EOF
+cat <<\EOF > exp-2
+3
+4
+EOF
+cat <<\EOF > exp-3
+5
+EOF
+compare exp-1 x01 || fail=1
+compare exp-2 x02 || fail=1
+compare exp-3 x03 || fail=1
+
+# Check that split failed when suffix length is not large enough for
+# the numerical suffix start value
+split -a 3 --numeric-suffixes=1000 in 2> /dev/null && fail=1
+
+# check invalid --numeric-suffixes start values are flagged
+split --numeric-suffixes=-1 in 2> /dev/null && fail=1
+split --numeric-suffixes=one in 2> /dev/null && fail=1
+
+Exit $fail
-- 
1.7.2.5

Reply via email to