Merge branch 'lisp-func-type-decls' into 'master'
[emacs.git] / lib-src / hexl.c
blob4b67633e743125d30f77a0e9015801d09d6f860d
1 /* Convert files for Emacs Hexl mode.
2 Copyright (C) 1989, 2001-2024 Free Software Foundation, Inc.
4 Author: Keith Gabryelski (according to authors.el)
6 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 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <https://www.gnu.org/licenses/>. */
22 #include <config.h>
24 #include <inttypes.h>
25 #include <stdlib.h>
26 #include <string.h>
28 #include <binary-io.h>
29 #include <unlocked-io.h>
31 static char *progname;
33 static _Noreturn void
34 output_error (void)
36 fprintf (stderr, "%s: write error\n", progname);
37 exit (EXIT_FAILURE);
40 static int
41 hexchar (int c)
43 return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
46 int
47 main (int argc, char **argv)
49 int status = EXIT_SUCCESS;
50 int DEFAULT_GROUPING = 0x01;
51 int group_by = DEFAULT_GROUPING;
52 bool un_flag = false, iso_flag = false;
53 progname = *argv++;
56 ** -hex hex dump
57 ** -group-by-8-bits
58 ** -group-by-16-bits
59 ** -group-by-32-bits
60 ** -group-by-64-bits
61 ** -iso iso character set.
62 ** -un || -de from hexl format to binary.
63 ** -- End switch list.
64 ** <filename> dump filename
65 ** - (as filename == stdin)
68 for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
70 /* A switch! */
71 if (!strcmp (*argv, "--"))
73 argv++;
74 break;
76 else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
78 un_flag = true;
79 set_binary_mode (fileno (stdout), O_BINARY);
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
95 fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
96 *argv);
97 fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
98 return EXIT_FAILURE;
102 char const *filename = *argv ? *argv++ : "-";
106 FILE *fp;
108 if (!strcmp (filename, "-"))
110 fp = stdin;
111 if (!un_flag)
112 set_binary_mode (fileno (stdin), O_BINARY);
114 else
116 fp = fopen (filename, un_flag ? "r" : "rb");
117 if (!fp)
119 perror (filename);
120 status = EXIT_FAILURE;
121 continue;
125 if (un_flag)
127 for (int c; 0 <= (c = getc (fp)); )
129 /* Skip address at start of line. */
130 if (c != ' ')
131 continue;
133 for (int i = 0; i < 16; i++)
135 c = getc (fp);
136 if (c < 0 || c == ' ')
137 break;
139 int hc = hexchar (c);
140 c = getc (fp);
141 if (c < 0)
142 break;
143 putchar (hc * 0x10 + hexchar (c));
145 if ((i & group_by) == group_by)
147 c = getc (fp);
148 if (c < 0)
149 break;
153 while (0 <= c && c != '\n')
154 c = getc (fp);
155 if (c < 0)
156 break;
157 if (ferror (stdout))
158 output_error ();
161 else
163 int c = 0;
164 char string[18];
165 string[0] = ' ';
166 string[17] = '\0';
167 for (uintmax_t address = 0; 0 <= c; address += 0x10)
169 int i;
170 for (i = 0; i < 16; i++)
172 if (0 <= c)
173 c = getc (fp);
174 if (c < 0)
176 if (!i)
177 break;
179 fputs (" ", stdout);
180 string[i + 1] = '\0';
182 else
184 if (!i)
185 printf ("%08"PRIxMAX": ", address);
187 string[i + 1]
188 = (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
189 ? '.' : c);
191 printf ("%02x", c + 0u);
194 if ((i & group_by) == group_by)
195 putchar (' ');
198 if (i)
199 puts (string);
201 if (ferror (stdout))
202 output_error ();
206 bool trouble = ferror (fp) != 0;
207 trouble |= fp != stdin && fclose (fp) != 0;
208 if (trouble)
210 fprintf (stderr, "%s: read error\n", progname);
211 status = EXIT_FAILURE;
214 filename = *argv++;
216 while (filename);
218 if (ferror (stdout) || fclose (stdout) != 0)
219 output_error ();
220 return status;