head.c 5.7 KB

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