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