(WRITTEN_BY): Rename from AUTHORS.
[platform/upstream/coreutils.git] / src / nl.c
index 1444002..63beb57 100644 (file)
--- a/src/nl.c
+++ b/src/nl.c
@@ -1,5 +1,5 @@
 /* nl -- number lines of files
-   Copyright (C) 1989, 1992 Free Software Foundation, Inc.
+   Copyright (C) 89, 92, 1995-2003 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
    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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 \f
 /* Written by Scott Bartram (nancy!scott@uunet.uu.net)
    Revised by David MacKenzie (djm@gnu.ai.mit.edu) */
 
+#include <config.h>
+
 #include <stdio.h>
 #include <sys/types.h>
 #include <getopt.h>
+
+#include "system.h"
+
 #include <regex.h>
+
+#include "error.h"
 #include "linebuffer.h"
-#include "system.h"
-#include "version.h"
+#include "quote.h"
+#include "xstrtol.h"
+
+/* The official name of this program (e.g., no `g' prefix).  */
+#define PROGRAM_NAME "nl"
+
+#define WRITTEN_BY _("Written by Scott Bartram and David MacKenzie.")
 
 #ifndef TRUE
-#define TRUE   1
-#define FALSE  0
+# define TRUE   1
+# define FALSE  0
 #endif
 
 /* Line-number formats. */
@@ -49,22 +61,6 @@ enum section
   Header, Body, Footer, Text
 };
 
-char *xmalloc ();
-char *xrealloc ();
-void error ();
-
-static enum section check_section ();
-static int build_type_arg ();
-static int nl_file ();
-static void usage ();
-static void process_file ();
-static void proc_header ();
-static void proc_body ();
-static void proc_footer ();
-static void proc_text ();
-static void print_lineno ();
-static void build_print_fmt ();
-
 /* The name this program was run with. */
 char *program_name;
 
@@ -102,19 +98,19 @@ static char *section_del = DEFAULT_SECTION_DELIMITERS;
 static char *header_del = NULL;
 
 /* Header section delimiter length.  */
-static int header_del_len;
+static size_t header_del_len;
 
 /* Body delimiter string.  */
 static char *body_del = NULL;
 
 /* Body section delimiter length.  */
-static int body_del_len;
+static size_t body_del_len;
 
 /* Footer delimiter string.  */
 static char *footer_del = NULL;
 
 /* Footer section delimiter length.  */
-static int footer_del_len;
+static size_t footer_del_len;
 
 /* Input buffer.  */
 static struct linebuffer line_buf;
@@ -126,7 +122,7 @@ static char *print_fmt;
 static char *print_no_line_fmt = NULL;
 
 /* Starting line number on each page (-v).  */
-static int page_start = 1;
+static int starting_line_number = 1;
 
 /* Line number increment (-i).  */
 static int page_incr = 1;
@@ -149,18 +145,12 @@ static int line_no;
 /* Nonzero if we have ever read standard input. */
 static int have_read_stdin;
 
-/* If non-zero, display usage information and exit.  */
-static int flag_help;
-
-/* If non-zero, print the version on standard error.  */
-static int flag_version;
-
 static struct option const longopts[] =
 {
   {"header-numbering", required_argument, NULL, 'h'},
   {"body-numbering", required_argument, NULL, 'b'},
   {"footer-numbering", required_argument, NULL, 'f'},
-  {"first-page", required_argument, NULL, 'v'},
+  {"starting-line-number", required_argument, NULL, 'v'},
   {"page-increment", required_argument, NULL, 'i'},
   {"no-renumber", no_argument, NULL, 'p'},
   {"join-blank-lines", required_argument, NULL, 'l'},
@@ -168,256 +158,163 @@ static struct option const longopts[] =
   {"number-width", required_argument, NULL, 'w'},
   {"number-format", required_argument, NULL, 'n'},
   {"section-delimiter", required_argument, NULL, 'd'},
-  {"help", no_argument, &flag_help, 1},
-  {"version", no_argument, &flag_version, 1},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
 };
 
+/* Print a usage message and quit. */
+
 void
-main (argc, argv)
-     int argc;
-     char **argv;
+usage (int status)
 {
-  int c, exit_status = 0;
-
-  program_name = argv[0];
-  have_read_stdin = 0;
-
-  while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
-                          (int *) 0)) != EOF)
+  if (status != 0)
+    fprintf (stderr, _("Try `%s --help' for more information.\n"),
+            program_name);
+  else
     {
-      switch (c)
-       {
-       case 0:
-         break;
-
-       case 'h':
-         if (build_type_arg (&header_type, &header_regex) != TRUE)
-           usage ();
-         break;
-       case 'b':
-         if (build_type_arg (&body_type, &body_regex) != TRUE)
-           usage ();
-         break;
-       case 'f':
-         if (build_type_arg (&footer_type, &footer_regex) != TRUE)
-           usage ();
-         break;
-       case 'v':
-         page_start = atoi (optarg);
-         break;
-       case 'i':
-         page_incr = atoi (optarg);
-         if (page_incr < 1)
-           page_incr = 1;
-         break;
-       case 'p':
-         reset_numbers = FALSE;
-         break;
-       case 'l':
-         blank_join = atoi (optarg);
-         break;
-       case 's':
-         separator_str = optarg;
-         break;
-       case 'w':
-         lineno_width = atoi (optarg);
-         if (lineno_width < 1)
-           lineno_width = 1;
-         break;
-       case 'n':
-         switch (*optarg)
-           {
-           case 'l':
-             if (optarg[1] == 'n')
-               lineno_format = FORMAT_LEFT;
-             else
-               usage ();
-             break;
-           case 'r':
-             switch (optarg[1])
-               {
-               case 'n':
-                 lineno_format = FORMAT_RIGHT_NOLZ;
-                 break;
-               case 'z':
-                 lineno_format = FORMAT_RIGHT_LZ;
-                 break;
-               default:
-                 usage ();
-                 break;
-               }
-             break;
-           default:
-             usage ();
-             break;
-           }
-         break;
-       case 'd':
-         section_del = optarg;
-         break;
-       default:
-         usage ();
-         break;
-       }
+      printf (_("\
+Usage: %s [OPTION]... [FILE]...\n\
+"),
+             program_name);
+      fputs (_("\
+Write each FILE to standard output, with line numbers added.\n\
+With no FILE, or when FILE is -, read standard input.\n\
+\n\
+"), stdout);
+      fputs (_("\
+Mandatory arguments to long options are mandatory for short options too.\n\
+"), stdout);
+      fputs (_("\
+  -b, --body-numbering=STYLE      use STYLE for numbering body lines\n\
+  -d, --section-delimiter=CC      use CC for separating logical pages\n\
+  -f, --footer-numbering=STYLE    use STYLE for numbering footer lines\n\
+"), stdout);
+      fputs (_("\
+  -h, --header-numbering=STYLE    use STYLE for numbering header lines\n\
+  -i, --page-increment=NUMBER     line number increment at each line\n\
+  -l, --join-blank-lines=NUMBER   group of NUMBER empty lines counted as one\n\
+  -n, --number-format=FORMAT      insert line numbers according to FORMAT\n\
+  -p, --no-renumber               do not reset line numbers at logical pages\n\
+  -s, --number-separator=STRING   add STRING after (possible) line number\n\
+"), stdout);
+      fputs (_("\
+  -v, --first-page=NUMBER         first line number on each logical page\n\
+  -w, --number-width=NUMBER       use NUMBER columns for line numbers\n\
+"), stdout);
+      fputs (HELP_OPTION_DESCRIPTION, stdout);
+      fputs (VERSION_OPTION_DESCRIPTION, stdout);
+      fputs (_("\
+\n\
+By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn.  CC are\n\
+two delimiter characters for separating logical pages, a missing\n\
+second character implies :.  Type \\\\ for \\.  STYLE is one of:\n\
+"), stdout);
+      fputs (_("\
+\n\
+  a         number all lines\n\
+  t         number only nonempty lines\n\
+  n         number no lines\n\
+  pREGEXP   number only lines that contain a match for REGEXP\n\
+\n\
+FORMAT is one of:\n\
+\n\
+  ln   left justified, no leading zeros\n\
+  rn   right justified, no leading zeros\n\
+  rz   right justified, leading zeros\n\
+\n\
+"), stdout);
+      printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
     }
+  exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+}
 
-  if (flag_version)
-    fprintf (stderr, "%s\n", version_string);
-
-  if (flag_help)
-    usage ();
-
-  /* Initialize the section delimiters.  */
-  c = strlen (section_del);
-
-  header_del_len = c * 3;
-  header_del = xmalloc (header_del_len + 1);
-  strcat (strcat (strcpy (header_del, section_del), section_del), section_del);
-
-  body_del_len = c * 2;
-  body_del = xmalloc (body_del_len + 1);
-  strcat (strcpy (body_del, section_del), section_del);
-
-  footer_del_len = c;
-  footer_del = xmalloc (footer_del_len + 1);
-  strcpy (footer_del, section_del);
-
-  /* Initialize the input buffer.  */
-  initbuffer (&line_buf);
-
-  /* Initialize the printf format for unnumbered lines. */
-  c = strlen (separator_str);
-  print_no_line_fmt = xmalloc (lineno_width + c + 1);
-  memset (print_no_line_fmt, ' ', lineno_width + c);
-  print_no_line_fmt[lineno_width + c] = '\0';
-
-  line_no = page_start;
-  current_type = body_type;
-  current_regex = &body_regex;
-  build_print_fmt ();
-
-  /* Main processing. */
-
-  if (optind == argc)
-    exit_status |= nl_file ("-");
-  else
-    for (; optind < argc; optind++)
-      exit_status |= nl_file (argv[optind]);
+/* Build the printf format string, based on `lineno_format'. */
 
-  if (have_read_stdin && fclose (stdin) == EOF)
+static void
+build_print_fmt (void)
+{
+  print_fmt = xmalloc (  1 /* for `%' */
+                      + 1 /* for `-' or `0' */
+                      + INT_STRLEN_BOUND (lineno_width)
+                      + 1 /* for `d' */
+                      + 1 /* for trailing NUL byte */ );
+  switch (lineno_format)
     {
-      error (0, errno, "-");
-      exit_status = 1;
+    case FORMAT_RIGHT_NOLZ:
+      sprintf (print_fmt, "%%%dd", lineno_width);
+      break;
+    case FORMAT_RIGHT_LZ:
+      sprintf (print_fmt, "%%0%dd", lineno_width);
+      break;
+    case FORMAT_LEFT:
+      sprintf (print_fmt, "%%-%dd", lineno_width);
+      break;
     }
-  if (ferror (stdout) || fclose (stdout) == EOF)
-    error (1, errno, "write error");
-
-  exit (exit_status);
 }
-\f
-/* Process file FILE to standard output.
-   Return 0 if successful, 1 if not. */
+
+/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
+   according to `optarg'.  */
 
 static int
-nl_file (file)
-     char *file;
+build_type_arg (char **typep, struct re_pattern_buffer *regexp)
 {
-  FILE *stream;
-
-  if (!strcmp (file, "-"))
-    {
-      have_read_stdin = 1;
-      stream = stdin;
-    }
-  else
-    {
-      stream = fopen (file, "r");
-      if (stream == NULL)
-       {
-         error (0, errno, "%s", file);
-         return 1;
-       }
-    }
-
-  process_file (stream);
+  const char *errmsg;
+  int rval = TRUE;
+  int optlen;
 
-  if (ferror (stream))
-    {
-      error (0, errno, "%s", file);
-      return 1;
-    }
-  if (!strcmp (file, "-"))
-    clearerr (stream);         /* Also clear EOF. */
-  else if (fclose (stream) == EOF)
+  switch (*optarg)
     {
-      error (0, errno, "%s", file);
-      return 1;
+    case 'a':
+    case 't':
+    case 'n':
+      *typep = optarg;
+      break;
+    case 'p':
+      *typep = optarg++;
+      optlen = strlen (optarg);
+      regexp->allocated = optlen * 2;
+      regexp->buffer = xmalloc (regexp->allocated);
+      regexp->translate = NULL;
+      regexp->fastmap = xmalloc (256);
+      regexp->fastmap_accurate = 0;
+      errmsg = re_compile_pattern (optarg, optlen, regexp);
+      if (errmsg)
+       error (EXIT_FAILURE, 0, "%s", errmsg);
+      break;
+    default:
+      rval = FALSE;
+      break;
     }
-  return 0;
+  return rval;
 }
 
-/* Read and process the file pointed to by FP. */
+/* Print the line number and separator; increment the line number. */
 
 static void
-process_file (fp)
-     FILE *fp;
+print_lineno (void)
 {
-  while (readline (&line_buf, fp))
-    {
-      switch ((int) check_section ())
-       {
-       case Header:
-         proc_header ();
-         break;
-       case Body:
-         proc_body ();
-         break;
-       case Footer:
-         proc_footer ();
-         break;
-       case Text:
-         proc_text ();
-         break;
-       }
-    }
-}
-\f
-/* Return the type of line in `line_buf'. */
-
-static enum section
-check_section ()
-{
-  if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
-    return Text;
-  if (line_buf.length == header_del_len
-      && !memcmp (line_buf.buffer, header_del, header_del_len))
-    return Header;
-  if (line_buf.length == body_del_len
-      && !memcmp (line_buf.buffer, body_del, body_del_len))
-    return Body;
-  if (line_buf.length == footer_del_len
-      && !memcmp (line_buf.buffer, footer_del, footer_del_len))
-    return Footer;
-  return Text;
+  printf (print_fmt, line_no);
+  fputs (separator_str, stdout);
+  line_no += page_incr;
 }
 
 /* Switch to a header section. */
 
 static void
-proc_header ()
+proc_header (void)
 {
   current_type = header_type;
   current_regex = &header_regex;
   if (reset_numbers)
-    line_no = page_start;
+    line_no = starting_line_number;
   putchar ('\n');
 }
 
 /* Switch to a body section. */
 
 static void
-proc_body ()
+proc_body (void)
 {
   current_type = body_type;
   current_regex = &body_regex;
@@ -427,7 +324,7 @@ proc_body ()
 /* Switch to a footer section. */
 
 static void
-proc_footer ()
+proc_footer (void)
 {
   current_type = footer_type;
   current_regex = &footer_regex;
@@ -437,7 +334,7 @@ proc_footer ()
 /* Process a regular text line in `line_buf'. */
 
 static void
-proc_text ()
+proc_text (void)
 {
   static int blank_lines = 0;  /* Consecutive blank lines so far. */
 
@@ -446,120 +343,313 @@ proc_text ()
     case 'a':
       if (blank_join > 1)
        {
-         if (line_buf.length || ++blank_lines == blank_join)
+         if (1 < line_buf.length || ++blank_lines == blank_join)
            {
              print_lineno ();
              blank_lines = 0;
            }
          else
-           printf (print_no_line_fmt);
+           fputs (print_no_line_fmt, stdout);
        }
       else
        print_lineno ();
       break;
     case 't':
-      if (line_buf.length)
+      if (1 < line_buf.length)
        print_lineno ();
       else
-       printf (print_no_line_fmt);
+       fputs (print_no_line_fmt, stdout);
       break;
     case 'n':
-      printf (print_no_line_fmt);
+      fputs (print_no_line_fmt, stdout);
       break;
     case 'p':
-      if (re_search (current_regex, line_buf.buffer, line_buf.length,
-                    0, line_buf.length, (struct re_registers *) 0) < 0)
-       printf (print_no_line_fmt);
+      if (re_search (current_regex, line_buf.buffer, line_buf.length - 1,
+                    0, line_buf.length - 1, (struct re_registers *) 0) < 0)
+       fputs (print_no_line_fmt, stdout);
       else
        print_lineno ();
       break;
     }
   fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
-  putchar ('\n');
 }
-\f
-/* Print and increment the line number. */
 
-static void
-print_lineno ()
+/* Return the type of line in `line_buf'. */
+
+static enum section
+check_section (void)
 {
-  printf (print_fmt, line_no);
-  line_no += page_incr;
+  size_t len = line_buf.length - 1;
+
+  if (len < 2 || memcmp (line_buf.buffer, section_del, 2))
+    return Text;
+  if (len == header_del_len
+      && !memcmp (line_buf.buffer, header_del, header_del_len))
+    return Header;
+  if (len == body_del_len
+      && !memcmp (line_buf.buffer, body_del, body_del_len))
+    return Body;
+  if (len == footer_del_len
+      && !memcmp (line_buf.buffer, footer_del, footer_del_len))
+    return Footer;
+  return Text;
 }
 
-/* Build the printf format string, based on `lineno_format'. */
+/* Read and process the file pointed to by FP. */
 
 static void
-build_print_fmt ()
+process_file (FILE *fp)
 {
-  /* 12 = 10 chars for lineno_width, 1 for %, 1 for \0.  */
-  print_fmt = xmalloc (strlen (separator_str) + 12);
-  switch (lineno_format)
+  while (readlinebuffer (&line_buf, fp))
     {
-    case FORMAT_RIGHT_NOLZ:
-      sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
-      break;
-    case FORMAT_RIGHT_LZ:
-      sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
-      break;
-    case FORMAT_LEFT:
-      sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
-      break;
+      switch ((int) check_section ())
+       {
+       case Header:
+         proc_header ();
+         break;
+       case Body:
+         proc_body ();
+         break;
+       case Footer:
+         proc_footer ();
+         break;
+       case Text:
+         proc_text ();
+         break;
+       }
     }
 }
 
-/* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
-   according to `optarg'.  */
+/* Process file FILE to standard output.
+   Return 0 if successful, 1 if not. */
 
 static int
-build_type_arg (typep, regexp)
-     char **typep;
-     struct re_pattern_buffer *regexp;
+nl_file (const char *file)
 {
-  const char *errmsg;
-  int rval = TRUE;
-  int optlen;
+  FILE *stream;
 
-  switch (*optarg)
+  if (STREQ (file, "-"))
     {
-    case 'a':
-    case 't':
-    case 'n':
-      *typep = optarg;
-      break;
-    case 'p':
-      *typep = optarg++;
-      optlen = strlen (optarg);
-      regexp->allocated = optlen * 2;
-      regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
-      regexp->translate = NULL;
-      regexp->fastmap = xmalloc (256);
-      regexp->fastmap_accurate = 0;
-      errmsg = re_compile_pattern (optarg, optlen, regexp);
-      if (errmsg)
-       error (1, 0, "%s", errmsg);
-      break;
-    default:
-      rval = FALSE;
-      break;
+      have_read_stdin = 1;
+      stream = stdin;
     }
-  return rval;
+  else
+    {
+      stream = fopen (file, "r");
+      if (stream == NULL)
+       {
+         error (0, errno, "%s", file);
+         return 1;
+       }
+    }
+
+  process_file (stream);
+
+  if (ferror (stream))
+    {
+      error (0, errno, "%s", file);
+      return 1;
+    }
+  if (STREQ (file, "-"))
+    clearerr (stream);         /* Also clear EOF. */
+  else if (fclose (stream) == EOF)
+    {
+      error (0, errno, "%s", file);
+      return 1;
+    }
+  return 0;
 }
-\f
-/* Print a usage message and quit. */
 
-static void
-usage ()
+int
+main (int argc, char **argv)
 {
-  fprintf (stderr, "\
-Usage: %s [-h header-style] [-b body-style] [-f footer-style] [-p] [-d cc]\n\
-       [-v start-number] [-i increment] [-l lines] [-s line-separator]\n\
-       [-w line-no-width] [-n {ln,rn,rz}] [--header-numbering=style]\n\
-       [--body-numbering=style] [--footer-numbering=style]\n\
-       [--first-page=number] [--page-increment=number] [--no-renumber]\n\
-       [--join-blank-lines=number] [--number-separator=string]\n\
-       [--number-width=number] [--number-format={ln,rn,rz}]\n\
-       [--section-delimiter=cc] [--help] [--version] [file...]\n",
-          program_name);
-  exit (2);
+  int c, exit_status = 0;
+  size_t len;
+  int fail = 0;
+
+  initialize_main (&argc, &argv);
+  program_name = argv[0];
+  setlocale (LC_ALL, "");
+  bindtextdomain (PACKAGE, LOCALEDIR);
+  textdomain (PACKAGE);
+
+  atexit (close_stdout);
+
+  have_read_stdin = 0;
+
+  while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
+                          NULL)) != -1)
+    {
+      switch (c)
+       {
+       case 0:
+         break;
+
+       case 'h':
+         if (build_type_arg (&header_type, &header_regex) != TRUE)
+           {
+             error (0, 0, _("invalid header numbering style: %s"),
+                    quote (optarg));
+             fail = 1;
+           }
+         break;
+       case 'b':
+         if (build_type_arg (&body_type, &body_regex) != TRUE)
+           {
+             error (0, 0, _("invalid body numbering style: %s"),
+                    quote (optarg));
+             fail = 1;
+           }
+         break;
+       case 'f':
+         if (build_type_arg (&footer_type, &footer_regex) != TRUE)
+           {
+             error (0, 0, _("invalid footer numbering style: %s"),
+                    quote (optarg));
+             fail = 1;
+           }
+         break;
+       case 'v':
+         {
+           long int tmp_long;
+           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
+               /* Allow it to be negative.  */
+               || tmp_long > INT_MAX)
+             {
+               error (0, 0, _("invalid starting line number: %s"),
+                      quote (optarg));
+               fail = 1;
+             }
+           else
+             {
+               starting_line_number = (int) tmp_long;
+             }
+         }
+         break;
+       case 'i':
+         {
+           long int tmp_long;
+           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
+               || tmp_long <= 0 || tmp_long > INT_MAX)
+             {
+               error (0, 0, _("invalid line number increment: %s"),
+                      quote (optarg));
+               fail = 1;
+             }
+           else
+             {
+               page_incr = (int) tmp_long;
+             }
+         }
+         break;
+       case 'p':
+         reset_numbers = FALSE;
+         break;
+       case 'l':
+         {
+           long int tmp_long;
+           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
+               || tmp_long <= 0 || tmp_long > INT_MAX)
+             {
+               error (0, 0, _("invalid number of blank lines: %s"),
+                      quote (optarg));
+               fail = 1;
+             }
+           else
+             {
+               blank_join = (int) tmp_long;
+             }
+         }
+         break;
+       case 's':
+         separator_str = optarg;
+         break;
+       case 'w':
+         {
+           long int tmp_long;
+           if (xstrtol (optarg, NULL, 10, &tmp_long, "") != LONGINT_OK
+               || tmp_long <= 0 || tmp_long > INT_MAX)
+             {
+               error (0, 0, _("invalid line number field width: %s"),
+                      quote (optarg));
+               fail = 1;
+             }
+           else
+             {
+               lineno_width = (int) tmp_long;
+             }
+         }
+         break;
+       case 'n':
+         if (STREQ (optarg, "ln"))
+           lineno_format = FORMAT_LEFT;
+         else if (STREQ (optarg, "rn"))
+           lineno_format = FORMAT_RIGHT_NOLZ;
+         else if (STREQ (optarg, "rz"))
+           lineno_format = FORMAT_RIGHT_LZ;
+         else
+           {
+             error (0, 0, _("invalid line numbering format: %s"),
+                    quote (optarg));
+             fail = 1;
+           }
+         break;
+       case 'd':
+         section_del = optarg;
+         break;
+       case_GETOPT_HELP_CHAR;
+       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, WRITTEN_BY);
+       default:
+         fail = 1;
+         break;
+       }
+    }
+
+  if (fail)
+    usage (2);
+
+  /* Initialize the section delimiters.  */
+  len = strlen (section_del);
+
+  header_del_len = len * 3;
+  header_del = xmalloc (header_del_len + 1);
+  strcat (strcat (strcpy (header_del, section_del), section_del), section_del);
+
+  body_del_len = len * 2;
+  body_del = xmalloc (body_del_len + 1);
+  strcat (strcpy (body_del, section_del), section_del);
+
+  footer_del_len = len;
+  footer_del = xmalloc (footer_del_len + 1);
+  strcpy (footer_del, section_del);
+
+  /* Initialize the input buffer.  */
+  initbuffer (&line_buf);
+
+  /* Initialize the printf format for unnumbered lines. */
+  len = strlen (separator_str);
+  print_no_line_fmt = xmalloc (lineno_width + len + 1);
+  memset (print_no_line_fmt, ' ', lineno_width + len);
+  print_no_line_fmt[lineno_width + len] = '\0';
+
+  line_no = starting_line_number;
+  current_type = body_type;
+  current_regex = &body_regex;
+  build_print_fmt ();
+
+  /* Main processing. */
+
+  if (optind == argc)
+    exit_status |= nl_file ("-");
+  else
+    for (; optind < argc; optind++)
+      exit_status |= nl_file (argv[optind]);
+
+  if (have_read_stdin && fclose (stdin) == EOF)
+    {
+      error (0, errno, "-");
+      exit_status = 1;
+    }
+
+  exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
 }