hexdump.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. /* hexdump.c - Dump file content in hexadecimal format to stdout
  2. *
  3. * Copyright 2021 Moritz Röhrich <moritz@ildefons.de>
  4. *
  5. * No standard
  6. *
  7. * TODO:
  8. * - Implement format strings (see man (1) hexdump)
  9. USE_HEXDUMP(NEWTOY(hexdump, "bcCdn#<0os#<0vx[!bcCdox]", TOYFLAG_USR|TOYFLAG_BIN))
  10. USE_HD(OLDTOY(hd, hexdump, TOYFLAG_USR|TOYFLAG_BIN))
  11. config HEXDUMP
  12. bool "hexdump"
  13. default n
  14. help
  15. usage: hexdump [-bcCdovx] [-n LEN] [-s SKIP] [FILE...]
  16. Dump file(s) in hexadecimal format.
  17. -n LEN Show LEN bytes of output
  18. -s SKIP Skip bytes of input
  19. -v Verbose (don't combine identical lines)
  20. Display type:
  21. -b One byte octal -c One byte character -C Canonical (hex + ASCII)
  22. -d Two byte decimal -o Two byte octal -x Two byte hexadecimal (default)
  23. config HD
  24. bool "hd"
  25. default HEXDUMP
  26. help
  27. usage: hd [FILE...]
  28. Display file(s) in cannonical hex+ASCII format.
  29. */
  30. #define FOR_hexdump
  31. #include "toys.h"
  32. GLOBALS(
  33. long s, n;
  34. long long len, pos, ppos;
  35. const char *fmt;
  36. unsigned int fn, bc; // file number and byte count
  37. char linebuf[16]; // line buffer - serves double duty for sqeezing repeat
  38. // lines and for accumulating full lines accross file
  39. // boundaries if necessesary.
  40. )
  41. const char *make_printable(unsigned char byte) {
  42. switch (byte) {
  43. case '\0': return "\\0";
  44. case '\a': return "\\a";
  45. case '\b': return "\\b";
  46. case '\t': return "\\t";
  47. case '\n': return "\\n";
  48. case '\v': return "\\v";
  49. case '\f': return "\\f";
  50. default: return "??"; // for all unprintable bytes
  51. }
  52. }
  53. void do_hexdump(int fd, char *name)
  54. {
  55. unsigned short block, adv, i;
  56. int sl, fs; // skip line, file size
  57. TT.fn++; // keep track of how many files have been printed.
  58. // skipp ahead, if necessary skip entire files:
  59. if (FLAG(s) && (TT.s-TT.pos>0)) {
  60. fs = xlseek(fd, 0L, SEEK_END);
  61. if (fs < TT.s) {
  62. TT.pos += fs;
  63. TT.ppos += fs;
  64. } else {
  65. xlseek(fd, TT.s-TT.pos, SEEK_SET);
  66. TT.ppos = TT.s;
  67. TT.pos = TT.s;
  68. }
  69. }
  70. for (sl = 0;
  71. 0 < (TT.len = readall(fd, toybuf,
  72. (TT.n && TT.s+TT.n-TT.pos<16-(TT.bc%16))
  73. ? TT.s+TT.n-TT.pos : 16-(TT.bc%16)));
  74. TT.pos += TT.len) {
  75. // This block compares the data read from file to the last line printed.
  76. // If they don't match a new line is printed, else the line is skipped.
  77. // If a * has already been printed to indicate a skipped line, printing the
  78. // * is also skipped.
  79. for (i = 0; i < 16 && i < TT.len; i++){
  80. if (FLAG(v) || TT.len < 16 || toybuf[i] != TT.linebuf[i]) goto newline;
  81. }
  82. if (sl == 0) {
  83. printf("*\n");
  84. sl = 1;
  85. }
  86. TT.ppos += TT.len;
  87. continue;
  88. newline:
  89. strncpy(TT.linebuf+(TT.bc%16), toybuf, TT.len);
  90. TT.bc = TT.bc % 16 + TT.len;
  91. sl = 0;
  92. if (TT.pos + TT.bc == TT.s+TT.n || TT.fn == toys.optc || TT.bc == 16) {
  93. if (!FLAG(C) && !FLAG(c)) {
  94. printf("%07llx", TT.ppos);
  95. adv = FLAG(b) ? 1 : 2;
  96. for (i = 0; i < TT.bc; i += adv) {
  97. block = (FLAG(b) || i == TT.bc-1)
  98. ? TT.linebuf[i] : (TT.linebuf[i] | TT.linebuf[i+1] << 8);
  99. printf(TT.fmt, block);
  100. }
  101. } else if (FLAG(C)) {
  102. printf("%08llx", TT.ppos);
  103. for (i = 0; i < 16; i++) {
  104. if (!(i % 8)) putchar(' ');
  105. if (i < TT.bc) printf(" %02x", TT.linebuf[i]);
  106. else printf(" ");
  107. }
  108. printf(" |");
  109. for (i = 0; i < TT.bc; i++) {
  110. if (TT.linebuf[i] < ' ' || TT.linebuf[i] > '~') putchar('.');
  111. else putchar(TT.linebuf[i]);
  112. }
  113. putchar('|');
  114. } else {
  115. printf("%07llx", TT.ppos);
  116. for (i = 0; i < TT.bc; i++) {
  117. if (TT.linebuf[i] >= ' ' && TT.linebuf[i] <= '~')
  118. printf("%4c", TT.linebuf[i]);
  119. else printf("%4s", make_printable(TT.linebuf[i]));
  120. }
  121. }
  122. putchar('\n');
  123. TT.ppos += TT.bc;
  124. }
  125. }
  126. if (TT.len < 0) perror_exit("read");
  127. }
  128. void hexdump_main(void)
  129. {
  130. if FLAG(b) TT.fmt = " %03o";
  131. else if FLAG(d) TT.fmt = " %05d";
  132. else if FLAG(o) TT.fmt = " %06o";
  133. else TT.fmt = " %04x";
  134. loopfiles(toys.optargs, do_hexdump);
  135. FLAG(C) ? printf("%08llx\n", TT.pos) : printf("%07llx\n", TT.pos);
  136. }