1 /* nl -- number lines of files
2 Copyright (C) 1989, 1992, 1995 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) */
24 #include <sys/types.h>
27 #include "linebuffer.h"
37 /* Line-number formats. */
40 FORMAT_RIGHT_NOLZ, /* Right justified, no leading zeroes. */
41 FORMAT_RIGHT_LZ, /* Right justified, leading zeroes. */
42 FORMAT_LEFT /* Left justified, no leading zeroes. */
45 /* Default section delimiter characters. */
46 #define DEFAULT_SECTION_DELIMITERS "\\:"
48 /* Types of input lines: either one of the section delimiters,
52 Header, Body, Footer, Text
58 static enum section check_section ();
59 static int build_type_arg ();
60 static int nl_file ();
62 static void process_file ();
63 static void proc_header ();
64 static void proc_body ();
65 static void proc_footer ();
66 static void proc_text ();
67 static void print_lineno ();
68 static void build_print_fmt ();
70 /* The name this program was run with. */
73 /* Format of body lines (-b). */
74 static char *body_type = "t";
76 /* Format of header lines (-h). */
77 static char *header_type = "n";
79 /* Format of footer lines (-f). */
80 static char *footer_type = "n";
82 /* Format currently being used (body, header, or footer). */
83 static char *current_type;
85 /* Regex for body lines to number (-bp). */
86 static struct re_pattern_buffer body_regex;
88 /* Regex for header lines to number (-hp). */
89 static struct re_pattern_buffer header_regex;
91 /* Regex for footer lines to number (-fp). */
92 static struct re_pattern_buffer footer_regex;
94 /* Pointer to current regex, if any. */
95 static struct re_pattern_buffer *current_regex = NULL;
97 /* Separator string to print after line number (-s). */
98 static char *separator_str = "\t";
100 /* Input section delimiter string (-d). */
101 static char *section_del = DEFAULT_SECTION_DELIMITERS;
103 /* Header delimiter string. */
104 static char *header_del = NULL;
106 /* Header section delimiter length. */
107 static int header_del_len;
109 /* Body delimiter string. */
110 static char *body_del = NULL;
112 /* Body section delimiter length. */
113 static int body_del_len;
115 /* Footer delimiter string. */
116 static char *footer_del = NULL;
118 /* Footer section delimiter length. */
119 static int footer_del_len;
122 static struct linebuffer line_buf;
124 /* printf format string for line number. */
125 static char *print_fmt;
127 /* printf format string for unnumbered lines. */
128 static char *print_no_line_fmt = NULL;
130 /* Starting line number on each page (-v). */
131 static int page_start = 1;
133 /* Line number increment (-i). */
134 static int page_incr = 1;
136 /* If TRUE, reset line number at start of each page (-p). */
137 static int reset_numbers = TRUE;
139 /* Number of blank lines to consider to be one line for numbering (-l). */
140 static int blank_join = 1;
142 /* Width of line numbers (-w). */
143 static int lineno_width = 6;
145 /* Line number format (-n). */
146 static enum number_format lineno_format = FORMAT_RIGHT_NOLZ;
148 /* Current print line number. */
151 /* Nonzero if we have ever read standard input. */
152 static int have_read_stdin;
154 /* If non-zero, display usage information and exit. */
155 static int show_help;
157 /* If non-zero, print the version on standard output then exit. */
158 static int show_version;
160 static struct option const longopts[] =
162 {"header-numbering", required_argument, NULL, 'h'},
163 {"body-numbering", required_argument, NULL, 'b'},
164 {"footer-numbering", required_argument, NULL, 'f'},
165 {"first-page", required_argument, NULL, 'v'},
166 {"page-increment", required_argument, NULL, 'i'},
167 {"no-renumber", no_argument, NULL, 'p'},
168 {"join-blank-lines", required_argument, NULL, 'l'},
169 {"number-separator", required_argument, NULL, 's'},
170 {"number-width", required_argument, NULL, 'w'},
171 {"number-format", required_argument, NULL, 'n'},
172 {"section-delimiter", required_argument, NULL, 'd'},
173 {"help", no_argument, &show_help, 1},
174 {"version", no_argument, &show_version, 1},
183 int c, exit_status = 0;
185 program_name = argv[0];
188 while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
197 if (build_type_arg (&header_type, &header_regex) != TRUE)
201 if (build_type_arg (&body_type, &body_regex) != TRUE)
205 if (build_type_arg (&footer_type, &footer_regex) != TRUE)
209 page_start = atoi (optarg);
212 page_incr = atoi (optarg);
217 reset_numbers = FALSE;
220 blank_join = atoi (optarg);
223 separator_str = optarg;
226 lineno_width = atoi (optarg);
227 if (lineno_width < 1)
234 if (optarg[1] == 'n')
235 lineno_format = FORMAT_LEFT;
243 lineno_format = FORMAT_RIGHT_NOLZ;
246 lineno_format = FORMAT_RIGHT_LZ;
259 section_del = optarg;
269 printf ("nl - %s\n", version_string);
276 /* Initialize the section delimiters. */
277 c = strlen (section_del);
279 header_del_len = c * 3;
280 header_del = xmalloc (header_del_len + 1);
281 strcat (strcat (strcpy (header_del, section_del), section_del), section_del);
283 body_del_len = c * 2;
284 body_del = xmalloc (body_del_len + 1);
285 strcat (strcpy (body_del, section_del), section_del);
288 footer_del = xmalloc (footer_del_len + 1);
289 strcpy (footer_del, section_del);
291 /* Initialize the input buffer. */
292 initbuffer (&line_buf);
294 /* Initialize the printf format for unnumbered lines. */
295 c = strlen (separator_str);
296 print_no_line_fmt = xmalloc (lineno_width + c + 1);
297 memset (print_no_line_fmt, ' ', lineno_width + c);
298 print_no_line_fmt[lineno_width + c] = '\0';
300 line_no = page_start;
301 current_type = body_type;
302 current_regex = &body_regex;
305 /* Main processing. */
308 exit_status |= nl_file ("-");
310 for (; optind < argc; optind++)
311 exit_status |= nl_file (argv[optind]);
313 if (have_read_stdin && fclose (stdin) == EOF)
315 error (0, errno, "-");
318 if (ferror (stdout) || fclose (stdout) == EOF)
319 error (1, errno, "write error");
324 /* Process file FILE to standard output.
325 Return 0 if successful, 1 if not. */
333 if (!strcmp (file, "-"))
340 stream = fopen (file, "r");
343 error (0, errno, "%s", file);
348 process_file (stream);
352 error (0, errno, "%s", file);
355 if (!strcmp (file, "-"))
356 clearerr (stream); /* Also clear EOF. */
357 else if (fclose (stream) == EOF)
359 error (0, errno, "%s", file);
365 /* Read and process the file pointed to by FP. */
371 while (readline (&line_buf, fp))
373 switch ((int) check_section ())
391 /* Return the type of line in `line_buf'. */
396 if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
398 if (line_buf.length == header_del_len
399 && !memcmp (line_buf.buffer, header_del, header_del_len))
401 if (line_buf.length == body_del_len
402 && !memcmp (line_buf.buffer, body_del, body_del_len))
404 if (line_buf.length == footer_del_len
405 && !memcmp (line_buf.buffer, footer_del, footer_del_len))
410 /* Switch to a header section. */
415 current_type = header_type;
416 current_regex = &header_regex;
418 line_no = page_start;
422 /* Switch to a body section. */
427 current_type = body_type;
428 current_regex = &body_regex;
432 /* Switch to a footer section. */
437 current_type = footer_type;
438 current_regex = &footer_regex;
442 /* Process a regular text line in `line_buf'. */
447 static int blank_lines = 0; /* Consecutive blank lines so far. */
449 switch (*current_type)
454 if (line_buf.length || ++blank_lines == blank_join)
460 printf (print_no_line_fmt);
469 printf (print_no_line_fmt);
472 printf (print_no_line_fmt);
475 if (re_search (current_regex, line_buf.buffer, line_buf.length,
476 0, line_buf.length, (struct re_registers *) 0) < 0)
477 printf (print_no_line_fmt);
482 fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
486 /* Print and increment the line number. */
491 printf (print_fmt, line_no);
492 line_no += page_incr;
495 /* Build the printf format string, based on `lineno_format'. */
500 /* 12 = 10 chars for lineno_width, 1 for %, 1 for \0. */
501 print_fmt = xmalloc (strlen (separator_str) + 12);
502 switch (lineno_format)
504 case FORMAT_RIGHT_NOLZ:
505 sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
507 case FORMAT_RIGHT_LZ:
508 sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
511 sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
516 /* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
517 according to `optarg'. */
520 build_type_arg (typep, regexp)
522 struct re_pattern_buffer *regexp;
537 optlen = strlen (optarg);
538 regexp->allocated = optlen * 2;
539 regexp->buffer = (unsigned char *) xmalloc (regexp->allocated);
540 regexp->translate = NULL;
541 regexp->fastmap = xmalloc (256);
542 regexp->fastmap_accurate = 0;
543 errmsg = re_compile_pattern (optarg, optlen, regexp);
545 error (1, 0, "%s", errmsg);
554 /* Print a usage message and quit. */
561 fprintf (stderr, "Try `%s --help' for more information.\n",
566 Usage: %s [OPTION]... [FILE]...\n\
571 -b, --body-numbering=STYLE use STYLE for numbering body lines\n\
572 -d, --section-delimiter=CC use CC for separating logical pages\n\
573 -f, --footer-numbering=STYLE use STYLE for numbering footer lines\n\
574 -h, --header-numbering=STYLE use STYLE for numbering header lines\n\
575 -i, --page-increment=NUMBER line number increment at each line\n\
576 -l, --join-blank-lines=NUMBER group of NUMBER empty lines counted as one\n\
577 -n, --number-format=FORMAT insert line numbers according to FORMAT\n\
578 -p, --no-renumber do not reset line numbers at logical pages\n\
579 -s, --number-separator=STRING add STRING after (possible) line number\n\
580 -v, --first-page=NUMBER first line number on each logical page\n\
581 -w, --number-width=NUMBER use NUMBER columns for line numbers\n\
582 --help display this help and exit\n\
583 --version output version information and exit\n\
585 By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn. CC are\n\
586 two delimiter characters for separating logical pages, a missing\n\
587 second character implies :. Type \\\\ for \\. STYLE is one of:\n\
589 a number all lines\n\
590 t number only nonempty lines\n\
592 pREGEXP number only lines that contain a match for REGEXP\n\
596 ln left justified, no leading zeros\n\
597 rn right justified, no leading zeros\n\
598 rz right justified, leading zeros\n\
600 With no FILE, or when FILE is -, read standard input.\n\