Compare getopt_long return value against -1, not EOF. Use NULL, not '(int *) 0'...
[platform/upstream/coreutils.git] / src / head.c
1 /* head -- output first part of file(s)
2    Copyright (C) 89, 90, 91, 95, 1996 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 "error.h"
34
35 /* Number of lines/chars/blocks to head. */
36 #define DEFAULT_NUMBER 10
37
38 /* Size of atomic reads. */
39 #define BUFSIZE (512 * 8)
40
41 /* Number of bytes per item we are printing.
42    If 0, head in lines. */
43 static int unit_size;
44
45 /* If nonzero, print filename headers. */
46 static int print_headers;
47
48 /* When to print the filename banners. */
49 enum header_mode
50 {
51   multiple_files, always, never
52 };
53
54 int safe_read ();
55
56 /* The name this program was run with. */
57 char *program_name;
58
59 /* Have we ever read standard input?  */
60 static int have_read_stdin;
61
62 /* If nonzero, display usage information and exit.  */
63 static int show_help;
64
65 /* If nonzero, print the version on standard output then exit.  */
66 static int show_version;
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   {"help", no_argument, &show_help, 1},
76   {"version", no_argument, &show_version, 1},
77   {NULL, 0, NULL, 0}
78 };
79
80 static 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       printf (_("\
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   -c, --bytes=SIZE         print first SIZE bytes\n\
98   -n, --lines=NUMBER       print first NUMBER lines instead of first 10\n\
99   -q, --quiet, --silent    never print headers giving file names\n\
100   -v, --verbose            always print headers giving file names\n\
101       --help               display this help and exit\n\
102       --version            output version information and exit\n\
103 \n\
104 SIZE may have a multiplier suffix: b for 512, k for 1K, m for 1 Meg.\n\
105 If -VALUE is used as first OPTION, read -c VALUE when one of\n\
106 multipliers bkm follows concatenated, else read -n VALUE.\n\
107 "));
108       puts (_("\nReport bugs to textutils-bugs@gnu.ai.mit.edu"));
109     }
110   exit (status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
111 }
112
113 /* Convert STR, a string of ASCII digits, into an unsigned integer.
114    Return -1 if STR does not represent a valid unsigned integer. */
115
116 static long
117 atou (const char *str)
118 {
119   int value;
120
121   for (value = 0; ISDIGIT (*str); ++str)
122     value = value * 10 + *str - '0';
123   return *str ? -1 : value;
124 }
125
126 static void
127 parse_unit (char *str)
128 {
129   int arglen = strlen (str);
130
131   if (arglen == 0)
132     return;
133
134   switch (str[arglen - 1])
135     {
136     case 'b':
137       unit_size = 512;
138       str[arglen - 1] = '\0';
139       break;
140     case 'k':
141       unit_size = 1024;
142       str[arglen - 1] = '\0';
143       break;
144     case 'm':
145       unit_size = 1048576;
146       str[arglen - 1] = '\0';
147       break;
148     }
149 }
150
151 static void
152 write_header (const char *filename)
153 {
154   static int first_file = 1;
155
156   printf ("%s==> %s <==\n", (first_file ? "" : "\n"), filename);
157   first_file = 0;
158 }
159
160 static int
161 head_bytes (const char *filename, int fd, long int bytes_to_write)
162 {
163   char buffer[BUFSIZE];
164   int bytes_read;
165
166   while (bytes_to_write)
167     {
168       bytes_read = safe_read (fd, buffer, BUFSIZE);
169       if (bytes_read < 0)
170         {
171           error (0, errno, "%s", filename);
172           return 1;
173         }
174       if (bytes_read == 0)
175         break;
176       if (bytes_read > bytes_to_write)
177         bytes_read = bytes_to_write;
178       if (fwrite (buffer, 1, bytes_read, stdout) == 0)
179         error (EXIT_FAILURE, errno, _("write error"));
180       bytes_to_write -= bytes_read;
181     }
182   return 0;
183 }
184
185 static int
186 head_lines (const char *filename, int fd, long int lines_to_write)
187 {
188   char buffer[BUFSIZE];
189   int bytes_read;
190   int bytes_to_write;
191
192   while (lines_to_write)
193     {
194       bytes_read = safe_read (fd, buffer, BUFSIZE);
195       if (bytes_read < 0)
196         {
197           error (0, errno, "%s", filename);
198           return 1;
199         }
200       if (bytes_read == 0)
201         break;
202       bytes_to_write = 0;
203       while (bytes_to_write < bytes_read)
204         if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
205           break;
206       if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
207         error (EXIT_FAILURE, errno, _("write error"));
208     }
209   return 0;
210 }
211
212 static int
213 head (const char *filename, int fd, long int number)
214 {
215   if (unit_size)
216     return head_bytes (filename, fd, number);
217   else
218     return head_lines (filename, fd, number);
219 }
220
221 static int
222 head_file (const char *filename, long int number)
223 {
224   int fd;
225
226   if (!strcmp (filename, "-"))
227     {
228       have_read_stdin = 1;
229       filename = _("standard input");
230       if (print_headers)
231         write_header (filename);
232       return head (filename, 0, number);
233     }
234   else
235     {
236       fd = open (filename, O_RDONLY);
237       if (fd >= 0)
238         {
239           int errors;
240
241           if (print_headers)
242             write_header (filename);
243           errors = head (filename, fd, number);
244           if (close (fd) == 0)
245             return errors;
246         }
247       error (0, errno, "%s", filename);
248       return 1;
249     }
250 }
251
252 int
253 main (int argc, char **argv)
254 {
255   enum header_mode header_mode = multiple_files;
256   int exit_status = 0;
257   long number = -1;             /* Number of items to print (-1 if undef.). */
258   int c;                        /* Option character. */
259
260   program_name = argv[0];
261   setlocale (LC_ALL, "");
262   bindtextdomain (PACKAGE, LOCALEDIR);
263   textdomain (PACKAGE);
264
265   have_read_stdin = 0;
266   unit_size = 0;
267   print_headers = 0;
268
269   if (argc > 1 && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
270     {
271       /* Old option syntax; a dash, one or more digits, and one or
272          more option letters.  Move past the number. */
273       for (number = 0, ++argv[1]; ISDIGIT (*argv[1]); ++argv[1])
274         number = number * 10 + *argv[1] - '0';
275       /* Parse any appended option letters. */
276       while (*argv[1])
277         {
278           switch (*argv[1])
279             {
280             case 'b':
281               unit_size = 512;
282               break;
283
284             case 'c':
285               unit_size = 1;
286               break;
287
288             case 'k':
289               unit_size = 1024;
290               break;
291
292             case 'l':
293               unit_size = 0;
294               break;
295
296             case 'm':
297               unit_size = 1048576;
298               break;
299
300             case 'q':
301               header_mode = never;
302               break;
303
304             case 'v':
305               header_mode = always;
306               break;
307
308             default:
309               error (0, 0, _("unrecognized option `-%c'"), *argv[1]);
310               usage (1);
311             }
312           ++argv[1];
313         }
314       /* Make the options we just parsed invisible to getopt. */
315       argv[1] = argv[0];
316       argv++;
317       argc--;
318     }
319
320   while ((c = getopt_long (argc, argv, "c:n:qv", long_options, NULL)) != -1)
321     {
322       switch (c)
323         {
324         case 0:
325           break;
326
327         case 'c':
328           unit_size = 1;
329           parse_unit (optarg);
330           goto getnum;
331         case 'n':
332           unit_size = 0;
333         getnum:
334           /* FIXME: use xstrtoul instead.  */
335           number = atou (optarg);
336           if (number == -1)
337             error (EXIT_FAILURE, 0, _("invalid number `%s'"), optarg);
338           break;
339
340         case 'q':
341           header_mode = never;
342           break;
343
344         case 'v':
345           header_mode = always;
346           break;
347
348         default:
349           usage (1);
350         }
351     }
352
353   if (show_version)
354     {
355       printf ("head (%s) %s\n", GNU_PACKAGE, VERSION);
356       exit (EXIT_SUCCESS);
357     }
358
359   if (show_help)
360     usage (0);
361
362   if (number == -1)
363     number = DEFAULT_NUMBER;
364
365   if (unit_size > 1)
366     number *= unit_size;
367
368   if (header_mode == always
369       || (header_mode == multiple_files && optind < argc - 1))
370     print_headers = 1;
371
372   if (optind == argc)
373     exit_status |= head_file ("-", number);
374
375   for (; optind < argc; ++optind)
376     exit_status |= head_file (argv[optind], number);
377
378   if (have_read_stdin && close (0) < 0)
379     error (EXIT_FAILURE, errno, "-");
380   if (fclose (stdout) == EOF)
381     error (EXIT_FAILURE, errno, _("write error"));
382
383   exit (exit_status == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
384 }