Declared lots of external functions and variables static.
[platform/upstream/coreutils.git] / src / head.c
1 /* head -- output first part of file(s)
2    Copyright (C) 1989, 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
18 /* Options:
19    -b                   Print first N 512-byte blocks.
20    -c, --bytes=N[bkm]   Print first N bytes
21                         [or 512-byte blocks, kilobytes, or megabytes].
22    -k                   Print first N kilobytes.
23    -N, -l, -n, --lines=N        Print first N lines.
24    -m                   Print first N megabytes.
25    -q, --quiet, --silent        Never print filename headers.
26    -v, --verbose                Always print filename headers.
27
28    Reads from standard input if no files are given or when a filename of
29    ``-'' is encountered.
30    By default, filename headers are printed only if more than one file
31    is given.
32    By default, prints the first 10 lines (head -n 10).
33
34    David MacKenzie <djm@ai.mit.edu> */
35
36 #include <stdio.h>
37 #include <getopt.h>
38 #include <ctype.h>
39 #include <sys/types.h>
40 #include "system.h"
41
42 #ifdef isascii
43 #define ISDIGIT(c) (isascii ((c)) && isdigit ((c)))
44 #else
45 #define ISDIGIT(c) (isdigit ((c)))
46 #endif
47
48 /* Number of lines/chars/blocks to head. */
49 #define DEFAULT_NUMBER 10
50
51 /* Size of atomic reads. */
52 #define BUFSIZE (512 * 8)
53
54 /* Number of bytes per item we are printing.
55    If 0, head in lines. */
56 static int unit_size;
57
58 /* If nonzero, print filename headers. */
59 static int print_headers;
60
61 /* When to print the filename banners. */
62 enum header_mode
63 {
64   multiple_files, always, never
65 };
66
67 void error ();
68 void xwrite ();
69
70 static int head ();
71 static int head_bytes ();
72 static int head_file ();
73 static int head_lines ();
74 static long atou ();
75 static void parse_unit ();
76 static void usage ();
77 static void write_header ();
78
79 /* The name this program was run with. */
80 char *program_name;
81
82 /* Have we ever read standard input?  */
83 static int have_read_stdin;
84
85 static struct option const long_options[] =
86 {
87   {"bytes", 1, NULL, 'c'},
88   {"lines", 1, NULL, 'n'},
89   {"quiet", 0, NULL, 'q'},
90   {"silent", 0, NULL, 'q'},
91   {"verbose", 0, NULL, 'v'},
92   {NULL, 0, NULL, 0}
93 };
94
95 void
96 main (argc, argv)
97      int argc;
98      char **argv;
99 {
100   enum header_mode header_mode = multiple_files;
101   int exit_status = 0;
102   long number = -1;             /* Number of items to print (-1 if undef.). */
103   int c;                        /* Option character. */
104
105   program_name = argv[0];
106   have_read_stdin = 0;
107   unit_size = 0;
108   print_headers = 0;
109
110   if (argc > 1 && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
111     {
112       /* Old option syntax; a dash, one or more digits, and one or
113          more option letters.  Move past the number. */
114       for (number = 0, ++argv[1]; ISDIGIT (*argv[1]); ++argv[1])
115         number = number * 10 + *argv[1] - '0';
116       /* Parse any appended option letters. */
117       while (*argv[1])
118         {
119           switch (*argv[1])
120             {
121             case 'b':
122               unit_size = 512;
123               break;
124
125             case 'c':
126               unit_size = 1;
127               break;
128
129             case 'k':
130               unit_size = 1024;
131               break;
132
133             case 'l':
134               unit_size = 0;
135               break;
136
137             case 'm':
138               unit_size = 1048576;
139               break;
140
141             case 'q':
142               header_mode = never;
143               break;
144
145             case 'v':
146               header_mode = always;
147               break;
148
149             default:
150               error (0, 0, "unrecognized option `-%c'", *argv[1]);
151               usage ();
152             }
153           ++argv[1];
154         }
155       /* Make the options we just parsed invisible to getopt. */
156       argv[1] = argv[0];
157       argv++;
158       argc--;
159     }
160
161   while ((c = getopt_long (argc, argv, "c:n:qv", long_options, (int *) 0))
162          != EOF)
163     {
164       switch (c)
165         {
166         case 'c':
167           unit_size = 1;
168           parse_unit (optarg);
169           goto getnum;
170         case 'n':
171           unit_size = 0;
172         getnum:
173           number = atou (optarg);
174           if (number == -1)
175             error (1, 0, "invalid number `%s'", optarg);
176           break;
177
178         case 'q':
179           header_mode = never;
180           break;
181
182         case 'v':
183           header_mode = always;
184           break;
185
186         default:
187           usage ();
188         }
189     }
190
191   if (number == -1)
192     number = DEFAULT_NUMBER;
193
194   if (unit_size > 1)
195     number *= unit_size;
196
197   if (header_mode == always
198       || (header_mode == multiple_files && optind < argc - 1))
199     print_headers = 1;
200
201   if (optind == argc)
202     exit_status |= head_file ("-", number);
203
204   for (; optind < argc; ++optind)
205     exit_status |= head_file (argv[optind], number);
206
207   if (have_read_stdin && close (0) < 0)
208     error (1, errno, "-");
209   if (close (1) < 0)
210     error (1, errno, "write error");
211
212   exit (exit_status);
213 }
214
215 static int
216 head_file (filename, number)
217      char *filename;
218      long number;
219 {
220   int fd;
221
222   if (!strcmp (filename, "-"))
223     {
224       have_read_stdin = 1;
225       filename = "standard input";
226       if (print_headers)
227         write_header (filename);
228       return head (filename, 0, number);
229     }
230   else
231     {
232       fd = open (filename, O_RDONLY);
233       if (fd >= 0)
234         {
235           int errors;
236
237           if (print_headers)
238             write_header (filename);
239           errors = head (filename, fd, number);
240           if (close (fd) == 0)
241             return errors;
242         }
243       error (0, errno, "%s", filename);
244       return 1;
245     }
246 }
247
248 static void
249 write_header (filename)
250      char *filename;
251 {
252   static int first_file = 1;
253
254   if (first_file)
255     {
256       xwrite (1, "==> ", 4);
257       first_file = 0;
258     }
259   else
260     xwrite (1, "\n==> ", 5);
261   xwrite (1, filename, strlen (filename));
262   xwrite (1, " <==\n", 5);
263 }
264
265 static int
266 head (filename, fd, number)
267      char *filename;
268      int fd;
269      long number;
270 {
271   if (unit_size)
272     return head_bytes (filename, fd, number);
273   else
274     return head_lines (filename, fd, number);
275 }
276
277 static int
278 head_bytes (filename, fd, bytes_to_write)
279      char *filename;
280      int fd;
281      long bytes_to_write;
282 {
283   char buffer[BUFSIZE];
284   int bytes_read;
285
286   while (bytes_to_write)
287     {
288       bytes_read = read (fd, buffer, BUFSIZE);
289       if (bytes_read == -1)
290         {
291           error (0, errno, "%s", filename);
292           return 1;
293         }
294       if (bytes_read == 0)
295         break;
296       if (bytes_read > bytes_to_write)
297         bytes_read = bytes_to_write;
298       xwrite (1, buffer, bytes_read);
299       bytes_to_write -= bytes_read;
300     }
301   return 0;
302 }
303
304 static int
305 head_lines (filename, fd, lines_to_write)
306      char *filename;
307      int fd;
308      long lines_to_write;
309 {
310   char buffer[BUFSIZE];
311   int bytes_read;
312   int bytes_to_write;
313
314   while (lines_to_write)
315     {
316       bytes_read = read (fd, buffer, BUFSIZE);
317       if (bytes_read == -1)
318         {
319           error (0, errno, "%s", filename);
320           return 1;
321         }
322       if (bytes_read == 0)
323         break;
324       bytes_to_write = 0;
325       while (bytes_to_write < bytes_read)
326         if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
327           break;
328       xwrite (1, buffer, bytes_to_write);
329     }
330   return 0;
331 }
332
333 static void
334 parse_unit (str)
335      char *str;
336 {
337   int arglen = strlen (str);
338
339   if (arglen == 0)
340     return;
341
342   switch (str[arglen - 1])
343     {
344     case 'b':
345       unit_size = 512;
346       str[arglen - 1] = '\0';
347       break;
348     case 'k':
349       unit_size = 1024;
350       str[arglen - 1] = '\0';
351       break;
352     case 'm':
353       unit_size = 1048576;
354       str[arglen - 1] = '\0';
355       break;
356     }
357 }
358
359 /* Convert STR, a string of ASCII digits, into an unsigned integer.
360    Return -1 if STR does not represent a valid unsigned integer. */
361
362 static long
363 atou (str)
364      char *str;
365 {
366   int value;
367
368   for (value = 0; ISDIGIT (*str); ++str)
369     value = value * 10 + *str - '0';
370   return *str ? -1 : value;
371 }
372
373 static void
374 usage ()
375 {
376   fprintf (stderr, "\
377 Usage: %s [-c N[bkm]] [-n N] [-qv] [--bytes=N[bkm]] [--lines=N]\n\
378        [--quiet] [--silent] [--verbose] [file...]\n\
379        %s [-Nbcklmqv] [file...]\n", program_name, program_name);
380   exit (1);
381 }