merge with 1.8d
[platform/upstream/coreutils.git] / src / tac.c
1 /* tac - concatenate and print files in reverse
2    Copyright (C) 1988, 1989, 1990, 1991 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
18 /* Written by Jay Lepreau (lepreau@cs.utah.edu).
19    GNU enhancements by David MacKenzie (djm@gnu.ai.mit.edu). */
20
21 /* Copy each FILE, or the standard input if none are given or when a
22    FILE name of "-" is encountered, to the standard output with the
23    order of the records reversed.  The records are separated by
24    instances of a string, or a newline if none is given.  By default, the
25    separator string is attached to the end of the record that it
26    follows in the file.
27
28    Options:
29    -b, --before                 The separator is attached to the beginning
30                                 of the record that it precedes in the file.
31    -r, --regex                  The separator is a regular expression.
32    -s, --separator=separator    Use SEPARATOR as the record separator.
33
34    To reverse a file byte by byte, use (in bash, ksh, or sh):
35 tac -r -s '.\|
36 ' file */
37
38 #ifdef HAVE_CONFIG_H
39 #if defined (CONFIG_BROKETS)
40 /* We use <config.h> instead of "config.h" so that a compilation
41    using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
42    (which it would do because it found this file in $srcdir).  */
43 #include <config.h>
44 #else
45 #include "config.h"
46 #endif
47 #endif
48
49 #include <stdio.h>
50 #include <getopt.h>
51 #include <sys/types.h>
52 #include <signal.h>
53 #include <regex.h>
54 #include "system.h"
55 #include "version.h"
56
57 #ifndef STDC_HEADERS
58 char *malloc ();
59 char *realloc ();
60 #endif
61
62 /* The number of bytes per atomic read. */
63 #define INITIAL_READSIZE 8192
64
65 /* The number of bytes per atomic write. */
66 #define WRITESIZE 8192
67
68 char *mktemp ();
69
70 static RETSIGTYPE cleanup ();
71 static int tac ();
72 static int tac_file ();
73 static int tac_stdin ();
74 static char *xmalloc ();
75 static char *xrealloc ();
76 static void output ();
77 static void save_stdin ();
78 static void xwrite ();
79
80 void error ();
81
82 /* The name this program was run with. */
83 char *program_name;
84
85 /* The string that separates the records of the file. */
86 static char *separator;
87
88 /* If nonzero, print `separator' along with the record preceding it
89    in the file; otherwise with the record following it. */
90 static int separator_ends_record;
91
92 /* 0 if `separator' is to be matched as a regular expression;
93    otherwise, the length of `separator', used as a sentinel to
94    stop the search. */
95 static int sentinel_length;
96
97 /* The length of a match with `separator'.  If `sentinel_length' is 0,
98    `match_length' is computed every time a match succeeds;
99    otherwise, it is simply the length of `separator'. */
100 static int match_length;
101
102 /* The input buffer. */
103 static char *buffer;
104
105 /* The number of bytes to read at once into `buffer'. */
106 static unsigned read_size;
107
108 /* The size of `buffer'.  This is read_size * 2 + sentinel_length + 2.
109    The extra 2 bytes allow `past_end' to have a value beyond the
110    end of `buffer' and `match_start' to run off the front of `buffer'. */
111 static unsigned buffer_size;
112
113 /* The compiled regular expression representing `separator'. */
114 static struct re_pattern_buffer compiled_separator;
115
116 /* If non-zero, display usage information and exit.  */
117 static int show_help;
118
119 /* If non-zero, print the version on standard output then exit.  */
120 static int show_version;
121
122 static struct option const longopts[] =
123 {
124   {"before", no_argument, &separator_ends_record, 0},
125   {"regex", no_argument, &sentinel_length, 0},
126   {"separator", required_argument, NULL, 's'},
127   {"help", no_argument, &show_help, 1},
128   {"version", no_argument, &show_version, 1},
129   {NULL, 0, NULL, 0}
130 };
131
132 static void
133 usage ()
134 {
135   fprintf (stderr, "\
136 Usage: %s [-br] [-s separator] [--before] [--regex] [--separator=separator]\n\
137       [--help] [--version] [file...]\n",
138            program_name);
139   exit (1);
140 }
141
142 void
143 main (argc, argv)
144      int argc;
145      char **argv;
146 {
147   const char *error_message;    /* Return value from re_compile_pattern. */
148   int optc, errors;
149   int have_read_stdin = 0;
150
151   program_name = argv[0];
152   errors = 0;
153   separator = "\n";
154   sentinel_length = 1;
155   separator_ends_record = 1;
156
157   while ((optc = getopt_long (argc, argv, "brs:", longopts, (int *) 0))
158          != EOF)
159     {
160       switch (optc)
161         {
162         case 0:
163           break;
164         case 'b':
165           separator_ends_record = 0;
166           break;
167         case 'r':
168           sentinel_length = 0;
169           break;
170         case 's':
171           separator = optarg;
172           if (*separator == 0)
173             error (1, 0, "separator cannot be empty");
174           break;
175         default:
176           usage ();
177         }
178     }
179
180   if (show_version)
181     {
182       printf ("%s\n", version_string);
183       exit (0);
184     }
185
186   if (show_help)
187     usage ();
188
189   if (sentinel_length == 0)
190     {
191       compiled_separator.allocated = 100;
192       compiled_separator.buffer = (unsigned char *)
193         xmalloc (compiled_separator.allocated);
194       compiled_separator.fastmap = xmalloc (256);
195       compiled_separator.translate = 0;
196       error_message = re_compile_pattern (separator, strlen (separator),
197                                           &compiled_separator);
198       if (error_message)
199         error (1, 0, "%s", error_message);
200     }
201   else
202     match_length = sentinel_length = strlen (separator);
203
204   read_size = INITIAL_READSIZE;
205   /* A precaution that will probably never be needed. */
206   while (sentinel_length * 2 >= read_size)
207     read_size *= 2;
208   buffer_size = read_size * 2 + sentinel_length + 2;
209   buffer = xmalloc (buffer_size);
210   if (sentinel_length)
211     {
212       strcpy (buffer, separator);
213       buffer += sentinel_length;
214     }
215   else
216     ++buffer;
217
218   if (optind == argc)
219     {
220       have_read_stdin = 1;
221       errors = tac_stdin ();
222     }
223   else
224     for (; optind < argc; ++optind)
225       {
226         if (strcmp (argv[optind], "-") == 0)
227           {
228             have_read_stdin = 1;
229             errors |= tac_stdin ();
230           }
231         else
232           errors |= tac_file (argv[optind]);
233       }
234
235   /* Flush the output buffer. */
236   output ((char *) NULL, (char *) NULL);
237
238   if (have_read_stdin && close (0) < 0)
239     error (1, errno, "-");
240   if (close (1) < 0)
241     error (1, errno, "write error");
242   exit (errors);
243 }
244
245 /* The name of a temporary file containing a copy of pipe input. */
246 char *tempfile;
247
248 /* Print the standard input in reverse, saving it to temporary
249    file `tempfile' first if it is a pipe.
250    Return 0 if ok, 1 if an error occurs. */
251
252 static int
253 tac_stdin ()
254 {
255   /* Previous values of signal handlers. */
256   RETSIGTYPE (*sigint) (), (*sighup) (), (*sigpipe) (), (*sigterm) ();
257   int errors;
258   struct stat stats;
259 #ifdef _POSIX_VERSION
260     struct sigaction oldact, newact;
261 #endif                          /* _POSIX_VERSION */
262
263   /* No tempfile is needed for "tac < file".
264      Use fstat instead of checking for errno == ESPIPE because
265      lseek doesn't work on some special files but doesn't return an
266      error, either. */
267   if (fstat (0, &stats))
268     {
269       error (0, errno, "standard input");
270       return 1;
271     }
272   if (S_ISREG (stats.st_mode))
273     return tac (0, "standard input");
274
275 #ifdef _POSIX_VERSION
276   newact.sa_handler = cleanup;
277   sigemptyset (&newact.sa_mask);
278   newact.sa_flags = 0;
279
280   sigaction (SIGINT, NULL, &oldact);
281   sigint = oldact.sa_handler;
282   if (sigint != SIG_IGN)
283     sigaction (SIGINT, &newact, NULL);
284
285   sigaction (SIGHUP, NULL, &oldact);
286   sighup = oldact.sa_handler;
287   if (sighup != SIG_IGN)
288     sigaction (SIGHUP, &newact, NULL);
289
290   sigaction (SIGPIPE, NULL, &oldact);
291   sigpipe = oldact.sa_handler;
292   if (sigpipe != SIG_IGN)
293     sigaction (SIGPIPE, &newact, NULL);
294
295   sigaction (SIGTERM, NULL, &oldact);
296   sigterm = oldact.sa_handler;
297   if (sigterm != SIG_IGN)
298     sigaction (SIGTERM, &newact, NULL);
299 #else                           /* !_POSIX_VERSION */
300   sigint = signal (SIGINT, SIG_IGN);
301   if (sigint != SIG_IGN)
302     signal (SIGINT, cleanup);
303
304   sighup = signal (SIGHUP, SIG_IGN);
305   if (sighup != SIG_IGN)
306     signal (SIGHUP, cleanup);
307
308   sigpipe = signal (SIGPIPE, SIG_IGN);
309   if (sigpipe != SIG_IGN)
310     signal (SIGPIPE, cleanup);
311
312   sigterm = signal (SIGTERM, SIG_IGN);
313   if (sigterm != SIG_IGN)
314     signal (SIGTERM, cleanup);
315 #endif                          /* _POSIX_VERSION */
316
317   save_stdin ();
318
319   errors = tac_file (tempfile);
320
321   unlink (tempfile);
322
323 #ifdef _POSIX_VERSION
324   newact.sa_handler = sigint;
325   sigaction (SIGINT, &newact, NULL);
326   newact.sa_handler = sighup;
327   sigaction (SIGHUP, &newact, NULL);
328   newact.sa_handler = sigterm;
329   sigaction (SIGTERM, &newact, NULL);
330   newact.sa_handler = sigpipe;
331   sigaction (SIGPIPE, &newact, NULL);
332 #else                           /* !_POSIX_VERSION */
333   signal (SIGINT, sigint);
334   signal (SIGHUP, sighup);
335   signal (SIGTERM, sigterm);
336   signal (SIGPIPE, sigpipe);
337 #endif                          /* _POSIX_VERSION */
338
339   return errors;
340 }
341
342 /* Make a copy of the standard input in `tempfile'. */
343
344 static void
345 save_stdin ()
346 {
347   static char *template = NULL;
348   static char *tempdir;
349   int fd;
350   int bytes_read;
351
352   if (template == NULL)
353     {
354       tempdir = getenv ("TMPDIR");
355       if (tempdir == NULL)
356         tempdir = "/tmp";
357       template = xmalloc (strlen (tempdir) + 11);
358     }
359   sprintf (template, "%s/tacXXXXXX", tempdir);
360   tempfile = mktemp (template);
361
362   fd = creat (tempfile, 0600);
363   if (fd == -1)
364     {
365       error (0, errno, "%s", tempfile);
366       cleanup ();
367     }
368   while ((bytes_read = read (0, buffer, read_size)) > 0)
369     if (write (fd, buffer, bytes_read) != bytes_read)
370       {
371         error (0, errno, "%s", tempfile);
372         cleanup ();
373       }
374   if (close (fd) < 0)
375     {
376       error (0, errno, "%s", tempfile);
377       cleanup ();
378     }
379   if (bytes_read == -1)
380     {
381       error (0, errno, "read error");
382       cleanup ();
383     }
384 }
385
386 /* Print FILE in reverse.
387    Return 0 if ok, 1 if an error occurs. */
388
389 static int
390 tac_file (file)
391      char *file;
392 {
393   int fd, errors;
394
395   fd = open (file, 0);
396   if (fd == -1)
397     {
398       error (0, errno, "%s", file);
399       return 1;
400     }
401   errors = tac (fd, file);
402   if (close (fd) < 0)
403     {
404       error (0, errno, "%s", file);
405       return 1;
406     }
407   return errors;
408 }
409
410 /* Print in reverse the file open on descriptor FD for reading FILE.
411    Return 0 if ok, 1 if an error occurs. */
412
413 static int
414 tac (fd, file)
415      int fd;
416      char *file;
417 {
418   /* Pointer to the location in `buffer' where the search for
419      the next separator will begin. */
420   char *match_start;
421   /* Pointer to one past the rightmost character in `buffer' that
422      has not been printed yet. */
423   char *past_end;
424   unsigned saved_record_size;   /* Length of the record growing in `buffer'. */
425   off_t file_pos;               /* Offset in the file of the next read. */
426   /* Nonzero if `output' has not been called yet for any file.
427      Only used when the separator is attached to the preceding record. */
428   int first_time = 1;
429   char first_char = *separator; /* Speed optimization, non-regexp. */
430   char *separator1 = separator + 1; /* Speed optimization, non-regexp. */
431   int match_length1 = match_length - 1; /* Speed optimization, non-regexp. */
432   struct re_registers regs;
433
434   /* Find the size of the input file. */
435   file_pos = lseek (fd, (off_t) 0, SEEK_END);
436   if (file_pos < 1)
437     return 0;                   /* It's an empty file. */
438
439   /* Arrange for the first read to lop off enough to leave the rest of the
440      file a multiple of `read_size'.  Since `read_size' can change, this may
441      not always hold during the program run, but since it usually will, leave
442      it here for i/o efficiency (page/sector boundaries and all that).
443      Note: the efficiency gain has not been verified. */
444   saved_record_size = file_pos % read_size;
445   if (saved_record_size == 0)
446     saved_record_size = read_size;
447   file_pos -= saved_record_size;
448   /* `file_pos' now points to the start of the last (probably partial) block
449      in the input file. */
450
451   lseek (fd, file_pos, SEEK_SET);
452   if (read (fd, buffer, saved_record_size) != saved_record_size)
453     {
454       error (0, 1, "%s", file);
455       return 1;
456     }
457
458   match_start = past_end = buffer + saved_record_size;
459   /* For non-regexp search, move past impossible positions for a match. */
460   if (sentinel_length)
461     match_start -= match_length1;
462
463   for (;;)
464     {
465       /* Search backward from `match_start' - 1 to `buffer' for a match
466          with `separator'; for speed, use strncmp if `separator' contains no
467          metacharacters.
468          If the match succeeds, set `match_start' to point to the start of
469          the match and `match_length' to the length of the match.
470          Otherwise, make `match_start' < `buffer'. */
471       if (sentinel_length == 0)
472         {
473           int i = match_start - buffer;
474           int ret;
475
476           ret = re_search (&compiled_separator, buffer, i, i - 1, -i, &regs);
477           if (ret == -1)
478             match_start = buffer - 1;
479           else if (ret == -2)
480             {
481               error (0, 0, "error in regular expression search");
482               cleanup ();
483             }
484           else
485             {
486               match_start = buffer + regs.start[0];
487               match_length = regs.end[0] - regs.start[0];
488             }
489         }
490       else
491         {
492           /* `match_length' is constant for non-regexp boundaries. */
493           while (*--match_start != first_char
494                  || (match_length1 && strncmp (match_start + 1, separator1,
495                                                match_length1)))
496             /* Do nothing. */ ;
497         }
498
499       /* Check whether we backed off the front of `buffer' without finding
500          a match for `separator'. */
501       if (match_start < buffer)
502         {
503           if (file_pos == 0)
504             {
505               /* Hit the beginning of the file; print the remaining record. */
506               output (buffer, past_end);
507               return 0;
508             }
509
510           saved_record_size = past_end - buffer;
511           if (saved_record_size > read_size)
512             {
513               /* `buffer_size' is about twice `read_size', so since
514                  we want to read in another `read_size' bytes before
515                  the data already in `buffer', we need to increase
516                  `buffer_size'. */
517               char *newbuffer;
518               int offset = sentinel_length ? sentinel_length : 1;
519
520               read_size *= 2;
521               buffer_size = read_size * 2 + sentinel_length + 2;
522               newbuffer = xrealloc (buffer - offset, buffer_size) + offset;
523               /* Adjust the pointers for the new buffer location.  */
524               match_start += newbuffer - buffer;
525               past_end += newbuffer - buffer;
526               buffer = newbuffer;
527             }
528
529           /* Back up to the start of the next bufferfull of the file.  */
530           if (file_pos >= read_size)
531             file_pos -= read_size;
532           else
533             {
534               read_size = file_pos;
535               file_pos = 0;
536             }
537           lseek (fd, file_pos, SEEK_SET);
538
539           /* Shift the pending record data right to make room for the new. */
540           bcopy (buffer, buffer + read_size, saved_record_size);
541           past_end = buffer + read_size + saved_record_size;
542           /* For non-regexp searches, avoid unneccessary scanning. */
543           if (sentinel_length)
544             match_start = buffer + read_size;
545           else
546             match_start = past_end;
547
548           if (read (fd, buffer, read_size) != read_size)
549             {
550               error (0, errno, "%s", file);
551               return 1;
552             }
553         }
554       else
555         {
556           /* Found a match of `separator'. */
557           if (separator_ends_record)
558             {
559               char *match_end = match_start + match_length;
560
561               /* If this match of `separator' isn't at the end of the
562                  file, print the record. */
563               if (first_time == 0 || match_end != past_end)
564                 output (match_end, past_end);
565               past_end = match_end;
566               first_time = 0;
567             }
568           else
569             {
570               output (match_start, past_end);
571               past_end = match_start;
572             }
573           match_start -= match_length - 1;
574         }
575     }
576 }
577
578 /* Print the characters from START to PAST_END - 1.
579    If START is NULL, just flush the buffer. */
580
581 static void
582 output (start, past_end)
583      char *start;
584      char *past_end;
585 {
586   static char buffer[WRITESIZE];
587   static int bytes_in_buffer = 0;
588   int bytes_to_add = past_end - start;
589   int bytes_available = WRITESIZE - bytes_in_buffer;
590
591   if (start == 0)
592     {
593       xwrite (1, buffer, bytes_in_buffer);
594       bytes_in_buffer = 0;
595       return;
596     }
597
598   /* Write out as many full buffers as possible. */
599   while (bytes_to_add >= bytes_available)
600     {
601       bcopy (start, buffer + bytes_in_buffer, bytes_available);
602       bytes_to_add -= bytes_available;
603       start += bytes_available;
604       xwrite (1, buffer, WRITESIZE);
605       bytes_in_buffer = 0;
606       bytes_available = WRITESIZE;
607     }
608
609   bcopy (start, buffer + bytes_in_buffer, bytes_to_add);
610   bytes_in_buffer += bytes_to_add;
611 }
612
613 static RETSIGTYPE
614 cleanup ()
615 {
616   unlink (tempfile);
617   exit (1);
618 }
619
620 static void
621 xwrite (desc, buffer, size)
622      int desc;
623      char *buffer;
624      int size;
625 {
626   if (write (desc, buffer, size) != size)
627     {
628       error (0, errno, "write error");
629       cleanup ();
630     }
631 }
632
633 /* Allocate N bytes of memory dynamically, with error checking.  */
634
635 static char *
636 xmalloc (n)
637      unsigned n;
638 {
639   char *p;
640
641   p = malloc (n);
642   if (p == 0)
643     {
644       error (0, 0, "virtual memory exhausted");
645       cleanup ();
646     }
647   return p;
648 }
649
650 /* Change the size of memory area P to N bytes, with error checking. */
651
652 static char *
653 xrealloc (p, n)
654      char *p;
655      unsigned n;
656 {
657   p = realloc (p, n);
658   if (p == 0)
659     {
660       error (0, 0, "virtual memory exhausted");
661       cleanup ();
662     }
663   return p;
664 }