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