0c972e28328db1b050153f3578d404c21d9e5750
[platform/upstream/coreutils.git] / src / head.c
1 /* head -- output first part of file(s)
2    Copyright (C) 89, 90, 91, 1995-2002 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 /* Options: (see usage)
19    Reads from standard input if no files are given or when a filename of
20    ``-'' is encountered.
21    By default, filename headers are printed only if more than one file
22    is given.
23    By default, prints the first 10 lines (head -n 10).
24
25    David MacKenzie <djm@gnu.ai.mit.edu> */
26
27 #include <config.h>
28
29 #include <stdio.h>
30 #include <getopt.h>
31 #include <sys/types.h>
32 #include "system.h"
33 #include "closeout.h"
34 #include "error.h"
35 #include "posixver.h"
36 #include "xstrtol.h"
37 #include "safe-read.h"
38
39 /* The official name of this program (e.g., no `g' prefix).  */
40 #define PROGRAM_NAME "head"
41
42 #define AUTHORS "David MacKenzie"
43
44 /* Number of lines/chars/blocks to head. */
45 #define DEFAULT_NUMBER 10
46
47 /* Size of atomic reads. */
48 #define BUFSIZE (512 * 8)
49
50 /* If nonzero, print filename headers. */
51 static int print_headers;
52
53 /* When to print the filename banners. */
54 enum header_mode
55 {
56   multiple_files, always, never
57 };
58
59 /* Options corresponding to header_mode values.  */
60 static char const header_mode_option[][4] = { "", " -v", " -q" };
61
62 /* The name this program was run with. */
63 char *program_name;
64
65 /* Have we ever read standard input?  */
66 static int have_read_stdin;
67
68 static struct option const long_options[] =
69 {
70   {"bytes", required_argument, NULL, 'c'},
71   {"lines", required_argument, NULL, 'n'},
72   {"quiet", no_argument, NULL, 'q'},
73   {"silent", no_argument, NULL, 'q'},
74   {"verbose", no_argument, NULL, 'v'},
75   {GETOPT_HELP_OPTION_DECL},
76   {GETOPT_VERSION_OPTION_DECL},
77   {NULL, 0, NULL, 0}
78 };
79
80 void
81 usage (int status)
82 {
83   if (status != 0)
84     fprintf (stderr, _("Try `%s --help' for more information.\n"),
85              program_name);
86   else
87     {
88       printf (_("\
89 Usage: %s [OPTION]... [FILE]...\n\
90 "),
91               program_name);
92       fputs (_("\
93 Print first 10 lines of each FILE to standard output.\n\
94 With more than one FILE, precede each with a header giving the file name.\n\
95 With no FILE, or when FILE is -, read standard input.\n\
96 \n\
97 "), stdout);
98       fputs (_("\
99 Mandatory arguments to long options are mandatory for short options too.\n\
100 "), stdout);
101       fputs (_("\
102   -c, --bytes=SIZE         print first SIZE bytes\n\
103   -n, --lines=NUMBER       print first NUMBER lines instead of first 10\n\
104 "), stdout);
105       fputs (_("\
106   -q, --quiet, --silent    never print headers giving file names\n\
107   -v, --verbose            always print headers giving file names\n\
108 "), stdout);
109       fputs (HELP_OPTION_DESCRIPTION, stdout);
110       fputs (VERSION_OPTION_DESCRIPTION, stdout);
111       fputs (_("\
112 \n\
113 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
114 "), stdout);
115       printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
116     }
117   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
118 }
119
120 static void
121 write_header (const char *filename)
122 {
123   static int first_file = 1;
124
125   printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
126   first_file = 0;
127 }
128
129 static int
130 head_bytes (const char *filename, int fd, uintmax_t bytes_to_write)
131 {
132   char buffer[BUFSIZE];
133   size_t bytes_to_read = BUFSIZE;
134
135   /* Need BINARY I/O for the byte counts to be accurate.  */
136   SET_BINARY2 (fd, fileno (stdout));
137
138   while (bytes_to_write)
139     {
140       size_t bytes_read;
141       if (bytes_to_write < bytes_to_read)
142         bytes_to_read = bytes_to_write;
143       bytes_read = safe_read (fd, buffer, bytes_to_read);
144       if (bytes_read == SAFE_READ_ERROR)
145         {
146           error (0, errno, "%s", filename);
147           return 1;
148         }
149       if (bytes_read == 0)
150         break;
151       if (fwrite (buffer, 1, bytes_read, stdout) == 0)
152         error (EXIT_FAILURE, errno, _("write error"));
153       bytes_to_write -= bytes_read;
154     }
155   return 0;
156 }
157
158 static int
159 head_lines (const char *filename, int fd, uintmax_t lines_to_write)
160 {
161   char buffer[BUFSIZE];
162
163   /* Need BINARY I/O for the byte counts to be accurate.  */
164   SET_BINARY2 (fd, fileno (stdout));
165
166   while (lines_to_write)
167     {
168       size_t bytes_read = safe_read (fd, buffer, BUFSIZE);
169       size_t bytes_to_write = 0;
170
171       if (bytes_read == SAFE_READ_ERROR)
172         {
173           error (0, errno, "%s", filename);
174           return 1;
175         }
176       if (bytes_read == 0)
177         break;
178       while (bytes_to_write < bytes_read)
179         if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
180           {
181             off_t n_bytes_past_EOL = bytes_read - bytes_to_write;
182             /* If we have read more data than that on the specified number
183                of lines, try to seek back to the position we would have
184                gotten to had we been reading one byte at a time.  */
185             if (lseek (fd, -n_bytes_past_EOL, SEEK_CUR) < 0)
186               {
187                 int e = errno;
188                 struct stat st;
189                 if (fstat (fd, &st) != 0 || S_ISREG (st.st_mode))
190                   error (0, e, _("cannot reposition file pointer for %s"),
191                          filename);
192               }
193             break;
194           }
195       if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
196         error (EXIT_FAILURE, errno, _("write error"));
197     }
198   return 0;
199 }
200
201 static int
202 head (const char *filename, int fd, uintmax_t n_units, int count_lines)
203 {
204   if (print_headers)
205     write_header (filename);
206
207   if (count_lines)
208     return head_lines (filename, fd, n_units);
209   else
210     return head_bytes (filename, fd, n_units);
211 }
212
213 static int
214 head_file (const char *filename, uintmax_t n_units, int count_lines)
215 {
216   int fd;
217
218   if (STREQ (filename, "-"))
219     {
220       have_read_stdin = 1;
221       return head (_("standard input"), STDIN_FILENO, n_units, count_lines);
222     }
223   else
224     {
225       fd = open (filename, O_RDONLY);
226       if (fd >= 0)
227         {
228           int errors;
229
230           errors = head (filename, fd, n_units, count_lines);
231           if (close (fd) == 0)
232             return errors;
233         }
234       error (0, errno, "%s", filename);
235       return 1;
236     }
237 }
238
239 /* Convert a string of decimal digits, N_STRING, with a single, optional suffix
240    character (b, k, or m) to an integral value.  Upon successful conversion,
241    return that value.  If it cannot be converted, give a diagnostic and exit.
242    COUNT_LINES indicates whether N_STRING is a number of bytes or a number
243    of lines.  It is used solely to give a more specific diagnostic.  */
244
245 static uintmax_t
246 string_to_integer (int count_lines, const char *n_string)
247 {
248   strtol_error s_err;
249   uintmax_t n;
250
251   s_err = xstrtoumax (n_string, NULL, 10, &n, "bkm");
252
253   if (s_err == LONGINT_OVERFLOW)
254     {
255       error (EXIT_FAILURE, 0,
256              _("%s: %s is so large that it is not representable"), n_string,
257              count_lines ? _("number of lines") : _("number of bytes"));
258     }
259
260   if (s_err != LONGINT_OK)
261     {
262       error (EXIT_FAILURE, 0, "%s: %s", n_string,
263              (count_lines
264               ? _("invalid number of lines")
265               : _("invalid number of bytes")));
266     }
267
268   return n;
269 }
270
271 int
272 main (int argc, char **argv)
273 {
274   enum header_mode header_mode = multiple_files;
275   int exit_status = 0;
276   int c;
277
278   /* Number of items to print. */
279   uintmax_t n_units = DEFAULT_NUMBER;
280
281   /* If nonzero, interpret the numeric argument as the number of lines.
282      Otherwise, interpret it as the number of bytes.  */
283   int count_lines = 1;
284
285   program_name = argv[0];
286   setlocale (LC_ALL, "");
287   bindtextdomain (PACKAGE, LOCALEDIR);
288   textdomain (PACKAGE);
289
290   atexit (close_stdout);
291
292   have_read_stdin = 0;
293
294   print_headers = 0;
295
296   if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
297     {
298       char *a = argv[1];
299       char *n_string = ++a;
300       char *end_n_string;
301       char multiplier_char = 0;
302
303       /* Old option syntax; a dash, one or more digits, and one or
304          more option letters.  Move past the number. */
305       do ++a;
306       while (ISDIGIT (*a));
307
308       /* Pointer to the byte after the last digit.  */
309       end_n_string = a;
310
311       /* Parse any appended option letters. */
312       for (; *a; a++)
313         {
314           switch (*a)
315             {
316             case 'c':
317               count_lines = 0;
318               multiplier_char = 0;
319               break;
320
321             case 'b':
322             case 'k':
323             case 'm':
324               count_lines = 0;
325               multiplier_char = *a;
326               break;
327
328             case 'l':
329               count_lines = 1;
330               break;
331
332             case 'q':
333               header_mode = never;
334               break;
335
336             case 'v':
337               header_mode = always;
338               break;
339
340             default:
341               error (0, 0, _("unrecognized option `-%c'"), *a);
342               usage (EXIT_FAILURE);
343             }
344         }
345
346       if (200112 <= posix2_version ())
347         {
348           error (0, 0, _("`-%s' option is obsolete; use `-%c %.*s%.*s%s'"),
349                  n_string, count_lines ? 'n' : 'c',
350                  (int) (end_n_string - n_string), n_string,
351                  multiplier_char != 0, &multiplier_char,
352                  header_mode_option[header_mode]);
353           usage (EXIT_FAILURE);
354         }
355
356       /* Append the multiplier character (if any) onto the end of
357          the digit string.  Then add NUL byte if necessary.  */
358       *end_n_string = multiplier_char;
359       if (multiplier_char)
360         *(++end_n_string) = 0;
361
362       n_units = string_to_integer (count_lines, n_string);
363
364       /* Make the options we just parsed invisible to getopt. */
365       argv[1] = argv[0];
366       argv++;
367       argc--;
368
369       /* FIXME: allow POSIX options if there were obsolescent ones?  */
370
371     }
372
373   while ((c = getopt_long (argc, argv, "c:n:qv", long_options, NULL)) != -1)
374     {
375       switch (c)
376         {
377         case 0:
378           break;
379
380         case 'c':
381           count_lines = 0;
382           n_units = string_to_integer (count_lines, optarg);
383           break;
384
385         case 'n':
386           count_lines = 1;
387           n_units = string_to_integer (count_lines, optarg);
388           break;
389
390         case 'q':
391           header_mode = never;
392           break;
393
394         case 'v':
395           header_mode = always;
396           break;
397
398         case_GETOPT_HELP_CHAR;
399
400         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
401
402         default:
403           usage (EXIT_FAILURE);
404         }
405     }
406
407   if (header_mode == always
408       || (header_mode == multiple_files && optind < argc - 1))
409     print_headers = 1;
410
411   if (optind == argc)
412     exit_status |= head_file ("-", n_units, count_lines);
413
414   for (; optind < argc; ++optind)
415     exit_status |= head_file (argv[optind], n_units, count_lines);
416
417   if (have_read_stdin && close (STDIN_FILENO) < 0)
418     error (EXIT_FAILURE, errno, "-");
419
420   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
421 }