Improve the check for departures from C89, and fix the departures
[platform/upstream/coreutils.git] / src / split.c
index f1e4dc3..1f0f3d7 100644 (file)
@@ -1,5 +1,5 @@
 /* split.c -- split a file into pieces.
-   Copyright (C) 88, 91, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1991, 1995-2006 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
@@ -12,8 +12,8 @@
    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, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
 \f
 /* By tege@sics.se, with rms.
 
 #include <getopt.h>
 #include <sys/types.h>
 
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#ifndef UINT_MAX
-# define UINT_MAX ((unsigned int) ~(unsigned int) 0)
-#endif
-
-#ifndef INT_MAX
-# define INT_MAX ((int) (UINT_MAX >> 1))
-#endif
-
 #include "system.h"
 #include "error.h"
+#include "fd-reopen.h"
+#include "fcntl--.h"
+#include "getpagesize.h"
+#include "full-read.h"
+#include "full-write.h"
+#include "inttostr.h"
+#include "quote.h"
+#include "safe-read.h"
 #include "xstrtol.h"
 
-char *xmalloc ();
-int full_write ();
-int safe_read ();
+/* The official name of this program (e.g., no `g' prefix).  */
+#define PROGRAM_NAME "split"
+
+#define AUTHORS "Torbjorn Granlund", "Richard M. Stallman"
+
+#define DEFAULT_SUFFIX_LENGTH 2
 
 /* The name this program was run with. */
 char *program_name;
 
 /* Base name of output files.  */
+static char const *outbase;
+
+/* Name of output files.  */
 static char *outfile;
 
 /* Pointer to the end of the prefix in OUTFILE.
    Suffixes are inserted here.  */
 static char *outfile_mid;
 
-/* Pointer to the end of OUTFILE. */
-static char *outfile_end;
+/* Length of OUTFILE's suffix.  */
+static size_t suffix_length = DEFAULT_SUFFIX_LENGTH;
+
+/* Alphabet of characters to use in suffix.  */
+static char const *suffix_alphabet = "abcdefghijklmnopqrstuvwxyz";
 
 /* Name of input file.  May be "-".  */
 static char *infile;
 
-/* Descriptor on which input file is open.  */
-static int input_desc;
-
 /* Descriptor on which output file is open.  */
 static int output_desc;
 
-/* If nonzero, display usage information and exit.  */
-static int show_help;
-
-/* If nonzero, print the version on standard output then exit.  */
-static int show_version;
-
-/* If nonzero, print a diagnostic on standard error just before each
+/* If true, print a diagnostic on standard error just before each
    output file is opened. */
-static int verbose;
+static bool verbose;
+
+/* For long options that have no equivalent short option, use a
+   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
+enum
+{
+  VERBOSE_OPTION = CHAR_MAX + 1
+};
 
 static struct option const longopts[] =
 {
   {"bytes", required_argument, NULL, 'b'},
   {"lines", required_argument, NULL, 'l'},
   {"line-bytes", required_argument, NULL, 'C'},
-  {"verbose", no_argument, NULL, 2},
-  {"help", no_argument, &show_help, 1},
-  {"version", no_argument, &show_version, 1},
+  {"suffix-length", required_argument, NULL, 'a'},
+  {"numeric-suffixes", no_argument, NULL, 'd'},
+  {"verbose", no_argument, NULL, VERBOSE_OPTION},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
 };
 
-static void
-usage (int status, const char *reason)
+void
+usage (int status)
 {
-  if (reason != NULL)
-    fprintf (stderr, "%s: %s\n", program_name, reason);
-
-  if (status != 0)
+  if (status != EXIT_SUCCESS)
     fprintf (stderr, _("Try `%s --help' for more information.\n"),
             program_name);
   else
@@ -105,73 +107,99 @@ usage (int status, const char *reason)
 Usage: %s [OPTION] [INPUT [PREFIX]]\n\
 "),
              program_name);
-    printf (_("\
+    fputs (_("\
 Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default\n\
-PREFIX is `x'.  With no INPUT, or when INPUT is -, read standard input.\n\
+size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT\n\
+is -, read standard input.\n\
 \n\
-  -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file\n\
+"), stdout);
+      fputs (_("\
+Mandatory arguments to long options are mandatory for short options too.\n\
+"), stdout);
+      fprintf (stdout, _("\
+  -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\
   -l, --lines=NUMBER      put NUMBER lines per output file\n\
+"), DEFAULT_SUFFIX_LENGTH);
+      fputs (_("\
       --verbose           print a diagnostic to standard error just\n\
-                           before each output file is opened\n\
-  -NUMBER                 same as -l NUMBER\n\
-      --help              display this help and exit\n\
-      --version           output version information and exit\n\
+                            before each output file is opened\n\
+"), stdout);
+      fputs (HELP_OPTION_DESCRIPTION, stdout);
+      fputs (VERSION_OPTION_DESCRIPTION, stdout);
+      fputs (_("\
 \n\
 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
-"));
+"), stdout);
+      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     }
-  exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+  exit (status);
 }
 
-/* Compute the next sequential output file name suffix and store it
-   into the string `outfile' at the position pointed to by `outfile_mid'.  */
+/* Compute the next sequential output file name and store it into the
+   string `outfile'.  */
 
 static void
 next_file_name (void)
 {
-  int x;
-  char *ne;
-  unsigned int i;
-
-  static int first_call = 1;
-
-  /* Status for outfile name generation.  */
-  static unsigned outfile_count = 0;
-  static unsigned outfile_name_limit = 25 * 26;
-  static unsigned outfile_name_generation = 1;
+  /* Index in suffix_alphabet of each character in the suffix.  */
+  static size_t *sufindex;
 
-  if (!first_call)
-    outfile_count++;
-  first_call = 0;
-  if (outfile_count < outfile_name_limit)
+  if (! outfile)
+    {
+      /* Allocate and initialize the first file name.  */
+
+      size_t outbase_length = strlen (outbase);
+      size_t outfile_length = outbase_length + suffix_length;
+      if (outfile_length + 1 < outbase_length)
+       xalloc_die ();
+      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);
+
+#if ! _POSIX_NO_TRUNC && HAVE_PATHCONF && defined _PC_NAME_MAX
+      /* POSIX requires that if the output file name is too long for
+        its directory, `split' must fail without creating any files.
+        This must be checked for explicitly on operating systems that
+        silently truncate file names.  */
+      {
+       char *dir = dir_name (outfile);
+       long name_max = pathconf (dir, _PC_NAME_MAX);
+       if (0 <= name_max && name_max < base_len (last_component (outfile)))
+         error (EXIT_FAILURE, ENAMETOOLONG, "%s", outfile);
+       free (dir);
+      }
+#endif
+    }
+  else
     {
-      for (ne = outfile_end - 1; ; ne--)
+      /* Increment the suffix in place, if possible.  */
+
+      size_t i = suffix_length;
+      while (i-- != 0)
        {
-         x = *ne;
-         if (x != 'z')
-           break;
-         *ne = 'a';
+         sufindex[i]++;
+         outfile_mid[i] = suffix_alphabet[sufindex[i]];
+         if (outfile_mid[i])
+           return;
+         sufindex[i] = 0;
+         outfile_mid[i] = suffix_alphabet[sufindex[i]];
        }
-      *ne = x + 1;
-      return;
+      error (EXIT_FAILURE, 0, _("Output file suffixes exhausted"));
     }
-
-  outfile_count = 0;
-  outfile_name_limit *= 26;
-  outfile_name_generation++;
-  *outfile_mid++ = 'z';
-  for (i = 0; i <= outfile_name_generation; i++)
-    outfile_mid[i] = 'a';
-  outfile_end += 2;
 }
 
 /* Write BYTES bytes at BP to an output file.
-   If NEW_FILE_FLAG is nonzero, open the next output file.
+   If NEW_FILE_FLAG is true, open the next output file.
    Otherwise add to the same output file already in use.  */
 
 static void
-cwrite (int new_file_flag, const char *bp, int bytes)
+cwrite (bool new_file_flag, const char *bp, size_t bytes)
 {
   if (new_file_flag)
     {
@@ -180,54 +208,34 @@ cwrite (int new_file_flag, const char *bp, int bytes)
 
       next_file_name ();
       if (verbose)
-       fprintf (stderr, _("creating file `%s'\n"), outfile);
-      output_desc = open (outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+       fprintf (stderr, _("creating file %s\n"), quote (outfile));
+      output_desc = open (outfile,
+                         O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+                         (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
+                          | S_IROTH | S_IWOTH));
       if (output_desc < 0)
        error (EXIT_FAILURE, errno, "%s", outfile);
     }
-  if (full_write (output_desc, bp, bytes) < 0)
+  if (full_write (output_desc, bp, bytes) != bytes)
     error (EXIT_FAILURE, errno, "%s", outfile);
 }
 
-/* Read NCHARS bytes from the input file into BUF.
-   Return the number of bytes successfully read.
-   If this is less than NCHARS, do not call `stdread' again.  */
-
-static int
-stdread (char *buf, int nchars)
-{
-  int n_read;
-  int to_be_read = nchars;
-
-  while (to_be_read)
-    {
-      n_read = safe_read (input_desc, buf, to_be_read);
-      if (n_read < 0)
-       return -1;
-      if (n_read == 0)
-       break;
-      to_be_read -= n_read;
-      buf += n_read;
-    }
-  return nchars - to_be_read;
-}
-
-/* Split into pieces of exactly NCHARS bytes.
+/* Split into pieces of exactly N_BYTES bytes.
    Use buffer BUF, whose size is BUFSIZE.  */
 
 static void
-bytes_split (int nchars, char *buf, int bufsize)
+bytes_split (uintmax_t n_bytes, char *buf, size_t bufsize)
 {
-  int n_read;
-  int new_file_flag = 1;
-  int to_read;
-  int to_write = nchars;
+  size_t n_read;
+  bool new_file_flag = true;
+  size_t to_read;
+  uintmax_t to_write = n_bytes;
   char *bp_out;
 
   do
     {
-      n_read = stdread (buf, bufsize);
-      if (n_read < 0)
+      n_read = full_read (STDIN_FILENO, buf, bufsize);
+      if (n_read == SAFE_READ_ERROR)
         error (EXIT_FAILURE, errno, "%s", infile);
       bp_out = buf;
       to_read = n_read;
@@ -239,96 +247,100 @@ bytes_split (int nchars, char *buf, int bufsize)
                {
                  cwrite (new_file_flag, bp_out, to_read);
                  to_write -= to_read;
-                 new_file_flag = 0;
+                 new_file_flag = false;
                }
              break;
            }
          else
            {
-             cwrite (new_file_flag, bp_out, to_write);
-             bp_out += to_write;
-             to_read -= to_write;
-             new_file_flag = 1;
-             to_write = nchars;
+             size_t w = to_write;
+             cwrite (new_file_flag, bp_out, w);
+             bp_out += w;
+             to_read -= w;
+             new_file_flag = true;
+             to_write = n_bytes;
            }
        }
     }
   while (n_read == bufsize);
 }
 
-/* Split into pieces of exactly NLINES lines.
+/* Split into pieces of exactly N_LINES lines.
    Use buffer BUF, whose size is BUFSIZE.  */
 
 static void
-lines_split (int nlines, char *buf, int bufsize)
+lines_split (uintmax_t n_lines, char *buf, size_t bufsize)
 {
-  int n_read;
+  size_t n_read;
   char *bp, *bp_out, *eob;
-  int new_file_flag = 1;
-  int n = 0;
+  bool new_file_flag = true;
+  uintmax_t n = 0;
 
   do
     {
-      n_read = stdread (buf, bufsize);
-      if (n_read < 0)
+      n_read = full_read (STDIN_FILENO, buf, bufsize);
+      if (n_read == SAFE_READ_ERROR)
        error (EXIT_FAILURE, errno, "%s", infile);
       bp = bp_out = buf;
       eob = bp + n_read;
       *eob = '\n';
       for (;;)
        {
-         while (*bp++ != '\n')
-           ;                   /* this semicolon takes most of the time */
-         if (bp > eob)
+         bp = memchr (bp, '\n', eob - bp + 1);
+         if (bp == eob)
            {
              if (eob != bp_out) /* do not write 0 bytes! */
                {
-                 cwrite (new_file_flag, bp_out, eob - bp_out);
-                 new_file_flag = 0;
+                 size_t len = eob - bp_out;
+                 cwrite (new_file_flag, bp_out, len);
+                 new_file_flag = false;
                }
              break;
            }
-         else
-           if (++n >= nlines)
-             {
-               cwrite (new_file_flag, bp_out, bp - bp_out);
-               bp_out = bp;
-               new_file_flag = 1;
-               n = 0;
-             }
+
+         ++bp;
+         if (++n >= n_lines)
+           {
+             cwrite (new_file_flag, bp_out, bp - bp_out);
+             bp_out = bp;
+             new_file_flag = true;
+             n = 0;
+           }
        }
     }
   while (n_read == bufsize);
 }
 \f
 /* Split into pieces that are as large as possible while still not more
-   than NCHARS bytes, and are split on line boundaries except
-   where lines longer than NCHARS bytes occur. */
+   than N_BYTES bytes, and are split on line boundaries except
+   where lines longer than N_BYTES bytes occur.
+   FIXME: Allow N_BYTES to be any uintmax_t value, and don't require a
+   buffer of size N_BYTES, in case N_BYTES is very large.  */
 
 static void
-line_bytes_split (int nchars)
+line_bytes_split (size_t n_bytes)
 {
-  int n_read;
+  size_t n_read;
   char *bp;
-  int eof = 0;
-  int n_buffered = 0;
-  char *buf = (char *) xmalloc (nchars);
+  bool eof = false;
+  size_t n_buffered = 0;
+  char *buf = xmalloc (n_bytes);
 
   do
     {
       /* Fill up the full buffer size from the input file.  */
 
-      n_read = stdread (buf + n_buffered, nchars - n_buffered);
-      if (n_read < 0)
+      n_read = full_read (STDIN_FILENO, buf + n_buffered, n_bytes - n_buffered);
+      if (n_read == SAFE_READ_ERROR)
        error (EXIT_FAILURE, errno, "%s", infile);
 
       n_buffered += n_read;
-      if (n_buffered != nchars)
-       eof = 1;
+      if (n_buffered != n_bytes)
+       eof = true;
 
       /* Find where to end this chunk.  */
       bp = buf + n_buffered;
-      if (n_buffered == nchars)
+      if (n_buffered == n_bytes)
        {
          while (bp > buf && bp[-1] != '\n')
            bp--;
@@ -339,7 +351,7 @@ line_bytes_split (int nchars)
        bp = buf + n_buffered;
 
       /* Output the chars as one output file.  */
-      cwrite (1, buf, bp - buf);
+      cwrite (true, buf, bp - buf);
 
       /* Discard the chars we just output; move rest of chunk
         down to be the start of the next chunk.  Source and
@@ -352,27 +364,37 @@ line_bytes_split (int nchars)
   free (buf);
 }
 
+#define FAIL_ONLY_ONE_WAY()                                    \
+  do                                                           \
+    {                                                          \
+      error (0, 0, _("cannot split in more than one way"));    \
+      usage (EXIT_FAILURE);                                    \
+    }                                                          \
+  while (0)
+
 int
 main (int argc, char **argv)
 {
   struct stat stat_buf;
-  int num;                     /* numeric argument from command line */
   enum
     {
       type_undef, type_bytes, type_byteslines, type_lines, type_digits
     } split_type = type_undef;
-  int in_blk_size;             /* optimal block size of input file device */
+  size_t in_blk_size;          /* optimal block size of input file device */
   char *buf;                   /* file i/o buffer */
-  int accum = 0;
-  char *outbase;
+  size_t page_size = getpagesize ();
+  uintmax_t n_units;
   int c;
   int digits_optind = 0;
 
+  initialize_main (&argc, &argv);
   program_name = argv[0];
   setlocale (LC_ALL, "");
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
+  atexit (close_stdout);
+
   /* Parse command line options.  */
 
   infile = "-";
@@ -382,45 +404,60 @@ main (int argc, char **argv)
     {
       /* This is the argv-index of the option we will read next.  */
       int this_optind = optind ? optind : 1;
-      long int tmp_long;
 
-      c = getopt_long (argc, argv, "0123456789vb:l:C:", longopts, (int *) 0);
-      if (c == EOF)
+      c = getopt_long (argc, argv, "0123456789C:a:b:dl:", longopts, NULL);
+      if (c == -1)
        break;
 
       switch (c)
        {
-       case 0:
+       case 'a':
+         {
+           unsigned long tmp;
+           if (xstrtoul (optarg, NULL, 10, &tmp, "") != LONGINT_OK
+               || SIZE_MAX / sizeof (size_t) < tmp)
+             {
+               error (0, 0, _("%s: invalid suffix length"), optarg);
+               usage (EXIT_FAILURE);
+             }
+           suffix_length = tmp;
+         }
          break;
 
        case 'b':
          if (split_type != type_undef)
-           usage (2, _("cannot split in more than one way"));
+           FAIL_ONLY_ONE_WAY ();
          split_type = type_bytes;
-         if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
-             || tmp_long < 0 || tmp_long > INT_MAX)
-           usage (2, _("invalid number of bytes"));
-         accum = (int) tmp_long;
+         if (xstrtoumax (optarg, NULL, 10, &n_units, "bkm") != LONGINT_OK
+             || n_units == 0)
+           {
+             error (0, 0, _("%s: invalid number of bytes"), optarg);
+             usage (EXIT_FAILURE);
+           }
          break;
 
        case 'l':
          if (split_type != type_undef)
-           usage (2, _("cannot split in more than one way"));
+           FAIL_ONLY_ONE_WAY ();
          split_type = type_lines;
-         if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
-             || tmp_long < 0 || tmp_long > INT_MAX)
-           usage (2, _("invalid number of lines"));
-         accum = (int) tmp_long;
+         if (xstrtoumax (optarg, NULL, 10, &n_units, "") != LONGINT_OK
+             || n_units == 0)
+           {
+             error (0, 0, _("%s: invalid number of lines"), optarg);
+             usage (EXIT_FAILURE);
+           }
          break;
 
        case 'C':
          if (split_type != type_undef)
-           usage (2, _("cannot split in more than one way"));
+           FAIL_ONLY_ONE_WAY ();
          split_type = type_byteslines;
-         if (xstrtol (optarg, NULL, 10, &tmp_long, "bkm") != LONGINT_OK
-             || tmp_long < 0 ||  tmp_long > INT_MAX)
-           usage (2, _("invalid number of bytes"));
-         accum = (int) tmp_long;
+         if (xstrtoumax (optarg, NULL, 10, &n_units, "bkm") != LONGINT_OK
+             || n_units == 0 || SIZE_MAX < n_units)
+           {
+             error (0, 0, _("%s: invalid number of bytes"), optarg);
+             usage (EXIT_FAILURE);
+           }
          break;
 
        case '0':
@@ -433,43 +470,54 @@ main (int argc, char **argv)
        case '7':
        case '8':
        case '9':
+         if (split_type == type_undef)
+           {
+             split_type = type_digits;
+             n_units = 0;
+           }
          if (split_type != type_undef && split_type != type_digits)
-           usage (2, _("cannot split in more than one way"));
+           FAIL_ONLY_ONE_WAY ();
          if (digits_optind != 0 && digits_optind != this_optind)
-           accum = 0;          /* More than one number given; ignore other. */
+           n_units = 0;        /* More than one number given; ignore other. */
          digits_optind = this_optind;
-         split_type = type_digits;
-         accum = accum * 10 + c - '0';
+         if (!DECIMAL_DIGIT_ACCUMULATE (n_units, c - '0', uintmax_t))
+           {
+             char buffer[INT_BUFSIZE_BOUND (uintmax_t)];
+             error (EXIT_FAILURE, 0,
+                    _("line count option -%s%c... is too large"),
+                    umaxtostr (n_units, buffer), c);
+           }
          break;
 
-       case 2:
-         verbose = 1;
+       case 'd':
+         suffix_alphabet = "0123456789";
          break;
 
+       case VERBOSE_OPTION:
+         verbose = true;
+         break;
+
+       case_GETOPT_HELP_CHAR;
+
+       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
        default:
-         usage (2, (char *)0);
+         usage (EXIT_FAILURE);
        }
     }
 
-  if (show_version)
-    {
-      printf ("split - %s\n", PACKAGE_VERSION);
-      exit (EXIT_SUCCESS);
-    }
-
-  if (show_help)
-    usage (0, (char *)0);
-
   /* Handle default case.  */
   if (split_type == type_undef)
     {
       split_type = type_lines;
-      accum = 1000;
+      n_units = 1000;
     }
 
-  if (accum < 1)
-    usage (2, _("invalid number"));
-  num = accum;
+  if (n_units == 0)
+    {
+      error (0, 0, _("invalid number of lines: 0"));
+      usage (EXIT_FAILURE);
+    }
 
   /* Get out the filename arguments.  */
 
@@ -480,60 +528,52 @@ main (int argc, char **argv)
     outbase = argv[optind++];
 
   if (optind < argc)
-    usage (2, _("too many arguments"));
-
-  /* Open the input file.  */
-  if (!strcmp (infile, "-"))
-    input_desc = 0;
-  else
     {
-      input_desc = open (infile, O_RDONLY);
-      if (input_desc < 0)
-       error (EXIT_FAILURE, errno, "%s", infile);
+      error (0, 0, _("extra operand %s"), quote (argv[optind]));
+      usage (EXIT_FAILURE);
     }
 
-  /* No output file is open now.  */
-  output_desc = -1;
+  /* Open the input file.  */
+  if (! STREQ (infile, "-")
+      && fd_reopen (STDIN_FILENO, infile, O_RDONLY, 0) < 0)
+    error (EXIT_FAILURE, errno, _("cannot open %s for reading"),
+          quote (infile));
 
-  /* Copy the output file prefix so we can add suffixes to it.
-     26**29 is certainly enough output files!  */
+  /* Binary I/O is safer when bytecounts are used.  */
+  if (O_BINARY && ! isatty (STDIN_FILENO))
+    freopen (NULL, "rb", stdin);
 
-  outfile = xmalloc (strlen (outbase) + 30);
-  strcpy (outfile, outbase);
-  outfile_mid = outfile + strlen (outfile);
-  outfile_end = outfile_mid + 2;
-  memset (outfile_mid, 0, 30);
-  outfile_mid[0] = 'a';
-  outfile_mid[1] = 'a' - 1;  /* first call to next_file_name makes it an 'a' */
+  /* No output file is open now.  */
+  output_desc = -1;
 
   /* Get the optimal block size of input device and make a buffer.  */
 
-  if (fstat (input_desc, &stat_buf) < 0)
+  if (fstat (STDIN_FILENO, &stat_buf) != 0)
     error (EXIT_FAILURE, errno, "%s", infile);
   in_blk_size = ST_BLKSIZE (stat_buf);
 
-  buf = xmalloc (in_blk_size + 1);
+  buf = ptr_align (xmalloc (in_blk_size + 1 + page_size - 1), page_size);
 
   switch (split_type)
     {
     case type_digits:
     case type_lines:
-      lines_split (num, buf, in_blk_size);
+      lines_split (n_units, buf, in_blk_size);
       break;
 
     case type_bytes:
-      bytes_split (num, buf, in_blk_size);
+      bytes_split (n_units, buf, in_blk_size);
       break;
 
     case type_byteslines:
-      line_bytes_split (num);
+      line_bytes_split (n_units);
       break;
 
     default:
       abort ();
     }
 
-  if (close (input_desc) < 0)
+  if (close (STDIN_FILENO) != 0)
     error (EXIT_FAILURE, errno, "%s", infile);
   if (output_desc >= 0 && close (output_desc) < 0)
     error (EXIT_FAILURE, errno, "%s", outfile);