.
[platform/upstream/coreutils.git] / src / nl.c
1 /* nl -- number lines of files
2    Copyright (C) 1989, 1992 Free Software Foundation, Inc.
3
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)
7    any later version.
8
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.
13
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.  */
17 \f
18 /* Written by Scott Bartram (nancy!scott@uunet.uu.net)
19    Revised by David MacKenzie (djm@gnu.ai.mit.edu) */
20
21 #ifdef HAVE_CONFIG_H
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).  */
26 #include <config.h>
27 #else
28 #include "config.h"
29 #endif
30 #endif
31
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <getopt.h>
35 #include <regex.h>
36 #include "linebuffer.h"
37 #include "system.h"
38 #include "version.h"
39
40 #ifndef TRUE
41 #define TRUE   1
42 #define FALSE  0
43 #endif
44
45 /* Line-number formats. */
46 enum number_format
47 {
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.  */
51 };
52
53 /* Default section delimiter characters.  */
54 #define DEFAULT_SECTION_DELIMITERS  "\\:"
55
56 /* Types of input lines: either one of the section delimiters,
57    or text to output. */
58 enum section
59 {
60   Header, Body, Footer, Text
61 };
62
63 char *xmalloc ();
64 char *xrealloc ();
65 void error ();
66
67 static enum section check_section ();
68 static int build_type_arg ();
69 static int nl_file ();
70 static void usage ();
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 ();
78
79 /* The name this program was run with. */
80 char *program_name;
81
82 /* Format of body lines (-b).  */
83 static char *body_type = "t";
84
85 /* Format of header lines (-h).  */
86 static char *header_type = "n";
87
88 /* Format of footer lines (-f).  */
89 static char *footer_type = "n";
90
91 /* Format currently being used (body, header, or footer).  */
92 static char *current_type;
93
94 /* Regex for body lines to number (-bp).  */
95 static struct re_pattern_buffer body_regex;
96
97 /* Regex for header lines to number (-hp).  */
98 static struct re_pattern_buffer header_regex;
99
100 /* Regex for footer lines to number (-fp).  */
101 static struct re_pattern_buffer footer_regex;
102
103 /* Pointer to current regex, if any.  */
104 static struct re_pattern_buffer *current_regex = NULL;
105
106 /* Separator string to print after line number (-s).  */
107 static char *separator_str = "\t";
108
109 /* Input section delimiter string (-d).  */
110 static char *section_del = DEFAULT_SECTION_DELIMITERS;
111
112 /* Header delimiter string.  */
113 static char *header_del = NULL;
114
115 /* Header section delimiter length.  */
116 static int header_del_len;
117
118 /* Body delimiter string.  */
119 static char *body_del = NULL;
120
121 /* Body section delimiter length.  */
122 static int body_del_len;
123
124 /* Footer delimiter string.  */
125 static char *footer_del = NULL;
126
127 /* Footer section delimiter length.  */
128 static int footer_del_len;
129
130 /* Input buffer.  */
131 static struct linebuffer line_buf;
132
133 /* printf format string for line number.  */
134 static char *print_fmt;
135
136 /* printf format string for unnumbered lines.  */
137 static char *print_no_line_fmt = NULL;
138
139 /* Starting line number on each page (-v).  */
140 static int page_start = 1;
141
142 /* Line number increment (-i).  */
143 static int page_incr = 1;
144
145 /* If TRUE, reset line number at start of each page (-p).  */
146 static int reset_numbers = TRUE;
147
148 /* Number of blank lines to consider to be one line for numbering (-l).  */
149 static int blank_join = 1;
150
151 /* Width of line numbers (-w).  */
152 static int lineno_width = 6;
153
154 /* Line number format (-n).  */
155 static enum number_format lineno_format = FORMAT_RIGHT_NOLZ;
156
157 /* Current print line number.  */
158 static int line_no;
159
160 /* Nonzero if we have ever read standard input. */
161 static int have_read_stdin;
162
163 /* If non-zero, display usage information and exit.  */
164 static int show_help;
165
166 /* If non-zero, print the version on standard output then exit.  */
167 static int show_version;
168
169 static struct option const longopts[] =
170 {
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},
184   {NULL, 0, NULL, 0}
185 };
186
187 void
188 main (argc, argv)
189      int argc;
190      char **argv;
191 {
192   int c, exit_status = 0;
193
194   program_name = argv[0];
195   have_read_stdin = 0;
196
197   while ((c = getopt_long (argc, argv, "h:b:f:v:i:pl:s:w:n:d:", longopts,
198                            (int *) 0)) != EOF)
199     {
200       switch (c)
201         {
202         case 0:
203           break;
204
205         case 'h':
206           if (build_type_arg (&header_type, &header_regex) != TRUE)
207             usage (2);
208           break;
209         case 'b':
210           if (build_type_arg (&body_type, &body_regex) != TRUE)
211             usage (2);
212           break;
213         case 'f':
214           if (build_type_arg (&footer_type, &footer_regex) != TRUE)
215             usage (2);
216           break;
217         case 'v':
218           page_start = atoi (optarg);
219           break;
220         case 'i':
221           page_incr = atoi (optarg);
222           if (page_incr < 1)
223             page_incr = 1;
224           break;
225         case 'p':
226           reset_numbers = FALSE;
227           break;
228         case 'l':
229           blank_join = atoi (optarg);
230           break;
231         case 's':
232           separator_str = optarg;
233           break;
234         case 'w':
235           lineno_width = atoi (optarg);
236           if (lineno_width < 1)
237             lineno_width = 1;
238           break;
239         case 'n':
240           switch (*optarg)
241             {
242             case 'l':
243               if (optarg[1] == 'n')
244                 lineno_format = FORMAT_LEFT;
245               else
246                 usage (2);
247               break;
248             case 'r':
249               switch (optarg[1])
250                 {
251                 case 'n':
252                   lineno_format = FORMAT_RIGHT_NOLZ;
253                   break;
254                 case 'z':
255                   lineno_format = FORMAT_RIGHT_LZ;
256                   break;
257                 default:
258                   usage (2);
259                   break;
260                 }
261               break;
262             default:
263               usage (2);
264               break;
265             }
266           break;
267         case 'd':
268           section_del = optarg;
269           break;
270         default:
271           usage (2);
272           break;
273         }
274     }
275
276   if (show_version)
277     {
278       printf ("nl - %s\n", version_string);
279       exit (0);
280     }
281
282   if (show_help)
283     usage (0);
284
285   /* Initialize the section delimiters.  */
286   c = strlen (section_del);
287
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);
291
292   body_del_len = c * 2;
293   body_del = xmalloc (body_del_len + 1);
294   strcat (strcpy (body_del, section_del), section_del);
295
296   footer_del_len = c;
297   footer_del = xmalloc (footer_del_len + 1);
298   strcpy (footer_del, section_del);
299
300   /* Initialize the input buffer.  */
301   initbuffer (&line_buf);
302
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';
308
309   line_no = page_start;
310   current_type = body_type;
311   current_regex = &body_regex;
312   build_print_fmt ();
313
314   /* Main processing. */
315
316   if (optind == argc)
317     exit_status |= nl_file ("-");
318   else
319     for (; optind < argc; optind++)
320       exit_status |= nl_file (argv[optind]);
321
322   if (have_read_stdin && fclose (stdin) == EOF)
323     {
324       error (0, errno, "-");
325       exit_status = 1;
326     }
327   if (ferror (stdout) || fclose (stdout) == EOF)
328     error (1, errno, "write error");
329
330   exit (exit_status);
331 }
332 \f
333 /* Process file FILE to standard output.
334    Return 0 if successful, 1 if not. */
335
336 static int
337 nl_file (file)
338      char *file;
339 {
340   FILE *stream;
341
342   if (!strcmp (file, "-"))
343     {
344       have_read_stdin = 1;
345       stream = stdin;
346     }
347   else
348     {
349       stream = fopen (file, "r");
350       if (stream == NULL)
351         {
352           error (0, errno, "%s", file);
353           return 1;
354         }
355     }
356
357   process_file (stream);
358
359   if (ferror (stream))
360     {
361       error (0, errno, "%s", file);
362       return 1;
363     }
364   if (!strcmp (file, "-"))
365     clearerr (stream);          /* Also clear EOF. */
366   else if (fclose (stream) == EOF)
367     {
368       error (0, errno, "%s", file);
369       return 1;
370     }
371   return 0;
372 }
373
374 /* Read and process the file pointed to by FP. */
375
376 static void
377 process_file (fp)
378      FILE *fp;
379 {
380   while (readline (&line_buf, fp))
381     {
382       switch ((int) check_section ())
383         {
384         case Header:
385           proc_header ();
386           break;
387         case Body:
388           proc_body ();
389           break;
390         case Footer:
391           proc_footer ();
392           break;
393         case Text:
394           proc_text ();
395           break;
396         }
397     }
398 }
399 \f
400 /* Return the type of line in `line_buf'. */
401
402 static enum section
403 check_section ()
404 {
405   if (line_buf.length < 2 || memcmp (line_buf.buffer, section_del, 2))
406     return Text;
407   if (line_buf.length == header_del_len
408       && !memcmp (line_buf.buffer, header_del, header_del_len))
409     return Header;
410   if (line_buf.length == body_del_len
411       && !memcmp (line_buf.buffer, body_del, body_del_len))
412     return Body;
413   if (line_buf.length == footer_del_len
414       && !memcmp (line_buf.buffer, footer_del, footer_del_len))
415     return Footer;
416   return Text;
417 }
418
419 /* Switch to a header section. */
420
421 static void
422 proc_header ()
423 {
424   current_type = header_type;
425   current_regex = &header_regex;
426   if (reset_numbers)
427     line_no = page_start;
428   putchar ('\n');
429 }
430
431 /* Switch to a body section. */
432
433 static void
434 proc_body ()
435 {
436   current_type = body_type;
437   current_regex = &body_regex;
438   putchar ('\n');
439 }
440
441 /* Switch to a footer section. */
442
443 static void
444 proc_footer ()
445 {
446   current_type = footer_type;
447   current_regex = &footer_regex;
448   putchar ('\n');
449 }
450
451 /* Process a regular text line in `line_buf'. */
452
453 static void
454 proc_text ()
455 {
456   static int blank_lines = 0;   /* Consecutive blank lines so far. */
457
458   switch (*current_type)
459     {
460     case 'a':
461       if (blank_join > 1)
462         {
463           if (line_buf.length || ++blank_lines == blank_join)
464             {
465               print_lineno ();
466               blank_lines = 0;
467             }
468           else
469             printf (print_no_line_fmt);
470         }
471       else
472         print_lineno ();
473       break;
474     case 't':
475       if (line_buf.length)
476         print_lineno ();
477       else
478         printf (print_no_line_fmt);
479       break;
480     case 'n':
481       printf (print_no_line_fmt);
482       break;
483     case 'p':
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);
487       else
488         print_lineno ();
489       break;
490     }
491   fwrite (line_buf.buffer, sizeof (char), line_buf.length, stdout);
492   putchar ('\n');
493 }
494 \f
495 /* Print and increment the line number. */
496
497 static void
498 print_lineno ()
499 {
500   printf (print_fmt, line_no);
501   line_no += page_incr;
502 }
503
504 /* Build the printf format string, based on `lineno_format'. */
505
506 static void
507 build_print_fmt ()
508 {
509   /* 12 = 10 chars for lineno_width, 1 for %, 1 for \0.  */
510   print_fmt = xmalloc (strlen (separator_str) + 12);
511   switch (lineno_format)
512     {
513     case FORMAT_RIGHT_NOLZ:
514       sprintf (print_fmt, "%%%dd%s", lineno_width, separator_str);
515       break;
516     case FORMAT_RIGHT_LZ:
517       sprintf (print_fmt, "%%0%dd%s", lineno_width, separator_str);
518       break;
519     case FORMAT_LEFT:
520       sprintf (print_fmt, "%%-%dd%s", lineno_width, separator_str);
521       break;
522     }
523 }
524
525 /* Set the command line flag TYPEP and possibly the regex pointer REGEXP,
526    according to `optarg'.  */
527
528 static int
529 build_type_arg (typep, regexp)
530      char **typep;
531      struct re_pattern_buffer *regexp;
532 {
533   const char *errmsg;
534   int rval = TRUE;
535   int optlen;
536
537   switch (*optarg)
538     {
539     case 'a':
540     case 't':
541     case 'n':
542       *typep = optarg;
543       break;
544     case 'p':
545       *typep = optarg++;
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);
553       if (errmsg)
554         error (1, 0, "%s", errmsg);
555       break;
556     default:
557       rval = FALSE;
558       break;
559     }
560   return rval;
561 }
562 \f
563 /* Print a usage message and quit. */
564
565 static void
566 usage (status)
567      int status;
568 {
569   if (status != 0)
570     fprintf (stderr, "Try `%s --help' for more information.\n",
571              program_name);
572   else
573     {
574       printf ("\
575 Usage: %s [OPTION]... [FILE]...\n\
576 ",
577               program_name);
578       printf ("\
579 \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\
593 \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\
597 \n\
598   a         number all lines\n\
599   t         number only nonempty lines\n\
600   n         number no lines\n\
601   pREGEXP   number only lines that contain a match for REGEXP\n\
602 \n\
603 FORMAT is one of:\n\
604 \n\
605   ln   left justified, no leading zeros\n\
606   rn   right justified, no leading zeros\n\
607   rz   right justified, leading zeros\n\
608 \n\
609 With no FILE, or when FILE is -, read standard input.\n\
610 ");
611     }
612   exit (status);
613 }