hexl.c 4.49 KB
Newer Older
1
/* Convert files for Emacs Hexl mode.
Paul Eggert's avatar
Paul Eggert committed
2
   Copyright (C) 1989, 2001-2017 Free Software Foundation, Inc.
3

4
Author: Keith Gabryelski (according to authors.el)
5 6 7

This file is not considered part of GNU Emacs.

8
This program is free software: you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10 11
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
12 13 14 15 16 17 18

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
19 20
along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

21

22 23
#include <config.h>

24
#include <inttypes.h>
Paul Eggert's avatar
Paul Eggert committed
25 26
#include <stdlib.h>
#include <string.h>
27 28

#include <binary-io.h>
29
#include <unlocked-io.h>
Jim Blandy's avatar
Jim Blandy committed
30

31
static char *progname;
Jim Blandy's avatar
Jim Blandy committed
32

33 34 35 36 37 38
static _Noreturn void
output_error (void)
{
  fprintf (stderr, "%s: write error\n", progname);
  exit (EXIT_FAILURE);
}
Jim Blandy's avatar
Jim Blandy committed
39

40 41 42 43 44
static int
hexchar (int c)
{
  return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
}
45 46

int
47
main (int argc, char **argv)
Jim Blandy's avatar
Jim Blandy committed
48
{
49 50 51 52 53
  int status = EXIT_SUCCESS;
  int DEFAULT_GROUPING = 0x01;
  int group_by = DEFAULT_GROUPING;
  bool un_flag = false, iso_flag = false;
  progname = *argv++;
54 55 56 57 58 59 60 61 62 63 64 65 66

  /*
   ** -hex		hex dump
   ** -group-by-8-bits
   ** -group-by-16-bits
   ** -group-by-32-bits
   ** -group-by-64-bits
   ** -iso		iso character set.
   ** -un || -de	from hexl format to binary.
   ** --		End switch list.
   ** <filename>	dump filename
   ** -		(as filename == stdin)
   */
Pavel Janík's avatar
Pavel Janík committed
67

68
  for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
Jim Blandy's avatar
Jim Blandy committed
69
    {
70 71
      /* A switch! */
      if (!strcmp (*argv, "--"))
Jim Blandy's avatar
Jim Blandy committed
72
	{
73
	  argv++;
74 75 76
	  break;
	}
      else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
Jim Blandy's avatar
Jim Blandy committed
77
	{
78
	  un_flag = true;
Paul Eggert's avatar
Paul Eggert committed
79
	  set_binary_mode (fileno (stdout), O_BINARY);
80 81
	}
      else if (!strcmp (*argv, "-hex"))
82
	/* Hex is the default and is only base supported.  */;
83
      else if (!strcmp (*argv, "-iso"))
84
	iso_flag = true;
85
      else if (!strcmp (*argv, "-group-by-8-bits"))
86
	group_by = 0x00;
87
      else if (!strcmp (*argv, "-group-by-16-bits"))
88
	group_by = 0x01;
89
      else if (!strcmp (*argv, "-group-by-32-bits"))
90
	group_by = 0x03;
91
      else if (!strcmp (*argv, "-group-by-64-bits"))
92
	group_by = 0x07;
93
      else
Jim Blandy's avatar
Jim Blandy committed
94
	{
95 96
	  fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
		   *argv);
97 98
	  fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
	  return EXIT_FAILURE;
Jim Blandy's avatar
Jim Blandy committed
99 100 101
	}
    }

102 103
  char const *filename = *argv ? *argv++ : "-";

104
  do
Jim Blandy's avatar
Jim Blandy committed
105
    {
106 107 108 109 110 111
      FILE *fp;

      if (!strcmp (filename, "-"))
	{
	  fp = stdin;
	  if (!un_flag)
Paul Eggert's avatar
Paul Eggert committed
112
	    set_binary_mode (fileno (stdin), O_BINARY);
113
	}
114
      else
Jim Blandy's avatar
Jim Blandy committed
115
	{
116 117
	  fp = fopen (filename, un_flag ? "r" : "rb");
	  if (!fp)
118 119
	    {
	      perror (filename);
120
	      status = EXIT_FAILURE;
121 122
	      continue;
	    }
Jim Blandy's avatar
Jim Blandy committed
123 124
	}

125
      if (un_flag)
Jim Blandy's avatar
Jim Blandy committed
126
	{
127
	  for (int c; 0 <= (c = getc (fp)); )
Jim Blandy's avatar
Jim Blandy committed
128
	    {
129 130 131
	      /* Skip address at start of line.  */
	      if (c != ' ')
		continue;
Jim Blandy's avatar
Jim Blandy committed
132

133
	      for (int i = 0; i < 16; i++)
Jim Blandy's avatar
Jim Blandy committed
134
		{
135 136
		  c = getc (fp);
		  if (c < 0 || c == ' ')
137
		    break;
Jim Blandy's avatar
Jim Blandy committed
138

139 140 141
		  int hc = hexchar (c);
		  c = getc (fp);
		  if (c < 0)
142
		    break;
143
		  putchar (hc * 0x10 + hexchar (c));
Jim Blandy's avatar
Jim Blandy committed
144

145 146 147 148 149 150
		  if ((i & group_by) == group_by)
		    {
		      c = getc (fp);
		      if (c < 0)
			break;
		    }
Jim Blandy's avatar
Jim Blandy committed
151
		}
152 153 154 155 156 157 158

	      while (0 <= c && c != '\n')
		c = getc (fp);
	      if (c < 0)
		break;
	      if (ferror (stdout))
		output_error ();
Jim Blandy's avatar
Jim Blandy committed
159 160
	    }
	}
161
      else
Jim Blandy's avatar
Jim Blandy committed
162
	{
163 164
	  int c = 0;
	  char string[18];
165 166
	  string[0] = ' ';
	  string[17] = '\0';
167
	  for (uintmax_t address = 0; 0 <= c; address += 0x10)
Jim Blandy's avatar
Jim Blandy committed
168
	    {
169 170
	      int i;
	      for (i = 0; i < 16; i++)
Jim Blandy's avatar
Jim Blandy committed
171
		{
172 173 174
		  if (0 <= c)
		    c = getc (fp);
		  if (c < 0)
Jim Blandy's avatar
Jim Blandy committed
175
		    {
176 177
		      if (!i)
			break;
Jim Blandy's avatar
Jim Blandy committed
178

179
		      fputs ("  ", stdout);
180
		      string[i + 1] = '\0';
Jim Blandy's avatar
Jim Blandy committed
181
		    }
182
		  else
Jim Blandy's avatar
Jim Blandy committed
183
		    {
184
		      if (!i)
185
			printf ("%08"PRIxMAX": ", address);
Jim Blandy's avatar
Jim Blandy committed
186

187 188 189
		      string[i + 1]
			= (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
			   ? '.' : c);
Jim Blandy's avatar
Jim Blandy committed
190

191
		      printf ("%02x", c + 0u);
Jim Blandy's avatar
Jim Blandy committed
192 193
		    }

194
		  if ((i & group_by) == group_by)
195
		    putchar (' ');
Jim Blandy's avatar
Jim Blandy committed
196 197
		}

198 199
	      if (i)
		puts (string);
Jim Blandy's avatar
Jim Blandy committed
200

201 202
	      if (ferror (stdout))
		output_error ();
Jim Blandy's avatar
Jim Blandy committed
203 204 205
	    }
	}

206 207 208 209 210 211 212
      bool trouble = ferror (fp) != 0;
      trouble |= fp != stdin && fclose (fp) != 0;
      if (trouble)
	{
	  fprintf (stderr, "%s: read error\n", progname);
	  status = EXIT_FAILURE;
	}
Jim Blandy's avatar
Jim Blandy committed
213

214 215 216
      filename = *argv++;
    }
  while (filename);
Jim Blandy's avatar
Jim Blandy committed
217

218 219 220
  if (ferror (stdout) || fclose (stdout) != 0)
    output_error ();
  return status;
Jim Blandy's avatar
Jim Blandy committed
221
}