- Stephane Billiart writes:
[oweals/busybox.git] / coreutils / head.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * head implementation for busybox
4  *
5  * Copyright (C) 2003  Manuel Novoa III  <mjn3@codepoet.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22
23 /* BB_AUDIT SUSv3 compliant */
24 /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
25 /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <limits.h>
30 #include <ctype.h>
31 #include <unistd.h>
32 #include "busybox.h"
33
34 static const char head_opts[] =
35         "n:"
36 #if ENABLE_FEATURE_FANCY_HEAD
37         "c:qv"
38 #endif
39         ;
40
41 static const char header_fmt_str[] = "\n==> %s <==\n";
42
43 int head_main(int argc, char **argv)
44 {
45         unsigned long count = 10;
46         unsigned long i;
47 #if ENABLE_FEATURE_FANCY_HEAD
48         int count_bytes = 0;
49         int header_threshhold = 1;
50 #endif
51
52         FILE *fp;
53         const char *fmt;
54         char *p;
55         int opt;
56         int c;
57         int retval = EXIT_SUCCESS;
58
59 #if defined CONFIG_FEATURE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
60         /* Allow legacy syntax of an initial numeric option without -n. */
61         if ((argc > 1) && (argv[1][0] == '-')
62                 /* && (isdigit)(argv[1][1]) */
63                 && (((unsigned int)(argv[1][1] - '0')) <= 9)
64         ) {
65                 --argc;
66                 ++argv;
67                 p = (*argv) + 1;
68                 goto GET_COUNT;
69         }
70 #endif
71
72         /* No size benefit in converting this to bb_getopt_ulflags */
73         while ((opt = getopt(argc, argv, head_opts)) > 0) {
74                 switch(opt) {
75 #if ENABLE_FEATURE_FANCY_HEAD
76                         case 'q':
77                                 header_threshhold = INT_MAX;
78                                 break;
79                         case 'v':
80                                 header_threshhold = -1;
81                                 break;
82                         case 'c':
83                                 count_bytes = 1;
84                                 /* fall through */
85 #endif
86                         case 'n':
87                                 p = optarg;
88 #if defined CONFIG_FEATURE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
89                         GET_COUNT:
90 #endif
91                                 count = bb_xgetularg10(p);
92                                 break;
93                         default:
94                                 bb_show_usage();
95                 }
96         }
97
98         argv += optind;
99         if (!*argv) {
100                 *--argv = "-";
101         }
102
103         fmt = header_fmt_str + 1;
104 #if ENABLE_FEATURE_FANCY_HEAD
105         if (argc - optind <= header_threshhold) {
106                 header_threshhold = 0;
107         }
108 #else
109         if (argc <= optind + 1) {
110                 fmt += 11;
111         }
112         /* Now define some things here to avoid #ifdefs in the code below.
113          * These should optimize out of the if conditions below. */
114 #define header_threshhold   1
115 #define count_bytes         0
116 #endif
117
118         do {
119                 if ((fp = bb_wfopen_input(*argv)) != NULL) {
120                         if (fp == stdin) {
121                                 *argv = (char *) bb_msg_standard_input;
122                         }
123                         if (header_threshhold) {
124                                 bb_printf(fmt, *argv);
125                         }
126                         i = count;
127                         while (i && ((c = getc(fp)) != EOF)) {
128                                 if (count_bytes || (c == '\n')) {
129                                         --i;
130                                 }
131                                 putchar(c);
132                         }
133                         if (bb_fclose_nonstdin(fp)) {
134                                 bb_perror_msg("%s", *argv);     /* Avoid multibyte problems. */
135                                 retval = EXIT_FAILURE;
136                         }
137                         bb_xferror_stdout();
138                 }
139                 fmt = header_fmt_str;
140         } while (*++argv);
141
142         bb_fflush_stdout_and_exit(retval);
143 }