Loading...
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | /* vi: set sw=4 ts=4: */ /* * head implementation for busybox * * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ //config:config HEAD //config: bool "head (4 kb)" //config: default y //config: help //config: head is used to print the first specified number of lines //config: from files. //config: //config:config FEATURE_FANCY_HEAD //config: bool "Enable -c, -q, and -v" //config: default y //config: depends on HEAD //applet:IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) //kbuild:lib-$(CONFIG_HEAD) += head.o /* BB_AUDIT SUSv3 compliant */ /* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ //usage:#define head_trivial_usage //usage: "[OPTIONS] [FILE]..." //usage:#define head_full_usage "\n\n" //usage: "Print first 10 lines of FILEs (or stdin).\n" //usage: "With more than one FILE, precede each with a filename header.\n" //usage: "\n -n N[bkm] Print first N lines" //usage: IF_FEATURE_FANCY_HEAD( //usage: "\n -n -N[bkm] Print all except N last lines" //usage: "\n -c [-]N[bkm] Print first N bytes" //usage: ) //usage: "\n (b:*512 k:*1024 m:*1024^2)" //usage: IF_FEATURE_FANCY_HEAD( //usage: "\n -q Never print headers" //usage: "\n -v Always print headers" //usage: ) //usage: //usage:#define head_example_usage //usage: "$ head -n 2 /etc/passwd\n" //usage: "root:x:0:0:root:/root:/bin/bash\n" //usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ #if !ENABLE_FEATURE_FANCY_HEAD # define print_first_N(fp,count,bytes) print_first_N(fp,count) #endif static void print_first_N(FILE *fp, unsigned long count, bool count_bytes) { #if !ENABLE_FEATURE_FANCY_HEAD const int count_bytes = 0; #endif while (count) { int c = getc(fp); if (c == EOF) break; if (count_bytes || (c == '\n')) --count; putchar(c); } } #if ENABLE_FEATURE_FANCY_HEAD static void print_except_N_last_bytes(FILE *fp, unsigned count) { unsigned char *circle = xmalloc(++count); unsigned head = 0; for (;;) { int c; c = getc(fp); if (c == EOF) goto ret; circle[head++] = c; if (head == count) break; } for (;;) { int c; if (head == count) head = 0; putchar(circle[head]); c = getc(fp); if (c == EOF) goto ret; circle[head] = c; head++; } ret: free(circle); } static void print_except_N_last_lines(FILE *fp, unsigned count) { char **circle = xzalloc((++count) * sizeof(circle[0])); unsigned head = 0; for (;;) { char *c; c = xmalloc_fgets(fp); if (!c) goto ret; circle[head++] = c; if (head == count) break; } for (;;) { char *c; if (head == count) head = 0; fputs_stdout(circle[head]); c = xmalloc_fgets(fp); if (!c) goto ret; free(circle[head]); circle[head++] = c; } ret: head = 0; for (;;) { free(circle[head++]); if (head == count) break; } free(circle); } #else /* Must never be called */ void print_except_N_last_bytes(FILE *fp, unsigned count); void print_except_N_last_lines(FILE *fp, unsigned count); #endif #if !ENABLE_FEATURE_FANCY_HEAD # define eat_num(negative_N,p) eat_num(p) #endif static unsigned long eat_num(bool *negative_N, const char *p) { #if ENABLE_FEATURE_FANCY_HEAD if (*p == '-') { *negative_N = 1; p++; } #endif return xatoul_sfx(p, bkm_suffixes); } static const char head_opts[] ALIGN1 = "n:" #if ENABLE_FEATURE_FANCY_HEAD "c:qv" #endif ; #define header_fmt_str "\n==> %s <==\n" int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int head_main(int argc, char **argv) { unsigned long count = 10; #if ENABLE_FEATURE_FANCY_HEAD int header_threshhold = 1; bool count_bytes = 0; bool negative_N = 0; #else # define header_threshhold 1 # define count_bytes 0 # define negative_N 0 #endif FILE *fp; const char *fmt; char *p; int opt; int retval = EXIT_SUCCESS; #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD /* Allow legacy syntax of an initial numeric option without -n. */ if (argv[1] && argv[1][0] == '-' && isdigit(argv[1][1]) ) { --argc; ++argv; p = argv[0] + 1; goto GET_COUNT; } #endif /* No size benefit in converting this to getopt32 */ while ((opt = getopt(argc, argv, head_opts)) > 0) { switch (opt) { #if ENABLE_FEATURE_FANCY_HEAD case 'q': header_threshhold = INT_MAX; break; case 'v': header_threshhold = -1; break; case 'c': count_bytes = 1; /* fall through */ #endif case 'n': p = optarg; #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD GET_COUNT: #endif count = eat_num(&negative_N, p); break; default: bb_show_usage(); } } argc -= optind; argv += optind; if (!*argv) *--argv = (char*)"-"; fmt = header_fmt_str + 1; if (argc <= header_threshhold) { #if ENABLE_FEATURE_FANCY_HEAD header_threshhold = 0; #else fmt += 11; /* "" */ #endif } if (negative_N) { if (count >= INT_MAX / sizeof(char*)) bb_error_msg("count is too big: %lu", count); } do { fp = fopen_or_warn_stdin(*argv); if (fp) { if (fp == stdin) { *argv = (char *) bb_msg_standard_input; } if (header_threshhold) { printf(fmt, *argv); } if (negative_N) { if (count_bytes) { print_except_N_last_bytes(fp, count); } else { print_except_N_last_lines(fp, count); } } else { print_first_N(fp, count, count_bytes); } die_if_ferror_stdout(); if (fclose_if_not_stdin(fp)) { bb_simple_perror_msg(*argv); retval = EXIT_FAILURE; } } else { retval = EXIT_FAILURE; } fmt = header_fmt_str; } while (*++argv); fflush_stdout_and_exit(retval); } |