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 tarball for details.
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#include "libbb.h"
15
16static const char head_opts[] ALIGN1 =
17	"n:"
18#if ENABLE_FEATURE_FANCY_HEAD
19	"c:qv"
20#endif
21	;
22
23#if ENABLE_FEATURE_FANCY_HEAD
24static const struct suffix_mult head_suffixes[] = {
25	{ "b", 512 },
26	{ "k", 1024 },
27	{ "m", 1024*1024 },
28	{ }
29};
30#endif
31
32static const char header_fmt_str[] ALIGN1 = "\n==> %s <==\n";
33
34int head_main(int argc, char **argv);
35int head_main(int argc, char **argv)
36{
37	unsigned long count = 10;
38	unsigned long i;
39#if ENABLE_FEATURE_FANCY_HEAD
40	int count_bytes = 0;
41	int header_threshhold = 1;
42#endif
43
44	FILE *fp;
45	const char *fmt;
46	char *p;
47	int opt;
48	int c;
49	int retval = EXIT_SUCCESS;
50
51#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
52	/* Allow legacy syntax of an initial numeric option without -n. */
53	if (argc > 1 && argv[1][0] == '-'
54	 && isdigit(argv[1][1])
55	) {
56		--argc;
57		++argv;
58		p = (*argv) + 1;
59		goto GET_COUNT;
60	}
61#endif
62
63	/* No size benefit in converting this to getopt32 */
64	while ((opt = getopt(argc, argv, head_opts)) > 0) {
65		switch (opt) {
66#if ENABLE_FEATURE_FANCY_HEAD
67		case 'q':
68			header_threshhold = INT_MAX;
69			break;
70		case 'v':
71			header_threshhold = -1;
72			break;
73		case 'c':
74			count_bytes = 1;
75			/* fall through */
76#endif
77		case 'n':
78			p = optarg;
79#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD
80 GET_COUNT:
81#endif
82
83#if !ENABLE_FEATURE_FANCY_HEAD
84			count = xatoul(p);
85#else
86			count = xatoul_sfx(p, head_suffixes);
87#endif
88			break;
89		default:
90			bb_show_usage();
91		}
92	}
93
94	argv += optind;
95	if (!*argv) {
96		*--argv = (char*)"-";
97	}
98
99	fmt = header_fmt_str + 1;
100#if ENABLE_FEATURE_FANCY_HEAD
101	if (argc - optind <= header_threshhold) {
102		header_threshhold = 0;
103	}
104#else
105	if (argc <= optind + 1) {
106		fmt += 11;
107	}
108	/* Now define some things here to avoid #ifdefs in the code below.
109	 * These should optimize out of the if conditions below. */
110#define header_threshhold   1
111#define count_bytes         0
112#endif
113
114	do {
115		fp = fopen_or_warn_stdin(*argv);
116		if (fp) {
117			if (fp == stdin) {
118				*argv = (char *) bb_msg_standard_input;
119			}
120			if (header_threshhold) {
121				printf(fmt, *argv);
122			}
123			i = count;
124			while (i && ((c = getc(fp)) != EOF)) {
125				if (count_bytes || (c == '\n')) {
126					--i;
127				}
128				putchar(c);
129			}
130			if (fclose_if_not_stdin(fp)) {
131				bb_perror_msg("%s", *argv);	/* Avoid multibyte problems. */
132				retval = EXIT_FAILURE;
133			}
134			die_if_ferror_stdout();
135		}
136		fmt = header_fmt_str;
137	} while (*++argv);
138
139	fflush_stdout_and_exit(retval);
140}
141