head.c 5.7 KB

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