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