source: MondoRescue/branches/3.3/mindi-busybox/coreutils/head.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 5.3 KB
Line 
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 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* BB_AUDIT SUSv3 compliant */
11/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */
12/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */
13
14//kbuild:lib-$(CONFIG_HEAD) += head.o
15
16//usage:#define head_trivial_usage
17//usage: "[OPTIONS] [FILE]..."
18//usage:#define head_full_usage "\n\n"
19//usage: "Print first 10 lines of each FILE (or stdin) to stdout.\n"
20//usage: "With more than one FILE, precede each with a filename header.\n"
21//usage: "\n -n N[kbm] Print first N lines"
22//usage: IF_FEATURE_FANCY_HEAD(
23//usage: "\n -n -N[kbm] Print all except N last lines"
24//usage: "\n -c [-]N[kbm] Print first N bytes"
25//usage: "\n -q Never print headers"
26//usage: "\n -v Always print headers"
27//usage: )
28//usage: "\n"
29//usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)."
30//usage:
31//usage:#define head_example_usage
32//usage: "$ head -n 2 /etc/passwd\n"
33//usage: "root:x:0:0:root:/root:/bin/bash\n"
34//usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
35
36#include "libbb.h"
37
38/* This is a NOEXEC applet. Be very careful! */
39
40#if !ENABLE_FEATURE_FANCY_HEAD
41# define print_first_N(fp,count,bytes) print_first_N(fp,count)
42#endif
43static void
44print_first_N(FILE *fp, unsigned long count, bool count_bytes)
45{
46#if !ENABLE_FEATURE_FANCY_HEAD
47 const int count_bytes = 0;
48#endif
49 while (count) {
50 int c = getc(fp);
51 if (c == EOF)
52 break;
53 if (count_bytes || (c == '\n'))
54 --count;
55 putchar(c);
56 }
57}
58
59#if ENABLE_FEATURE_FANCY_HEAD
60static void
61print_except_N_last_bytes(FILE *fp, unsigned count)
62{
63 unsigned char *circle = xmalloc(++count);
64 unsigned head = 0;
65 for(;;) {
66 int c;
67 c = getc(fp);
68 if (c == EOF)
69 goto ret;
70 circle[head++] = c;
71 if (head == count)
72 break;
73 }
74 for (;;) {
75 int c;
76 if (head == count)
77 head = 0;
78 putchar(circle[head]);
79 c = getc(fp);
80 if (c == EOF)
81 goto ret;
82 circle[head] = c;
83 head++;
84 }
85 ret:
86 free(circle);
87}
88
89static void
90print_except_N_last_lines(FILE *fp, unsigned count)
91{
92 char **circle = xzalloc((++count) * sizeof(circle[0]));
93 unsigned head = 0;
94 for(;;) {
95 char *c;
96 c = xmalloc_fgets(fp);
97 if (!c)
98 goto ret;
99 circle[head++] = c;
100 if (head == count)
101 break;
102 }
103 for (;;) {
104 char *c;
105 if (head == count)
106 head = 0;
107 fputs(circle[head], stdout);
108 c = xmalloc_fgets(fp);
109 if (!c)
110 goto ret;
111 free(circle[head]);
112 circle[head++] = c;
113 }
114 ret:
115 head = 0;
116 for(;;) {
117 free(circle[head++]);
118 if (head == count)
119 break;
120 }
121 free(circle);
122}
123#else
124/* Must never be called */
125void print_except_N_last_bytes(FILE *fp, unsigned count);
126void print_except_N_last_lines(FILE *fp, unsigned count);
127#endif
128
129#if !ENABLE_FEATURE_FANCY_HEAD
130# define eat_num(negative_N,p) eat_num(p)
131#endif
132static unsigned long
133eat_num(bool *negative_N, const char *p)
134{
135#if ENABLE_FEATURE_FANCY_HEAD
136 if (*p == '-') {
137 *negative_N = 1;
138 p++;
139 }
140#endif
141 return xatoul_sfx(p, bkm_suffixes);
142}
143
144static const char head_opts[] ALIGN1 =
145 "n:"
146#if ENABLE_FEATURE_FANCY_HEAD
147 "c:qv"
148#endif
149 ;
150
151#define header_fmt_str "\n==> %s <==\n"
152
153int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
154int head_main(int argc, char **argv)
155{
156 unsigned long count = 10;
157#if ENABLE_FEATURE_FANCY_HEAD
158 int header_threshhold = 1;
159 bool count_bytes = 0;
160 bool negative_N = 0;
161#else
162# define header_threshhold 1
163# define count_bytes 0
164# define negative_N 0
165#endif
166 FILE *fp;
167 const char *fmt;
168 char *p;
169 int opt;
170 int retval = EXIT_SUCCESS;
171
172#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
173 /* Allow legacy syntax of an initial numeric option without -n. */
174 if (argv[1] && argv[1][0] == '-'
175 && isdigit(argv[1][1])
176 ) {
177 --argc;
178 ++argv;
179 p = argv[0] + 1;
180 goto GET_COUNT;
181 }
182#endif
183
184 /* No size benefit in converting this to getopt32 */
185 while ((opt = getopt(argc, argv, head_opts)) > 0) {
186 switch (opt) {
187#if ENABLE_FEATURE_FANCY_HEAD
188 case 'q':
189 header_threshhold = INT_MAX;
190 break;
191 case 'v':
192 header_threshhold = -1;
193 break;
194 case 'c':
195 count_bytes = 1;
196 /* fall through */
197#endif
198 case 'n':
199 p = optarg;
200#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
201 GET_COUNT:
202#endif
203 count = eat_num(&negative_N, p);
204 break;
205 default:
206 bb_show_usage();
207 }
208 }
209
210 argc -= optind;
211 argv += optind;
212 if (!*argv)
213 *--argv = (char*)"-";
214
215 fmt = header_fmt_str + 1;
216 if (argc <= header_threshhold) {
217#if ENABLE_FEATURE_FANCY_HEAD
218 header_threshhold = 0;
219#else
220 fmt += 11; /* "" */
221#endif
222 }
223 if (negative_N) {
224 if (count >= INT_MAX / sizeof(char*))
225 bb_error_msg("count is too big: %lu", count);
226 }
227
228 do {
229 fp = fopen_or_warn_stdin(*argv);
230 if (fp) {
231 if (fp == stdin) {
232 *argv = (char *) bb_msg_standard_input;
233 }
234 if (header_threshhold) {
235 printf(fmt, *argv);
236 }
237 if (negative_N) {
238 if (count_bytes) {
239 print_except_N_last_bytes(fp, count);
240 } else {
241 print_except_N_last_lines(fp, count);
242 }
243 } else {
244 print_first_N(fp, count, count_bytes);
245 }
246 die_if_ferror_stdout();
247 if (fclose_if_not_stdin(fp)) {
248 bb_simple_perror_msg(*argv);
249 retval = EXIT_FAILURE;
250 }
251 } else {
252 retval = EXIT_FAILURE;
253 }
254 fmt = header_fmt_str;
255 } while (*++argv);
256
257 fflush_stdout_and_exit(retval);
258}
Note: See TracBrowser for help on using the repository browser.