1 #include <stdio.h>
2 #include <dirent.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/stat.h>
7 #include <stdbool.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <stdint.h>
11 #include <aos/cli.h>
12 #include <path_helper.h>
13
14 #ifndef MIN
15 #define MIN(a, b) (a > b ? b : a)
16 #endif
17
18 #define HEXDUMP_LINE_CHR_CNT 16
19
20 struct hd_struct {
21 const char *buf;
22 int bytes;
23 int baseaddr;
24 char same_chr;
25 #define FLAGS_SAME_CHR (1 << 0)
26 #define FLAGS_DUMP_CHR (1 << 1)
27 #define FLAGS_PRINT_STAR (1 << 2)
28 int flags;
29 };
30
is_same_char(const unsigned char * buf,int len,unsigned char chr)31 static bool is_same_char(const unsigned char *buf, int len, unsigned char chr)
32 {
33 for (len -= 1; len; len--) {
34 if (buf[len] != chr)
35 return false;
36 }
37 return true;
38 }
39
multi_hexdump(struct hd_struct * hd)40 static int multi_hexdump(struct hd_struct *hd)
41 {
42 unsigned char line[HEXDUMP_LINE_CHR_CNT] = {0};
43 int addr = 0;
44
45 for (addr = 0; addr < hd->bytes; addr += HEXDUMP_LINE_CHR_CNT) {
46 int len = MIN(hd->bytes - addr, HEXDUMP_LINE_CHR_CNT), i;
47 memcpy(line, hd->buf + addr, len);
48 memset(line + len, 0, HEXDUMP_LINE_CHR_CNT - len);
49
50 if (is_same_char(line, HEXDUMP_LINE_CHR_CNT, line[0])) {
51 if (hd->flags & FLAGS_SAME_CHR) {
52 if (is_same_char(line, HEXDUMP_LINE_CHR_CNT, hd->same_chr)) {
53 if (!(hd->flags & FLAGS_PRINT_STAR)) {
54 hd->flags |= FLAGS_PRINT_STAR;
55 aos_cli_printf("*\n");
56 }
57 continue;
58 } else {
59 hd->flags &= ~(FLAGS_SAME_CHR | FLAGS_PRINT_STAR);
60 }
61 } else {
62 hd->same_chr = line[0];
63 hd->flags |= FLAGS_SAME_CHR;
64 }
65 } else {
66 hd->flags &= ~(FLAGS_SAME_CHR | FLAGS_PRINT_STAR);
67 }
68
69 /* print addr */
70 aos_cli_printf("0x%.8X: ", addr + hd->baseaddr);
71 /* print hex */
72 for (i = 0; i < HEXDUMP_LINE_CHR_CNT; i++) {
73 if (i < len)
74 aos_cli_printf("%.2X ", line[i]);
75 else
76 aos_cli_printf(" ");
77 }
78
79 /* print char */
80 if (!(hd->flags & FLAGS_DUMP_CHR)) {
81 aos_cli_printf("\n");
82 continue;
83 }
84 aos_cli_printf("|");
85 for (i = 0; i < HEXDUMP_LINE_CHR_CNT; i++) {
86 if (i < len) {
87 if (line[i] >= 0x20 && line[i] <= 0x7E)
88 aos_cli_printf("%c", line[i]);
89 else
90 aos_cli_printf(".");
91 } else {
92 aos_cli_printf(" ");
93 }
94 }
95 aos_cli_printf("|\n");
96 }
97 hd->baseaddr += addr;
98 return 0;
99 }
100
hexdump_do(const char * file,int len,int skip,int chr)101 static int hexdump_do(const char *file, int len, int skip, int chr)
102 {
103 int ret = 0, fd = 0;
104 char buf[128];
105 struct hd_struct hd = {0};
106 char abspath[256] = {0}, *file1;
107
108 file1 = get_realpath(file, abspath, sizeof(abspath));
109 if (!file1) {
110 aos_cli_printf("Failed to get real path!\r\n");
111 return -1;
112 }
113
114 fd = open(file1, O_RDONLY);
115 if (fd < 0) {
116 aos_cli_printf("open %s failed - %s\n", file, strerror(errno));
117 return -1;
118 }
119
120 if (skip) {
121 ret = lseek(fd, skip, SEEK_SET);
122 if (ret < 0) {
123 aos_cli_printf("lseek %s failed - %s\n", file, strerror(errno));
124 goto close;
125 }
126 }
127
128 if (chr)
129 hd.flags |= FLAGS_DUMP_CHR;
130
131 len = len ? len : INT32_MAX;
132 while (len > 0 && (ret = read(fd, buf, MIN(128, len)))) {
133
134 if (ret < 0) {
135 aos_cli_printf("read %s failed - %s\n", file, strerror(errno));
136 goto close;
137 }
138
139 hd.buf = buf;
140 hd.bytes = ret;
141 multi_hexdump(&hd);
142 len -= ret;
143 }
144
145 close:
146 close(fd);
147 return 0;
148 }
149
show_help(void)150 static int show_help(void)
151 {
152 aos_cli_printf("usage:\r\n"
153 " hexdump [-C] [-n length] [-s skip] file\r\n"
154 "options:\r\n"
155 " -C show ASCII and hexadecimal\r\n"
156 " -n length set file length(Byte) for hexadecimal conversion\r\n"
157 " -s skip set start position(Byte) for hexadecimal conversion\r\n");
158 return 0;
159 }
160
hexdump_main(int argc,char ** argv)161 static int hexdump_main(int argc, char **argv)
162 {
163 int opts = 0, len = 0, skip = 0, chr = 0;
164
165 optind = 0;
166 while ((opts = getopt(argc, argv, ":n:hs:C")) != EOF) {
167 switch (opts) {
168 case 'n':
169 len = atoi(optarg);
170 break;
171 case 's':
172 skip = atoi(optarg);
173 break;
174 case 'C':
175 chr = true;
176 break;
177 case 'h':
178 show_help();
179 return 0;
180 case '?':
181 aos_cli_printf("invalid option %c\n", optopt);
182 return -1;
183 case ':':
184 aos_cli_printf("option -%c requires an argument\n", optopt);
185 show_help();
186 return -1;
187 }
188 }
189
190 argc -= optind;
191 argv += optind;
192
193 for (opts = 0; opts < argc; opts++)
194 hexdump_do(argv[opts], len, skip, chr);
195
196 return 0;
197 }
198 ALIOS_CLI_CMD_REGISTER(hexdump_main, hexdump, dump binary data in decimal);
199
hd_main(int argc,char ** argv)200 static int hd_main(int argc, char **argv)
201 {
202 char *_argv[128 + 1] = {0};
203 int i = 0;
204
205 argc = MIN(argc, 128);
206 _argv[i++] = "hexdump";
207 _argv[i++] = "-C";
208 for (; i < argc + 1; i++)
209 _argv[i] = argv[i - 1];
210 return hexdump_main(argc + 1, _argv);
211 }
212 ALIOS_CLI_CMD_REGISTER(hd_main, hd, the same as 'hexdump -C');
213