1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49#include "libbb.h"
50
51
52
53#if !ENABLE_FEATURE_FANCY_HEAD
54# define print_first_N(fp,count,bytes) print_first_N(fp,count)
55#endif
56static void
57print_first_N(FILE *fp, unsigned long count, bool count_bytes)
58{
59#if !ENABLE_FEATURE_FANCY_HEAD
60 const int count_bytes = 0;
61#endif
62 while (count) {
63 int c = getc(fp);
64 if (c == EOF)
65 break;
66 if (count_bytes || (c == '\n'))
67 --count;
68 putchar(c);
69 }
70}
71
72#if ENABLE_FEATURE_FANCY_HEAD
73static void
74print_except_N_last_bytes(FILE *fp, unsigned count)
75{
76 unsigned char *circle = xmalloc(++count);
77 unsigned head = 0;
78 for(;;) {
79 int c;
80 c = getc(fp);
81 if (c == EOF)
82 goto ret;
83 circle[head++] = c;
84 if (head == count)
85 break;
86 }
87 for (;;) {
88 int c;
89 if (head == count)
90 head = 0;
91 putchar(circle[head]);
92 c = getc(fp);
93 if (c == EOF)
94 goto ret;
95 circle[head] = c;
96 head++;
97 }
98 ret:
99 free(circle);
100}
101
102static void
103print_except_N_last_lines(FILE *fp, unsigned count)
104{
105 char **circle = xzalloc((++count) * sizeof(circle[0]));
106 unsigned head = 0;
107 for(;;) {
108 char *c;
109 c = xmalloc_fgets(fp);
110 if (!c)
111 goto ret;
112 circle[head++] = c;
113 if (head == count)
114 break;
115 }
116 for (;;) {
117 char *c;
118 if (head == count)
119 head = 0;
120 fputs(circle[head], stdout);
121 c = xmalloc_fgets(fp);
122 if (!c)
123 goto ret;
124 free(circle[head]);
125 circle[head++] = c;
126 }
127 ret:
128 head = 0;
129 for(;;) {
130 free(circle[head++]);
131 if (head == count)
132 break;
133 }
134 free(circle);
135}
136#else
137
138void print_except_N_last_bytes(FILE *fp, unsigned count);
139void print_except_N_last_lines(FILE *fp, unsigned count);
140#endif
141
142#if !ENABLE_FEATURE_FANCY_HEAD
143# define eat_num(negative_N,p) eat_num(p)
144#endif
145static unsigned long
146eat_num(bool *negative_N, const char *p)
147{
148#if ENABLE_FEATURE_FANCY_HEAD
149 if (*p == '-') {
150 *negative_N = 1;
151 p++;
152 }
153#endif
154 return xatoul_sfx(p, bkm_suffixes);
155}
156
157static const char head_opts[] ALIGN1 =
158 "n:"
159#if ENABLE_FEATURE_FANCY_HEAD
160 "c:qv"
161#endif
162 ;
163
164#define header_fmt_str "\n==> %s <==\n"
165
166int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
167int head_main(int argc, char **argv)
168{
169 unsigned long count = 10;
170#if ENABLE_FEATURE_FANCY_HEAD
171 int header_threshhold = 1;
172 bool count_bytes = 0;
173 bool negative_N = 0;
174#else
175# define header_threshhold 1
176# define count_bytes 0
177# define negative_N 0
178#endif
179 FILE *fp;
180 const char *fmt;
181 char *p;
182 int opt;
183 int retval = EXIT_SUCCESS;
184
185#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
186
187 if (argv[1] && argv[1][0] == '-'
188 && isdigit(argv[1][1])
189 ) {
190 --argc;
191 ++argv;
192 p = argv[0] + 1;
193 goto GET_COUNT;
194 }
195#endif
196
197
198 while ((opt = getopt(argc, argv, head_opts)) > 0) {
199 switch (opt) {
200#if ENABLE_FEATURE_FANCY_HEAD
201 case 'q':
202 header_threshhold = INT_MAX;
203 break;
204 case 'v':
205 header_threshhold = -1;
206 break;
207 case 'c':
208 count_bytes = 1;
209
210#endif
211 case 'n':
212 p = optarg;
213#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
214 GET_COUNT:
215#endif
216 count = eat_num(&negative_N, p);
217 break;
218 default:
219 bb_show_usage();
220 }
221 }
222
223 argc -= optind;
224 argv += optind;
225 if (!*argv)
226 *--argv = (char*)"-";
227
228 fmt = header_fmt_str + 1;
229 if (argc <= header_threshhold) {
230#if ENABLE_FEATURE_FANCY_HEAD
231 header_threshhold = 0;
232#else
233 fmt += 11;
234#endif
235 }
236 if (negative_N) {
237 if (count >= INT_MAX / sizeof(char*))
238 bb_error_msg("count is too big: %lu", count);
239 }
240
241 do {
242 fp = fopen_or_warn_stdin(*argv);
243 if (fp) {
244 if (fp == stdin) {
245 *argv = (char *) bb_msg_standard_input;
246 }
247 if (header_threshhold) {
248 printf(fmt, *argv);
249 }
250 if (negative_N) {
251 if (count_bytes) {
252 print_except_N_last_bytes(fp, count);
253 } else {
254 print_except_N_last_lines(fp, count);
255 }
256 } else {
257 print_first_N(fp, count, count_bytes);
258 }
259 die_if_ferror_stdout();
260 if (fclose_if_not_stdin(fp)) {
261 bb_simple_perror_msg(*argv);
262 retval = EXIT_FAILURE;
263 }
264 } else {
265 retval = EXIT_FAILURE;
266 }
267 fmt = header_fmt_str;
268 } while (*++argv);
269
270 fflush_stdout_and_exit(retval);
271}
272