Protoize. Reorder functions to obviate forward dcls.
[platform/upstream/coreutils.git] / src / cat.c
1 /* cat -- concatenate files and print on the standard output.
2    Copyright (C) 1988, 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 Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Differences from the Unix cat:
19    * Always unbuffered, -u is ignored.
20    * Usually much faster than other versions of cat, the difference
21    is especially apparent when using the -v option.
22
23    By tege@sics.se, Torbjorn Granlund, advised by rms, Richard Stallman. */
24
25 #include <config.h>
26
27 #include <stdio.h>
28 #include <getopt.h>
29 #include <sys/types.h>
30 #ifndef _POSIX_SOURCE
31 #include <sys/ioctl.h>
32 #endif
33 #include "system.h"
34 #include "version.h"
35 #include "error.h"
36
37 /* Undefine, to avoid warning about redefinition on some systems.  */
38 #undef max
39 #define max(h,i) ((h) > (i) ? (h) : (i))
40
41 char *stpcpy ();
42 char *xmalloc ();
43 int full_write ();
44 int safe_read ();
45
46 /* Name under which this program was invoked.  */
47 char *program_name;
48
49 /* Name of input file.  May be "-".  */
50 static char *infile;
51
52 /* Descriptor on which input file is open.  */
53 static int input_desc;
54
55 /* Descriptor on which output file is open.  Always is 1.  */
56 static int output_desc;
57
58 /* Buffer for line numbers.  */
59 static char line_buf[13] =
60 {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '0', '\t', '\0'};
61
62 /* Position in `line_buf' where printing starts.  This will not change
63    unless the number of lines is larger than 999999.  */
64 static char *line_num_print = line_buf + 5;
65
66 /* Position of the first digit in `line_buf'.  */
67 static char *line_num_start = line_buf + 10;
68
69 /* Position of the last digit in `line_buf'.  */
70 static char *line_num_end = line_buf + 10;
71
72 /* Preserves the `cat' function's local `newlines' between invocations.  */
73 static int newlines2 = 0;
74
75 /* Count of non-fatal error conditions.  */
76 static int exit_stat = 0;
77
78 static void
79 usage (status)
80      int status;
81 {
82   if (status != 0)
83     fprintf (stderr, _("Try `%s --help' for more information.\n"),
84              program_name);
85   else
86     {
87       printf (_("\
88 Usage: %s [OPTION] [FILE]...\n\
89 "),
90               program_name);
91       printf (_("\
92 Concatenate FILE(s), or standard input, to standard output.\n\
93 \n\
94   -b, --number-nonblank    number nonblank output lines\n\
95   -e                       equivalent to -vE\n\
96   -n, --number             number all output lines\n\
97   -s, --squeeze-blank      never more than one single blank line\n\
98   -t                       equivalent to -vT\n\
99   -u                       (ignored)\n\
100   -v, --show-nonprinting   use ^ and M- notation, save for LFD and TAB\n\
101   -A, --show-all           equivalent to -vET\n\
102   -E, --show-ends          display $ at end of each line\n\
103   -T, --show-tabs          display TAB characters as ^I\n\
104       --help               display this help and exit\n\
105       --version            output version information and exit\n\
106 \n\
107 With no FILE, or when FILE is -, read standard input.\n\
108 "));
109     }
110   exit (status);
111 }
112
113 /* Compute the next line number.  */
114
115 static void
116 next_line_num ()
117 {
118   char *endp = line_num_end;
119   do
120     {
121       if ((*endp)++ < '9')
122         return;
123       *endp-- = '0';
124     }
125   while (endp >= line_num_start);
126   *--line_num_start = '1';
127   if (line_num_start < line_num_print)
128     line_num_print--;
129 }
130
131 /* Plain cat.  Copies the file behind `input_desc' to the file behind
132    `output_desc'.  */
133
134 static void
135 simple_cat (
136      /* Pointer to the buffer, used by reads and writes.  */
137      unsigned char *buf,
138
139      /* Number of characters preferably read or written by each read and write
140         call.  */
141      int bufsize)
142 {
143   /* Actual number of characters read, and therefore written.  */
144   int n_read;
145
146   /* Loop until the end of the file.  */
147
148   for (;;)
149     {
150       /* Read a block of input.  */
151
152       n_read = safe_read (input_desc, buf, bufsize);
153       if (n_read < 0)
154         {
155           error (0, errno, "%s", infile);
156           exit_stat = 1;
157           return;
158         }
159
160       /* End of this file?  */
161
162       if (n_read == 0)
163         break;
164
165       /* Write this block out.  */
166
167       if (full_write (output_desc, buf, n_read) < 0)
168         error (1, errno, _("write error"));
169     }
170 }
171
172 /* Cat the file behind INPUT_DESC to the file behind OUTPUT_DESC.
173    Called if any option more than -u was specified.
174
175    A newline character is always put at the end of the buffer, to make
176    an explicit test for buffer end unnecessary.  */
177
178 static void
179 cat (
180      /* Pointer to the beginning of the input buffer.  */
181      unsigned char *inbuf,
182
183      /* Number of characters read in each read call.  */
184      int insize,
185
186      /* Pointer to the beginning of the output buffer.  */
187      unsigned char *outbuf,
188
189      /* Number of characters written by each write call.  */
190      int outsize,
191
192      /* Variables that have values according to the specified options.  */
193      int quote,
194      int output_tabs,
195      int numbers,
196      int numbers_at_empty_lines,
197      int mark_line_ends,
198      int squeeze_empty_lines)
199 {
200   /* Last character read from the input buffer.  */
201   unsigned char ch;
202
203   /* Pointer to the next character in the input buffer.  */
204   unsigned char *bpin;
205
206   /* Pointer to the first non-valid byte in the input buffer, i.e. the
207      current end of the buffer.  */
208   unsigned char *eob;
209
210   /* Pointer to the position where the next character shall be written.  */
211   unsigned char *bpout;
212
213   /* Number of characters read by the last read call.  */
214   int n_read;
215
216   /* Determines how many consecutive newlines there have been in the
217      input.  0 newlines makes NEWLINES -1, 1 newline makes NEWLINES 1,
218      etc.  Initially 0 to indicate that we are at the beginning of a
219      new line.  The "state" of the procedure is determined by
220      NEWLINES.  */
221   int newlines = newlines2;
222
223 #ifdef FIONREAD
224   /* If nonzero, use the FIONREAD ioctl, as an optimization.
225      (On Ultrix, it is not supported on NFS filesystems.)  */
226   int use_fionread = 1;
227 #endif
228
229   /* The inbuf pointers are initialized so that BPIN > EOB, and thereby input
230      is read immediately.  */
231
232   eob = inbuf;
233   bpin = eob + 1;
234
235   bpout = outbuf;
236
237   for (;;)
238     {
239       do
240         {
241           /* Write if there are at least OUTSIZE bytes in OUTBUF.  */
242
243           if (bpout - outbuf >= outsize)
244             {
245               unsigned char *wp = outbuf;
246               do
247                 {
248                   if (full_write (output_desc, wp, outsize) < 0)
249                     error (1, errno, _("write error"));
250                   wp += outsize;
251                 }
252               while (bpout - wp >= outsize);
253
254               /* Move the remaining bytes to the beginning of the
255                  buffer.  */
256
257               memmove (outbuf, wp, bpout - wp);
258               bpout = outbuf + (bpout - wp);
259             }
260
261           /* Is INBUF empty?  */
262
263           if (bpin > eob)
264             {
265 #ifdef FIONREAD
266               int n_to_read = 0;
267
268               /* Is there any input to read immediately?
269                  If not, we are about to wait,
270                  so write all buffered output before waiting.  */
271
272               if (use_fionread
273                   && ioctl (input_desc, FIONREAD, &n_to_read) < 0)
274                 {
275                   /* Ultrix returns EOPNOTSUPP on NFS;
276                      HP-UX returns ENOTTY on pipes.
277                      SunOS returns EINVAL and
278                      More/BSD returns ENODEV on special files
279                      like /dev/null.
280                      Irix-5 returns ENOSYS on pipes.  */
281                   if (errno == EOPNOTSUPP || errno == ENOTTY
282                       || errno == EINVAL || errno == ENODEV
283 #ifdef ENOSYS
284                       || errno == ENOSYS
285 #endif
286                       )
287                     use_fionread = 0;
288                   else
289                     {
290                       error (0, errno, _("cannot do ioctl on `%s'"), infile);
291                       exit_stat = 1;
292                       newlines2 = newlines;
293                       return;
294                     }
295                 }
296               if (n_to_read == 0)
297 #endif
298                 {
299                   int n_write = bpout - outbuf;
300
301                   if (full_write (output_desc, outbuf, n_write) < 0)
302                     error (1, errno, _("write error"));
303                   bpout = outbuf;
304                 }
305
306               /* Read more input into INBUF.  */
307
308               n_read = safe_read (input_desc, inbuf, insize);
309               if (n_read < 0)
310                 {
311                   error (0, errno, "%s", infile);
312                   exit_stat = 1;
313                   newlines2 = newlines;
314                   return;
315                 }
316               if (n_read == 0)
317                 {
318                   newlines2 = newlines;
319                   return;
320                 }
321
322               /* Update the pointers and insert a sentinel at the buffer
323                  end.  */
324
325               bpin = inbuf;
326               eob = bpin + n_read;
327               *eob = '\n';
328             }
329           else
330             {
331               /* It was a real (not a sentinel) newline.  */
332
333               /* Was the last line empty?
334                  (i.e. have two or more consecutive newlines been read?)  */
335
336               if (++newlines > 0)
337                 {
338                   /* Are multiple adjacent empty lines to be substituted by
339                      single ditto (-s), and this was the second empty line?  */
340
341                   if (squeeze_empty_lines && newlines >= 2)
342                     {
343                       ch = *bpin++;
344                       continue;
345                     }
346
347                   /* Are line numbers to be written at empty lines (-n)?  */
348
349                   if (numbers && numbers_at_empty_lines)
350                     {
351                       next_line_num ();
352                       bpout = (unsigned char *) stpcpy (bpout, line_num_print);
353                     }
354                 }
355
356               /* Output a currency symbol if requested (-e).  */
357
358               if (mark_line_ends)
359                 *bpout++ = '$';
360
361               /* Output the newline.  */
362
363               *bpout++ = '\n';
364             }
365           ch = *bpin++;
366         }
367       while (ch == '\n');
368
369       /* Are we at the beginning of a line, and line numbers are requested?  */
370
371       if (newlines >= 0 && numbers)
372         {
373           next_line_num ();
374           bpout = (unsigned char *) stpcpy (bpout, line_num_print);
375         }
376
377       /* Here CH cannot contain a newline character.  */
378
379       /* The loops below continue until a newline character is found,
380          which means that the buffer is empty or that a proper newline
381          has been found.  */
382
383       /* If quoting, i.e. at least one of -v, -e, or -t specified,
384          scan for chars that need conversion.  */
385       if (quote)
386         for (;;)
387           {
388             if (ch >= 32)
389               {
390                 if (ch < 127)
391                   *bpout++ = ch;
392                 else if (ch == 127)
393                   *bpout++ = '^',
394                     *bpout++ = '?';
395                 else
396                   {
397                     *bpout++ = 'M',
398                       *bpout++ = '-';
399                     if (ch >= 128 + 32)
400                       if (ch < 128 + 127)
401                         *bpout++ = ch - 128;
402                       else
403                         *bpout++ = '^',
404                           *bpout++ = '?';
405                     else
406                       *bpout++ = '^',
407                         *bpout++ = ch - 128 + 64;
408                   }
409               }
410             else if (ch == '\t' && output_tabs)
411               *bpout++ = '\t';
412             else if (ch == '\n')
413               {
414                 newlines = -1;
415                 break;
416               }
417             else
418               *bpout++ = '^',
419                 *bpout++ = ch + 64;
420
421             ch = *bpin++;
422           }
423       else
424         /* Not quoting, neither of -v, -e, or -t specified.  */
425         for (;;)
426           {
427             if (ch == '\t' && !output_tabs)
428               *bpout++ = '^',
429                 *bpout++ = ch + 64;
430             else if (ch != '\n')
431               *bpout++ = ch;
432             else
433               {
434                 newlines = -1;
435                 break;
436               }
437
438             ch = *bpin++;
439           }
440     }
441 }
442
443 void
444 main (argc, argv)
445      int argc;
446      char *argv[];
447 {
448   /* Optimal size of i/o operations of output.  */
449   int outsize;
450
451   /* Optimal size of i/o operations of input.  */
452   int insize;
453
454   /* Pointer to the input buffer.  */
455   unsigned char *inbuf;
456
457   /* Pointer to the output buffer.  */
458   unsigned char *outbuf;
459
460   int c;
461
462   /* Index in argv to processed argument.  */
463   int argind;
464
465   /* Device number of the output (file or whatever).  */
466   int out_dev;
467
468   /* I-node number of the output.  */
469   int out_ino;
470
471   /* Nonzero if the output file should not be the same as any input file. */
472   int check_redirection = 1;
473
474   /* Nonzero if we have ever read standard input. */
475   int have_read_stdin = 0;
476
477   struct stat stat_buf;
478
479   /* Variables that are set according to the specified options.  */
480   int numbers = 0;
481   int numbers_at_empty_lines = 1;
482   int squeeze_empty_lines = 0;
483   int mark_line_ends = 0;
484   int quote = 0;
485   int output_tabs = 1;
486
487 /* If non-zero, call cat, otherwise call simple_cat to do the actual work. */
488   int options = 0;
489
490   /* If non-zero, display usage information and exit.  */
491   static int show_help;
492
493   /* If non-zero, print the version on standard output then exit.  */
494   static int show_version;
495
496   static struct option const long_options[] =
497   {
498     {"number-nonblank", no_argument, NULL, 'b'},
499     {"number", no_argument, NULL, 'n'},
500     {"squeeze-blank", no_argument, NULL, 's'},
501     {"show-nonprinting", no_argument, NULL, 'v'},
502     {"show-ends", no_argument, NULL, 'E'},
503     {"show-tabs", no_argument, NULL, 'T'},
504     {"show-all", no_argument, NULL, 'A'},
505     {"help", no_argument, &show_help, 1},
506     {"version", no_argument, &show_version, 1},
507     {NULL, 0, NULL, 0}
508   };
509
510   program_name = argv[0];
511
512   /* Parse command line options.  */
513
514   while ((c = getopt_long (argc, argv, "benstuvAET", long_options, (int *) 0))
515          != EOF)
516     {
517       switch (c)
518         {
519         case 0:
520           break;
521
522         case 'b':
523           ++options;
524           numbers = 1;
525           numbers_at_empty_lines = 0;
526           break;
527
528         case 'e':
529           ++options;
530           mark_line_ends = 1;
531           quote = 1;
532           break;
533
534         case 'n':
535           ++options;
536           numbers = 1;
537           break;
538
539         case 's':
540           ++options;
541           squeeze_empty_lines = 1;
542           break;
543
544         case 't':
545           ++options;
546           output_tabs = 0;
547           quote = 1;
548           break;
549
550         case 'u':
551           /* We provide the -u feature unconditionally.  */
552           break;
553
554         case 'v':
555           ++options;
556           quote = 1;
557           break;
558
559         case 'A':
560           ++options;
561           quote = 1;
562           mark_line_ends = 1;
563           output_tabs = 0;
564           break;
565
566         case 'E':
567           ++options;
568           mark_line_ends = 1;
569           break;
570
571         case 'T':
572           ++options;
573           output_tabs = 0;
574           break;
575
576         default:
577           usage (2);
578         }
579     }
580
581   if (show_version)
582     {
583       printf ("cat - %s\n", version_string);
584       exit (0);
585     }
586
587   if (show_help)
588     usage (0);
589
590   output_desc = 1;
591
592   /* Get device, i-node number, and optimal blocksize of output.  */
593
594   if (fstat (output_desc, &stat_buf) < 0)
595     error (1, errno, _("standard output"));
596
597   outsize = ST_BLKSIZE (stat_buf);
598   /* Input file can be output file for non-regular files.
599      fstat on pipes returns S_IFSOCK on some systems, S_IFIFO
600      on others, so the checking should not be done for those types,
601      and to allow things like cat < /dev/tty > /dev/tty, checking
602      is not done for device files either. */
603
604   if (S_ISREG (stat_buf.st_mode))
605     {
606       out_dev = stat_buf.st_dev;
607       out_ino = stat_buf.st_ino;
608     }
609   else
610     {
611       check_redirection = 0;
612 #ifdef lint  /* Suppress `used before initialized' warning.  */
613       out_dev = 0;
614       out_ino = 0;
615 #endif
616     }
617
618   /* Check if any of the input files are the same as the output file.  */
619
620   /* Main loop.  */
621
622   infile = "-";
623   argind = optind;
624
625   do
626     {
627       if (argind < argc)
628         infile = argv[argind];
629
630       if (infile[0] == '-' && infile[1] == 0)
631         {
632           have_read_stdin = 1;
633           input_desc = 0;
634         }
635       else
636         {
637           input_desc = open (infile, O_RDONLY);
638           if (input_desc < 0)
639             {
640               error (0, errno, "%s", infile);
641               exit_stat = 1;
642               continue;
643             }
644         }
645
646       if (fstat (input_desc, &stat_buf) < 0)
647         {
648           error (0, errno, "%s", infile);
649           exit_stat = 1;
650           goto contin;
651         }
652       insize = ST_BLKSIZE (stat_buf);
653
654       /* Compare the device and i-node numbers of this input file with
655          the corresponding values of the (output file associated with)
656          stdout, and skip this input file if they coincide.  Input
657          files cannot be redirected to themselves.  */
658
659       if (check_redirection
660           && stat_buf.st_dev == out_dev && stat_buf.st_ino == out_ino)
661         {
662           error (0, 0, _("%s: input file is output file"), infile);
663           exit_stat = 1;
664           goto contin;
665         }
666
667       /* Select which version of `cat' to use. If any options (more than -u,
668          --version, or --help) were specified, use `cat', otherwise use
669          `simple_cat'.  */
670
671       if (options == 0)
672         {
673           insize = max (insize, outsize);
674           inbuf = (unsigned char *) xmalloc (insize);
675
676           simple_cat (inbuf, insize);
677         }
678       else
679         {
680           inbuf = (unsigned char *) xmalloc (insize + 1);
681
682           /* Why are (OUTSIZE  - 1 + INSIZE * 4 + 13) bytes allocated for
683              the output buffer?
684
685              A test whether output needs to be written is done when the input
686              buffer empties or when a newline appears in the input.  After
687              output is written, at most (OUTSIZE - 1) bytes will remain in the
688              buffer.  Now INSIZE bytes of input is read.  Each input character
689              may grow by a factor of 4 (by the prepending of M-^).  If all
690              characters do, and no newlines appear in this block of input, we
691              will have at most (OUTSIZE - 1 + INSIZE) bytes in the buffer.  If
692              the last character in the preceding block of input was a
693              newline, a line number may be written (according to the given
694              options) as the first thing in the output buffer. (Done after the
695              new input is read, but before processing of the input begins.)  A
696              line number requires seldom more than 13 positions.  */
697
698           outbuf = (unsigned char *) xmalloc (outsize - 1 + insize * 4 + 13);
699
700           cat (inbuf, insize, outbuf, outsize, quote,
701                output_tabs, numbers, numbers_at_empty_lines, mark_line_ends,
702                squeeze_empty_lines);
703
704           free (outbuf);
705         }
706
707       free (inbuf);
708
709     contin:
710       if (strcmp (infile, "-") && close (input_desc) < 0)
711         {
712           error (0, errno, "%s", infile);
713           exit_stat = 1;
714         }
715     }
716   while (++argind < argc);
717
718   if (have_read_stdin && close (0) < 0)
719     error (1, errno, "-");
720   if (close (1) < 0)
721     error (1, errno, _("write error"));
722
723   exit (exit_stat);
724 }