head.c 5.3 KB

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