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