aboutsummaryrefslogtreecommitdiffstats
path: root/lib-src/hexl.c
diff options
context:
space:
mode:
authorPaul Eggert2017-02-23 08:58:39 -0800
committerPaul Eggert2017-02-23 09:15:06 -0800
commit23e64facf9f74133c6bacedeec56ad782ae69b65 (patch)
tree19822ecfb5af4b2f867dd02a2a29319ade9fcb13 /lib-src/hexl.c
parent5114b3a2047a9bcdb72fddf35e70201c16eb39a3 (diff)
downloademacs-23e64facf9f74133c6bacedeec56ad782ae69b65.tar.gz
emacs-23e64facf9f74133c6bacedeec56ad782ae69b65.zip
hexl: handle large files and I/O errors
* lib-src/hexl.c: Include inttypes.h, for PRIxMAX etc. Do not include ctype.h, as the code no longer uses isdigit. (DEFAULT_GROUPING, un_flag, iso_flag, group_by): Now local to ‘main’. (DEFAULT_BASE, endian): Remove; was not really used. (usage): Remove; now done by ‘main’, as that’s simpler. (progname): Now static. (output_error, hexchar): New functions. (main): Use them. Simplify. Remove "-oct", "-big-endian", and "-little-endian" options, as they did not work and were not used. Use SET_BINARY only on stdin, and fopen with "rb" otherwise. Use SET_BINARY only once on stdout. Do not assume file offsets fit in ‘long’. If an I/O error occurs, report it and exit with nonzero status.
Diffstat (limited to 'lib-src/hexl.c')
-rw-r--r--lib-src/hexl.c230
1 files changed, 95 insertions, 135 deletions
diff --git a/lib-src/hexl.c b/lib-src/hexl.c
index 2eef7b3a63d..2c7e8c44161 100644
--- a/lib-src/hexl.c
+++ b/lib-src/hexl.c
@@ -21,241 +21,201 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 21
22#include <config.h> 22#include <config.h>
23 23
24#include <inttypes.h>
24#include <stdio.h> 25#include <stdio.h>
25#include <stdlib.h> 26#include <stdlib.h>
26#include <string.h> 27#include <string.h>
27#include <ctype.h>
28 28
29#include <binary-io.h> 29#include <binary-io.h>
30 30
31#define DEFAULT_GROUPING 0x01 31static char *progname;
32#define DEFAULT_BASE 16
33 32
34int base = DEFAULT_BASE; 33static _Noreturn void
35bool un_flag = false, iso_flag = false, endian = true; 34output_error (void)
36int group_by = DEFAULT_GROUPING; 35{
37char *progname; 36 fprintf (stderr, "%s: write error\n", progname);
37 exit (EXIT_FAILURE);
38}
38 39
39_Noreturn void usage (void); 40static int
41hexchar (int c)
42{
43 return c - ('0' <= c && c <= '9' ? '0' : 'a' - 10);
44}
40 45
41int 46int
42main (int argc, char **argv) 47main (int argc, char **argv)
43{ 48{
44 register long address; 49 int status = EXIT_SUCCESS;
45 char string[18]; 50 int DEFAULT_GROUPING = 0x01;
46 FILE *fp; 51 int group_by = DEFAULT_GROUPING;
47 52 bool un_flag = false, iso_flag = false;
48 progname = *argv++; --argc; 53 progname = *argv++;
49 54
50 /* 55 /*
51 ** -hex hex dump 56 ** -hex hex dump
52 ** -oct Octal dump
53 ** -group-by-8-bits 57 ** -group-by-8-bits
54 ** -group-by-16-bits 58 ** -group-by-16-bits
55 ** -group-by-32-bits 59 ** -group-by-32-bits
56 ** -group-by-64-bits 60 ** -group-by-64-bits
57 ** -iso iso character set. 61 ** -iso iso character set.
58 ** -big-endian Big Endian
59 ** -little-endian Little Endian
60 ** -un || -de from hexl format to binary. 62 ** -un || -de from hexl format to binary.
61 ** -- End switch list. 63 ** -- End switch list.
62 ** <filename> dump filename 64 ** <filename> dump filename
63 ** - (as filename == stdin) 65 ** - (as filename == stdin)
64 */ 66 */
65 67
66 while (*argv && *argv[0] == '-' && (*argv)[1]) 68 for (; *argv && *argv[0] == '-' && (*argv)[1]; argv++)
67 { 69 {
68 /* A switch! */ 70 /* A switch! */
69 if (!strcmp (*argv, "--")) 71 if (!strcmp (*argv, "--"))
70 { 72 {
71 --argc; argv++; 73 argv++;
72 break; 74 break;
73 } 75 }
74 else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de")) 76 else if (!strcmp (*argv, "-un") || !strcmp (*argv, "-de"))
75 { 77 {
76 un_flag = true; 78 un_flag = true;
77 --argc; argv++; 79 SET_BINARY (fileno (stdout));
78 } 80 }
79 else if (!strcmp (*argv, "-hex")) 81 else if (!strcmp (*argv, "-hex"))
80 { 82 /* Hex is the default and is only base supported. */;
81 base = 16;
82 --argc; argv++;
83 }
84 else if (!strcmp (*argv, "-iso")) 83 else if (!strcmp (*argv, "-iso"))
85 { 84 iso_flag = true;
86 iso_flag = true;
87 --argc; argv++;
88 }
89 else if (!strcmp (*argv, "-oct"))
90 {
91 base = 8;
92 --argc; argv++;
93 }
94 else if (!strcmp (*argv, "-big-endian"))
95 {
96 endian = true;
97 --argc; argv++;
98 }
99 else if (!strcmp (*argv, "-little-endian"))
100 {
101 endian = false;
102 --argc; argv++;
103 }
104 else if (!strcmp (*argv, "-group-by-8-bits")) 85 else if (!strcmp (*argv, "-group-by-8-bits"))
105 { 86 group_by = 0x00;
106 group_by = 0x00;
107 --argc; argv++;
108 }
109 else if (!strcmp (*argv, "-group-by-16-bits")) 87 else if (!strcmp (*argv, "-group-by-16-bits"))
110 { 88 group_by = 0x01;
111 group_by = 0x01;
112 --argc; argv++;
113 }
114 else if (!strcmp (*argv, "-group-by-32-bits")) 89 else if (!strcmp (*argv, "-group-by-32-bits"))
115 { 90 group_by = 0x03;
116 group_by = 0x03;
117 --argc; argv++;
118 }
119 else if (!strcmp (*argv, "-group-by-64-bits")) 91 else if (!strcmp (*argv, "-group-by-64-bits"))
120 { 92 group_by = 0x07;
121 group_by = 0x07;
122 endian = false;
123 --argc; argv++;
124 }
125 else 93 else
126 { 94 {
127 fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname, 95 fprintf (stderr, "%s: invalid switch: \"%s\".\n", progname,
128 *argv); 96 *argv);
129 usage (); 97 fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
98 return EXIT_FAILURE;
130 } 99 }
131 } 100 }
132 101
102 char const *filename = *argv ? *argv++ : "-";
103
133 do 104 do
134 { 105 {
135 if (*argv == NULL) 106 FILE *fp;
136 fp = stdin; 107
108 if (!strcmp (filename, "-"))
109 {
110 fp = stdin;
111 if (!un_flag)
112 SET_BINARY (fileno (stdin));
113 }
137 else 114 else
138 { 115 {
139 char *filename = *argv++; 116 fp = fopen (filename, un_flag ? "r" : "rb");
140 117 if (!fp)
141 if (!strcmp (filename, "-"))
142 fp = stdin;
143 else if ((fp = fopen (filename, "r")) == NULL)
144 { 118 {
145 perror (filename); 119 perror (filename);
120 status = EXIT_FAILURE;
146 continue; 121 continue;
147 } 122 }
148 } 123 }
149 124
150 if (un_flag) 125 if (un_flag)
151 { 126 {
152 SET_BINARY (fileno (stdout)); 127 for (int c; 0 <= (c = getc (fp)); )
153
154 for (;;)
155 { 128 {
156 int i, c = 0, d; 129 /* Skip address at start of line. */
157 char buf[18]; 130 if (c != ' ')
158 131 continue;
159#define hexchar(x) (isdigit (x) ? x - '0' : x - 'a' + 10)
160
161 /* Skip 10 bytes. */
162 if (fread (buf, 1, 10, fp) != 10)
163 break;
164 132
165 for (i=0; i < 16; ++i) 133 for (int i = 0; i < 16; i++)
166 { 134 {
167 if ((c = getc (fp)) == ' ' || c == EOF) 135 c = getc (fp);
136 if (c < 0 || c == ' ')
168 break; 137 break;
169 138
170 d = getc (fp); 139 int hc = hexchar (c);
171 c = hexchar (c) * 0x10 + hexchar (d); 140 c = getc (fp);
172 putchar (c); 141 if (c < 0)
173
174 if ((i&group_by) == group_by)
175 getc (fp);
176 }
177
178 if (c == ' ')
179 {
180 while ((c = getc (fp)) != '\n' && c != EOF)
181 ;
182
183 if (c == EOF)
184 break;
185 }
186 else
187 {
188 if (i < 16)
189 break; 142 break;
143 putchar (hc * 0x10 + hexchar (c));
190 144
191 /* Skip 18 bytes. */ 145 if ((i & group_by) == group_by)
192 if (fread (buf, 1, 18, fp) != 18) 146 {
193 break; 147 c = getc (fp);
148 if (c < 0)
149 break;
150 }
194 } 151 }
152
153 while (0 <= c && c != '\n')
154 c = getc (fp);
155 if (c < 0)
156 break;
157 if (ferror (stdout))
158 output_error ();
195 } 159 }
196 } 160 }
197 else 161 else
198 { 162 {
199 SET_BINARY (fileno (fp)); 163 int c = 0;
200 address = 0; 164 char string[18];
201 string[0] = ' '; 165 string[0] = ' ';
202 string[17] = '\0'; 166 string[17] = '\0';
203 for (;;) 167 for (uintmax_t address = 0; 0 <= c; address += 0x10)
204 { 168 {
205 register int i, c = 0; 169 int i;
206 170 for (i = 0; i < 16; i++)
207 for (i=0; i < 16; ++i)
208 { 171 {
209 if ((c = getc (fp)) == EOF) 172 if (0 <= c)
173 c = getc (fp);
174 if (c < 0)
210 { 175 {
211 if (!i) 176 if (!i)
212 break; 177 break;
213 178
214 fputs (" ", stdout); 179 fputs (" ", stdout);
215 string[i+1] = '\0'; 180 string[i + 1] = '\0';
216 } 181 }
217 else 182 else
218 { 183 {
219 if (!i) 184 if (!i)
220 printf ("%08lx: ", address + 0ul); 185 printf ("%08"PRIxMAX": ", address);
221 186
222 if (iso_flag) 187 string[i + 1]
223 string[i+1] = 188 = (c < 0x20 || (0x7F <= c && (!iso_flag || c < 0xa0))
224 (c < 0x20 || (c >= 0x7F && c < 0xa0)) ? '.' :c; 189 ? '.' : c);
225 else
226 string[i+1] = (c < 0x20 || c >= 0x7F) ? '.' : c;
227 190
228 printf ("%02x", c + 0u); 191 printf ("%02x", c + 0u);
229 } 192 }
230 193
231 if ((i&group_by) == group_by) 194 if ((i & group_by) == group_by)
232 putchar (' '); 195 putchar (' ');
233 } 196 }
234 197
235 if (i) 198 if (i)
236 puts (string); 199 puts (string);
237 200
238 if (c == EOF) 201 if (ferror (stdout))
239 break; 202 output_error ();
240
241 address += 0x10;
242
243 } 203 }
244 } 204 }
245 205
246 if (fp != stdin) 206 bool trouble = ferror (fp) != 0;
247 fclose (fp); 207 trouble |= fp != stdin && fclose (fp) != 0;
208 if (trouble)
209 {
210 fprintf (stderr, "%s: read error\n", progname);
211 status = EXIT_FAILURE;
212 }
248 213
249 } while (*argv != NULL); 214 filename = *argv++;
250 return EXIT_SUCCESS; 215 }
251} 216 while (filename);
252 217
253void 218 if (ferror (stdout) || fclose (stdout) != 0)
254usage (void) 219 output_error ();
255{ 220 return status;
256 fprintf (stderr, "usage: %s [-de] [-iso]\n", progname);
257 exit (EXIT_FAILURE);
258} 221}
259
260
261/* hexl.c ends here */