1 /* nl -- number lines of files
2 Copyright (C) 1989, 1992 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Written by Scott Bartram (nancy!scott@uunet.uu.net)
19 Revised by David MacKenzie (djm@gnu.ai.mit.edu) */
22 #if defined (CONFIG_BROKETS)
23 /* We use <config.h> instead of "config.h" so that a compilation
24 using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
25 (which it would do because it found this file in $srcdir). */
33 #include <sys/types.h>
36 #include "linebuffer.h"
45 /* Line-number formats. */
48 FORMAT_RIGHT_NOLZ, /* Right justified, no leading zeroes. */
49 FORMAT_RIGHT_LZ, /* Right justified, leading zeroes. */
50 FORMAT_LEFT /* Left justified, no leading zeroes. */
53 /* Default section delimiter characters. */
54 #define DEFAULT_SECTION_DELIMITERS "\\:"
56 /* Types of input lines: either one of the section delimiters,
60 Header, Body, Footer, Text
67 static enum section check_section ();
68 static int build_type_arg ();
69 static int nl_file ();
71 static void process_file ();
72 static void proc_header ();
73 static void proc_body ();
74 static void proc_footer ();
75 static void proc_text ();
76 static void print_lineno ();
77 static void build_print_fmt ();
79 /* The name this program was run with. */
82 /* Format of body lines (-b). */
83 static char *body_type = "t";
85 /* Format of header lines (-h). */
86 static char *header_type = "n";
88 /* Format of footer lines (-f). */
89 static char *footer_type = "n";
91 /* Format currently being used (body, header, or footer). */
92 static char *current_type;
94 /* Regex for body lines to number (-bp). */
95 static struct re_pattern_buffer body_regex;
97 /* Regex for header lines to number (-hp). */
98 static struct re_pattern_buffer header_regex;
100 /* Regex for footer lines to number (-fp). */
101 static struct re_pattern_buffer footer_regex;
103 /* Pointer to current regex, if any. */
104 static struct re_pattern_buffer *current_regex = NULL;
106 /* Separator string to print after line number (-s). */
107 static char *separator_str = "\t";
109 /* Input section delimiter string (-d). */
110 static char *section_del = DEFAULT_SECTION_DELIMITERS;
112 /* Header delimiter string. */
113 static char *header_del = NULL;
115 /* Header section delimiter length. */
116 static int header_del_len;
118 /* Body delimiter string. */
119 static char *body_del = NULL;
121 /* Body section delimiter length. */
122 static int body_del_len;
124 /* Footer delimiter string. */
125 static char *footer_del = NULL;
127 /* Footer section delimiter length. */
128 static int footer_del_len;
131 static struct linebuffer line_buf;
133 /* printf format string for line number. */
134 static char *print_fmt;
136 /* printf format string for unnumbered lines. */
137 static char *print_no_line_fmt = NULL;
139 /* Starting line number on each page (-v). */
140 static int page_start = 1;
142 /* Line number increment (-i). */
143 static int page_incr = 1;
145 /* If TRUE, reset line number at start of each page (-p). */
146 static int reset_numbers = TRUE;
148 /* Number of blank lines to consider to be one line for numbering (-l). */
149 static int blank_join = 1;
151 /* Width of line numbers (-w). */
152 static int lineno_width = 6;
154 /* Line number format (-n). */
155 static enum number_format lineno_format = FORMAT_RIGHT_NOLZ;
157 /* Current print line number. */
160 /* Nonzero if we have ever read standard input. */
161 static int have_read_stdin;
163 /* If non-zero, display usage information and exit. */
164 static int show_help;
166 /* If non-zero, print the version on standard output then exit. */
167 static int show_version;
169 static struct option const longopts[] =
171 {"header-numbering", required_argument, NULL, 'h'},
172 {"body-numbering", required_argument, NULL, 'b'},
173 {"footer-numbering", required_argument, NULL, 'f'},
174 {"first-page", required_argument, NULL, 'v'},
175 {"page-increment", required_argument, NULL, 'i'},
176 {"no-renumber", no_argument, NULL, 'p'},
177 {"join-blank-lines", required_argument, NULL, 'l'},
178 {"number-separator", required_argument, NULL, 's'},
179 {"number-width", required_argument, NULL, 'w'},
180 {"number-format", required_argument, NULL, 'n'},
181 {"section-delimiter", required_argument, NULL, 'd'},
182 {"help", no_argument, &show_help, 1},
183 {"version", no_argument, &show_version, 1},
192 int c, exit_status = 0;
194 program_name = argv[0];
197 while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
206 if (build_type_arg (&header_type, &header_regex) != TRUE)
210 if (build_type_arg (&body_type, &body_regex) != TRUE)
214 if (build_type_arg (&footer_type, &footer_regex) != TRUE)
218 page_start = atoi (optarg);
221 page_incr = atoi (optarg);
226 reset_numbers = FALSE;
229 blank_join = atoi (optarg);
232 separator_str = optarg;
235 lineno_width = atoi (optarg);
236 if (lineno_width < 1)
243 if (optarg[1] == 'n')
244 lineno_format = FORMAT_LEFT;
252 lineno_format = FORMAT_RIGHT_NOLZ;
255 lineno_format = FORMAT_RIGHT_LZ;
268 section_del = optarg;
278 printf ("%s\n", version_string);
285 /* Initialize the section delimiters. */
286 c = strlen (section_del);
288 header_del_len = c * 3;
289 header_del = xmalloc (header_del_len + 1);
290 strcat (strcat (strcpy (header_del, section_del), section_del), section_del);
292 body_del_len = c * 2;
293 body_del = xmalloc (body_del_len + 1);
294 strcat (strcpy (body_del, section_del), section_del);
297 footer_del = xmalloc (footer_del_len + 1);
298 strcpy (footer_del, section_del);
300 /* Initialize the input buffer. */
301 initbuffer (&line_buf);
303 /* Initialize the printf format for unnumbered lines. */
304 c = strlen (separator_str);
305 print_no_line_fmt = xmalloc (lineno_width + c + 1);
306 memset (print_no_line_fmt, ' ', lineno_width + c);
307 print_no_line_fmt[lineno_width + c] = '\0';
309 line_no = page_start;
310 current_type = body_type;
311 current_regex = &body_regex;
314 /* Main processing. */
317 exit_status |= nl_file ("-");
319 for (; optind < argc; optind++)
320 exit_status |= nl_file (argv[optind]);
322 if (have_read_stdin && fclose (stdin) == EOF)
324 error (0, errno, "-");
327 if (ferror (stdout) || fclose (stdout) == EOF)
328 error (1, errno, "write error");
333 /* Process file FILE to standard output.
334 Return 0 if successful, 1 if not. */
342 if (!strcmp (file, "-"))
349 stream = fopen (file, "r");
352 error (0, errno, "%s", file);
357 process_file (stream);
361 error (0, errno, "%s", file);
364 if (!strcmp (file, "-"))
365 clearerr (stream); /* Also clear EOF. */
366 else if (fclose (stream) == EOF)
368 error (0, errno, "%s", file);
374 /* Read and process the file pointed to by FP. */
380 while (readline (&line_buf, fp))
382 switch ((int) check_section ())
400 /* Return the type of line in `line_buf'. */
405 if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
407 if (line_buf.length == header_del_len
408 && !memcmp (line_buf.buffer, header_del, header_del_len))
410 if (line_buf.length == body_del_len
411 && !memcmp (line_buf.buffer, body_del, body_del_len))
413 if (line_buf.length == footer_del_len
414 && !memcmp (line_buf.buffer, footer_del, footer_del_len))
419 /* Switch to a header section. */
424 current_type = header_type;
425 current_regex = &header_regex;
427 line_no = page_start;
431 /* Switch to a body section. */
436 current_type = body_type;
437 current_regex = &body_regex;
441 /* Switch to a footer section. */
446 current_type = footer_type;
447 current_regex = &footer_regex;
451 /* Process a regular text line in `line_buf'. */
456 static int blank_lines = 0; /* Consecutive blank lines so far. */
458 switch (*current_type)
463 if (line_buf.length || ++blank_lines == blank_join)
469 printf (print_no_line_fmt);
478 printf (print_no_line_fmt);
481 printf (print_no_line_fmt);
484 if (re_search (current_regex, line_buf.buffer, line_buf.length,
485 0, line_buf.length, (struct re_registers *) 0) < 0)
486 printf (print_no_line_fmt);
491 fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
495 /* Print and increment the line number. */
500 printf (print_fmt, line_no);
501 line_no += page_incr;
504 /* Build the printf format string, based on `lineno_format'. */
509 /* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
510 print_fmt = xmalloc (strlen (separator_str) + 12);
511 switch (lineno_format)
513 case FORMAT_RIGHT_NOLZ:
514 sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
516 case FORMAT_RIGHT_LZ:
517 sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
520 sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
525 /* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
526 according to `optarg'. */
529 build_type_arg (typep, regexp)
531 struct re_pattern_buffer *regexp;
546 optlen = strlen (optarg);
547 regexp->allocated = optlen * 2;
548 regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
549 regexp->translate = NULL;
550 regexp->fastmap = xmalloc (256);
551 regexp->fastmap_accurate = 0;
552 errmsg = re_compile_pattern (optarg, optlen, regexp);
554 error (1, 0, "%s", errmsg);
563 /* Print a usage message and quit. */
570 fprintf (stderr, "Try `%s --help' for more information.\n",
575 Usage: %s [OPTION]... [FILE]...\n\
580 -b, --body-numbering=STYLE use STYLE for numbering body lines\n\
581 -d, --section-delimiter=CC use CC for separating logical pages\n\
582 -f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\
583 -h, --header-numbering=STYLE use STYLE for numbering header lines\n\
584 -i, --page-increment=NUMBER line number increment at each line\n\
585 -l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\
586 -n, --number-format=FORMAT insert line numbers according to FORMAT\n\
587 -p, --no-renumber do not reset line numbers at logical pages\n\
588 -s, --number-separator=STRING add STRING after (possible) line number\n\
589 -v, --first-page=NUMBER first line number on each logical page\n\
590 -w, --number-width=NUMBER use NUMBER columns for line numbers\n\
591 --help display this help and exit\n\
592 --version output version information and exit\n\
594 By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\
595 two delimiter characters for separating logical pages, a missing\n\
596 second character implies :. Type \\\\ for \\. STYLE is one of:\n\
598 a number all lines\n\
599 t number only nonempty lines\n\
601 pREGEXP number only lines that contain a match for REGEXP\n\
605 ln left justified, no leading zeros\n\
606 rn right justified, no leading zeros\n\
607 rz right justified, leading zeros\n\
609 With no FILE, or when FILE is -, read standard input.\n\