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