hexl.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* Convert files for Emacs Hexl mode.
  2. Copyright (C) 1989, 2001-2017 Free Software Foundation, Inc.
  3. Author: Keith Gabryelski (according to authors.el)
  4. This file is not considered part of GNU Emacs.
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or (at
  8. your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include <config.h>
  16. #include <inttypes.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <binary-io.h>
  20. #include <unlocked-io.h>
  21. static char *progname;
  22. static _Noreturn void
  23. output_error (void)
  24. {
  25. fprintf (stderr, "%s: write error\n", progname);
  26. exit (EXIT_FAILURE);
  27. }
  28. static int
  29. hexchar (int c)
  30. {
  31. return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
  32. }
  33. int
  34. main (int argc, char **argv)
  35. {
  36. int status = EXIT_SUCCESS;
  37. int DEFAULT_GROUPING = 0x01;
  38. int group_by = DEFAULT_GROUPING;
  39. bool un_flag = false, iso_flag = false;
  40. progname = *argv++;
  41. /*
  42. ** -hex hex dump
  43. ** -group-by-8-bits
  44. ** -group-by-16-bits
  45. ** -group-by-32-bits
  46. ** -group-by-64-bits
  47. ** -iso iso character set.
  48. ** -un || -de from hexl format to binary.
  49. ** -- End switch list.
  50. ** <filename> dump filename
  51. ** - (as filename == stdin)
  52. */
  53. for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
  54. {
  55. /* A switch! */
  56. if (!strcmp (*argv, "--"))
  57. {
  58. argv++;
  59. break;
  60. }
  61. else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
  62. {
  63. un_flag = true;
  64. set_binary_mode (fileno (stdout), O_BINARY);
  65. }
  66. else if (!strcmp (*argv, "-hex"))
  67. /* Hex is the default and is only base supported. */;
  68. else if (!strcmp (*argv, "-iso"))
  69. iso_flag = true;
  70. else if (!strcmp (*argv, "-group-by-8-bits"))
  71. group_by = 0x00;
  72. else if (!strcmp (*argv, "-group-by-16-bits"))
  73. group_by = 0x01;
  74. else if (!strcmp (*argv, "-group-by-32-bits"))
  75. group_by = 0x03;
  76. else if (!strcmp (*argv, "-group-by-64-bits"))
  77. group_by = 0x07;
  78. else
  79. {
  80. fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
  81. *argv);
  82. fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
  83. return EXIT_FAILURE;
  84. }
  85. }
  86. char const *filename = *argv ? *argv++ : "-";
  87. do
  88. {
  89. FILE *fp;
  90. if (!strcmp (filename, "-"))
  91. {
  92. fp = stdin;
  93. if (!un_flag)
  94. set_binary_mode (fileno (stdin), O_BINARY);
  95. }
  96. else
  97. {
  98. fp = fopen (filename, un_flag ? "r" : "rb");
  99. if (!fp)
  100. {
  101. perror (filename);
  102. status = EXIT_FAILURE;
  103. continue;
  104. }
  105. }
  106. if (un_flag)
  107. {
  108. for (int c; 0 <= (c = getc (fp)); )
  109. {
  110. /* Skip address at start of line. */
  111. if (c != ' ')
  112. continue;
  113. for (int i = 0; i < 16; i++)
  114. {
  115. c = getc (fp);
  116. if (c < 0 || c == ' ')
  117. break;
  118. int hc = hexchar (c);
  119. c = getc (fp);
  120. if (c < 0)
  121. break;
  122. putchar (hc * 0x10 + hexchar (c));
  123. if ((i & group_by) == group_by)
  124. {
  125. c = getc (fp);
  126. if (c < 0)
  127. break;
  128. }
  129. }
  130. while (0 <= c && c != '\n')
  131. c = getc (fp);
  132. if (c < 0)
  133. break;
  134. if (ferror (stdout))
  135. output_error ();
  136. }
  137. }
  138. else
  139. {
  140. int c = 0;
  141. char string[18];
  142. string[0] = ' ';
  143. string[17] = '\0';
  144. for (uintmax_t address = 0; 0 <= c; address += 0x10)
  145. {
  146. int i;
  147. for (i = 0; i < 16; i++)
  148. {
  149. if (0 <= c)
  150. c = getc (fp);
  151. if (c < 0)
  152. {
  153. if (!i)
  154. break;
  155. fputs (" ", stdout);
  156. string[i + 1] = '\0';
  157. }
  158. else
  159. {
  160. if (!i)
  161. printf ("%08"PRIxMAX": ", address);
  162. string[i + 1]
  163. = (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
  164. ? '.' : c);
  165. printf ("%02x", c + 0u);
  166. }
  167. if ((i & group_by) == group_by)
  168. putchar (' ');
  169. }
  170. if (i)
  171. puts (string);
  172. if (ferror (stdout))
  173. output_error ();
  174. }
  175. }
  176. bool trouble = ferror (fp) != 0;
  177. trouble |= fp != stdin && fclose (fp) != 0;
  178. if (trouble)
  179. {
  180. fprintf (stderr, "%s: read error\n", progname);
  181. status = EXIT_FAILURE;
  182. }
  183. filename = *argv++;
  184. }
  185. while (filename);
  186. if (ferror (stdout) || fclose (stdout) != 0)
  187. output_error ();
  188. return status;
  189. }