1/* Convert files for Emacs Hexl mode.
2   Copyright (C) 1989, 2001, 2002, 2003, 2004, 2005,
3                 2006, 2007  Free Software Foundation, Inc.
4
5This file is not considered part of GNU Emacs.
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program; if not, write to the Free Software Foundation,
19Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include <stdio.h>
26#include <ctype.h>
27#ifdef DOS_NT
28#include <fcntl.h>
29#if __DJGPP__ >= 2
30#include <io.h>
31#endif
32#endif
33#ifdef WINDOWSNT
34#include <io.h>
35#endif
36
37#define DEFAULT_GROUPING	0x01
38#define DEFAULT_BASE		16
39
40#undef TRUE
41#undef FALSE
42#define TRUE  (1)
43#define FALSE (0)
44
45int base = DEFAULT_BASE, un_flag = FALSE, iso_flag = FALSE, endian = 1;
46int group_by = DEFAULT_GROUPING;
47char *progname;
48
49void usage();
50
51int
52main (argc, argv)
53     int argc;
54     char *argv[];
55{
56  register long address;
57  char string[18];
58  FILE *fp;
59
60  progname = *argv++; --argc;
61
62  /*
63   ** -hex		hex dump
64   ** -oct		Octal dump
65   ** -group-by-8-bits
66   ** -group-by-16-bits
67   ** -group-by-32-bits
68   ** -group-by-64-bits
69   ** -iso		iso character set.
70   ** -big-endian	Big Endian
71   ** -little-endian	Little Endian
72   ** -un || -de	from hexl format to binary.
73   ** --		End switch list.
74   ** <filename>	dump filename
75   ** -		(as filename == stdin)
76   */
77
78  while (*argv && *argv[0] == '-' && (*argv)[1])
79    {
80      /* A switch! */
81      if (!strcmp (*argv, "--"))
82	{
83	  --argc; argv++;
84	  break;
85	}
86      else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
87	{
88	  un_flag = TRUE;
89	  --argc; argv++;
90	}
91      else if (!strcmp (*argv, "-hex"))
92	{
93	  base = 16;
94	  --argc; argv++;
95	}
96      else if (!strcmp (*argv, "-iso"))
97	{
98	  iso_flag = TRUE;
99	  --argc; argv++;
100	}
101      else if (!strcmp (*argv, "-oct"))
102	{
103	  base = 8;
104	  --argc; argv++;
105	}
106      else if (!strcmp (*argv, "-big-endian"))
107	{
108	  endian = 1;
109	  --argc; argv++;
110	}
111      else if (!strcmp (*argv, "-little-endian"))
112	{
113	  endian = 0;
114	  --argc; argv++;
115	}
116      else if (!strcmp (*argv, "-group-by-8-bits"))
117	{
118	  group_by = 0x00;
119	  --argc; argv++;
120	}
121      else if (!strcmp (*argv, "-group-by-16-bits"))
122	{
123	  group_by = 0x01;
124	  --argc; argv++;
125	}
126      else if (!strcmp (*argv, "-group-by-32-bits"))
127	{
128	  group_by = 0x03;
129	  --argc; argv++;
130	}
131      else if (!strcmp (*argv, "-group-by-64-bits"))
132	{
133	  group_by = 0x07;
134	  endian = 0;
135	  --argc; argv++;
136	}
137      else
138	{
139	  fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
140		   *argv);
141	  usage ();
142	}
143    }
144
145  do
146    {
147      if (*argv == NULL)
148	fp = stdin;
149      else
150	{
151	  char *filename = *argv++;
152
153	  if (!strcmp (filename, "-"))
154	    fp = stdin;
155	  else if ((fp = fopen (filename, "r")) == NULL)
156	    {
157	      perror (filename);
158	      continue;
159	    }
160	}
161
162      if (un_flag)
163	{
164	  char buf[18];
165
166#ifdef DOS_NT
167#if (__DJGPP__ >= 2) || (defined WINDOWSNT)
168          if (!isatty (fileno (stdout)))
169	    setmode (fileno (stdout), O_BINARY);
170#else
171	  (stdout)->_flag &= ~_IOTEXT; /* print binary */
172	  _setmode (fileno (stdout), O_BINARY);
173#endif
174#endif
175	  for (;;)
176	    {
177	      register int i, c = 0, d;
178
179#define hexchar(x) (isdigit (x) ? x - '0' : x - 'a' + 10)
180
181	      fread (buf, 1, 10, fp); /* skip 10 bytes */
182
183	      for (i=0; i < 16; ++i)
184		{
185		  if ((c = getc (fp)) == ' ' || c == EOF)
186		    break;
187
188		  d = getc (fp);
189		  c = hexchar (c) * 0x10 + hexchar (d);
190		  putchar (c);
191
192		  if ((i&group_by) == group_by)
193		    getc (fp);
194		}
195
196	      if (c == ' ')
197		{
198		  while ((c = getc (fp)) != '\n' && c != EOF)
199		    ;
200
201		  if (c == EOF)
202		    break;
203		}
204	      else
205		{
206		  if (i < 16)
207		    break;
208
209		  fread (buf, 1, 18, fp); /* skip 18 bytes */
210		}
211	    }
212	}
213      else
214	{
215#ifdef DOS_NT
216#if (__DJGPP__ >= 2) || (defined WINDOWSNT)
217          if (!isatty (fileno (fp)))
218	    setmode (fileno (fp), O_BINARY);
219#else
220	  (fp)->_flag &= ~_IOTEXT; /* read binary */
221	  _setmode (fileno (fp), O_BINARY);
222#endif
223#endif
224	  address = 0;
225	  string[0] = ' ';
226	  string[17] = '\0';
227	  for (;;)
228	    {
229	      register int i, c = 0;
230
231	      for (i=0; i < 16; ++i)
232		{
233		  if ((c = getc (fp)) == EOF)
234		    {
235		      if (!i)
236			break;
237
238		      fputs ("  ", stdout);
239		      string[i+1] = '\0';
240		    }
241		  else
242		    {
243		      if (!i)
244			printf ("%08lx: ", address);
245
246		      if (iso_flag)
247			string[i+1] =
248			  (c < 0x20 || (c >= 0x7F && c < 0xa0)) ? '.' :c;
249		      else
250			string[i+1] = (c < 0x20 || c >= 0x7F) ? '.' : c;
251
252		      printf ("%02x", c);
253		    }
254
255		  if ((i&group_by) == group_by)
256		    putchar (' ');
257		}
258
259	      if (i)
260		puts (string);
261
262	      if (c == EOF)
263		break;
264
265	      address += 0x10;
266
267	    }
268	}
269
270      if (fp != stdin)
271	fclose (fp);
272
273    } while (*argv != NULL);
274  return EXIT_SUCCESS;
275}
276
277void
278usage ()
279{
280  fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
281  exit (EXIT_FAILURE);
282}
283
284/* arch-tag: 20e04fb7-926e-4e48-be86-64fe869ecdaa
285   (do not change this comment) */
286
287/* hexl.c ends here */
288