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