print command
[hexdump.git] / hexdump.c
CommitLineData
a1ab98f9
LM
1/* depend: */
2/* cflags: */
3/* linker: debug.o */
4
5#include <assert.h>
6#include <getopt.h>
7#include <malloc.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include "debug.h"
13
14/* macros */
15
16#define CEIL(x, y) (((x) + (y) - 1) / (y))
17#define MIN(x, y) (((x) < (y)) ? (x) : (y))
18#define MAX(x, y) (((x) > (y)) ? (x) : (y))
19
20//#define BUFFERSIZE 4096
21#define BUFFERSIZE 256
22#define NBCOLS 8
23
24/* gobal variables */
25
26char *progname = NULL;
27
28/* help function */
29
30void usage (int ret)
31{
32 FILE *fd = ret ? stderr : stdout;
33 fprintf (fd, "usage: %s [-i file] [-h] [-n nbcols] [-o file] [-v]\n", progname);
5272fae8
LM
34 fprintf (fd, " -i: input file\n");
35 fprintf (fd, " -h: help message\n");
36 fprintf (fd, " -n: number of columns\n");
37 fprintf (fd, " -e: commands\n");
38 fprintf (fd, " -o: output file\n");
39 fprintf (fd, " -v: verbose level (%d)\n", verbose);
40 fprintf (fd, "\n");
41 fprintf (fd, "commands: [/hstr/|0xaddr] [a hstr] [d nb|-] [i hstr] [p nb|-] [s/h1/h2/[g]]\n");
42 fprintf (fd, " 0x: move to address addr\n");
43 fprintf (fd, " //: move to hexa stringi hstr\n");
44 fprintf (fd, " a : append hexa string hstr to current address\n");
45 fprintf (fd, " d : delete nb bytes (- until end file)\n");
46 fprintf (fd, " i : insert hexa string hstr to current address\n");
47 fprintf (fd, " p : print nb bytes (- until end file)\n");
48 fprintf (fd, " s : substitute h1 by h2 (g for globally)\n");
a1ab98f9
LM
49
50 exit (ret);
51}
52
53/* get number of digits */
54
55int getnbdigits (long int l) {
56 int n = 0;
57 while (l) {
58 n += 2;
59 l /= 256;
60 }
61 return n;
62}
63
64/* print a line */
65
66void printline (char *buffer, int nbcols, int nb, int addr, int nbdigits) {
67 int i;
68
69 printf ("0x%0*x:", nbdigits, addr);
70 for (i = 0; i < nb; i++) {
71 printf (" %02x", buffer[i]);
72 }
73 for (i = nb; i < nbcols; i++) {
74 printf (" ");
75 }
76 printf (" ");
77 for (i = 0; i < nb; i++) {
78 char c = buffer[i];
79 printf ("%c", (c > 31) && (c < 127) ? c : '.');
80 }
81 printf ("\n");
82}
83
84/* indent function */
85
5272fae8 86int hexdump (FILE *fin, int nbcols, int len) {
a1ab98f9
LM
87 char buffer[BUFFERSIZE] = {0};
88 int i;
89
90 char *pt = buffer;
91
92 /* get file size */
93 int nbdigits = 0;
94 if (fin != stdin) {
95 fseek (fin, 0 , SEEK_END);
96 long int filesize = ftell (fin);
97 fseek (fin, 0 , SEEK_SET);
98 nbdigits = getnbdigits (filesize);
99 } else {
100 nbdigits = 6;
101 }
102
103 int addr = 0;
104 int nb = 0;
105 while (!feof (fin)) {
5272fae8
LM
106 int nbtoread = BUFFERSIZE - (pt - buffer);
107 if ((len > 0) && (nbtoread > len)) {
108 nbtoread = len;
109 }
110 int nbread = fread (pt, 1, nbtoread, fin);
111 if (len > 0) {
112 len -= nbread;
113 }
114 nb += nbread;
a1ab98f9
LM
115 pt = buffer;
116
117 /* print line */
118 while ((nb - (int)(pt - buffer)) / nbcols > 0) {
119 printline (pt, nbcols, nbcols, addr, nbdigits);
120 pt += nbcols;
121 addr += nbcols;
122 }
123
124 /* copy end buffer */
125 nb -= pt - buffer;
126 for (i = 0; i < nb; i++) {
127 buffer[i] = pt[i];
128 }
129 pt = buffer + nb;
5272fae8
LM
130
131 /* end partial reading */
132 if (len == 0) {
133 break;
134 }
a1ab98f9
LM
135 }
136
137 /* last line */
138 if (nb > 0) {
139 printline (buffer, nbcols, nb, addr, nbdigits);
140 }
141
142 return 0;
143}
144
145/* main function */
146
147int main (int argc, char *argv[])
148{
5272fae8 149 int rc = 0;
a1ab98f9
LM
150 char *input = NULL;
151 char *output = NULL;
152 int nbcols = NBCOLS;
5272fae8
LM
153 char *commands = NULL;
154 int printlen = -1;
a1ab98f9
LM
155
156 /* get basename */
157 char *pt = progname = argv[0];
158 while (*pt) {
159 if ((*pt == '/') || (*pt == '\\')) {
160 progname = pt + 1;
161 }
162 pt++;
163 }
164
165 int c;
5272fae8 166 while ((c = getopt(argc, argv, "e:i:hn:o:v:")) != EOF) {
a1ab98f9
LM
167 switch (c) {
168 case 'i':
169 input = optarg;
170 break;
5272fae8
LM
171 case 'e':
172 if (commands == NULL) {
173 commands = optarg;
174 } else {
175 strcat (commands, " ");
176 strcat (commands, optarg);
177 }
178 break;
a1ab98f9
LM
179 case 'n':
180 nbcols = atoi (optarg);
181 break;
182 case 'o':
183 output = optarg;
184 break;
185 case 'v':
186 verbose = atoi (optarg);
187 break;
188 case 'h':
189 default:
190 usage (c != 'h');
191 }
192 }
193 if (argc - optind != 0) {
194 fprintf (stderr, "%s: invalid option -- %s\n", progname, argv[optind]);
195 usage (1);
196 }
197
198 /* check input */
199 FILE *fin = NULL;
200 if (input) {
201 fin = fopen (input, "rb");
202 if (!fin) {
203 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", input));
5272fae8 204 return 1;
a1ab98f9
LM
205 }
206 } else {
207 fin = stdin;
208 }
209
210 /* check output */
211 FILE *fout = NULL;
212 if (output) {
213 fout = fopen (input, "wb");
214 if (!fout) {
215 VERBOSE (ERROR, fprintf (stderr, "error: can't open file '%s'\n", output));
216 fclose (fin);
5272fae8 217 return 1;
a1ab98f9
LM
218 }
219 } else {
220 fout = stdout;
221 }
222
5272fae8
LM
223 if (commands == NULL) {
224 hexdump (fin, nbcols, -1);
225 } else {
226 VERBOSE (DEBUG, printf ("commands: %s\n", commands));
227 while ((*commands != '\0') && (rc == 0)) {
228 switch (*commands++) {
229 case ' ':
230 case '\t':
231 break;
232
233 case '/': /* read patern */
234 break;
235
236 case '0': /* read address */
237 break;
238
239 case 'a': /* append mode */
240 break;
241
242 case 'd': /* delete mode */
243 break;
244
245 case 'i': /* insert mode */
246 break;
247
248 case 'p': /* print mode */
249 printlen = -1;
250 while (*commands != '\0') {
251 if ((*commands == ' ') || (*commands == '\t')) {
252 commands++;
253 } else if ((*commands >= '0') && (*commands <= '9')) {
254 printlen = strtol (commands, &commands, 10);
255 break;
256 } else if (*commands == '-') {
257 printlen = -1;
258 commands++;
259 break;
260 } else {
261 VERBOSE (ERROR, fprintf (stderr, "unkown print lenght (%s)\n", commands));
262 rc = 1;
263 break;
264 }
265 }
266 if (rc == 0) hexdump (fin, nbcols, printlen);
267 break;
268
269 case 's': /* substitute mode */
270 break;
271
272 default:
273 VERBOSE (ERROR, fprintf (stderr, "unknown command (%c)\n", commands[-1]));
274 rc = 1;
275 }
276 }
277 }
a1ab98f9
LM
278
279 /* close all */
5272fae8
LM
280 if (fin) fclose (fin);
281 if (fout) fclose (fout);
a1ab98f9 282
5272fae8 283 return rc;
a1ab98f9
LM
284}
285
286// test: hexdump.exe -h
287// test: hexdump.exe -h | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
288// test: hexdump.exe -_ 2> /dev/null | awk 'END { if (NR == 0) { exit(0) } else exit (1) }'
289// test: hexdump.exe -_ 2>&1 | awk '/usage:/ { rc=1 } END { exit (1-rc) }'
290// test: hexdump.exe -i hexdump.c | grep -q '0x[0-9a-f]*: '
291// test: hexdump.exe -i hexdump.c -n 3|head -2|tail -1| grep '0x0003: 64 65 70 dep'
292
293/* vim: set ts=4 sw=4 et: */