1 /*
2  * Copyright (c) 2019,2020 Linaro Limited
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <ctype.h>
8 #include <stdio.h>
9 #include "util_sformat.h"
10 
sf_hex_ascii(unsigned char * data,size_t len,unsigned char nonvis)11 static void sf_hex_ascii(unsigned char *data, size_t len, unsigned char nonvis)
12 {
13 	uint32_t idx;
14 
15 	/* Render printable characters. */
16 	idx = 0;
17 	while (len) {
18 		printf("%c", isprint(data[idx]) ? data[idx] : nonvis);
19 		idx++;
20 		len--;
21 	}
22 }
23 
sf_hex_tabulate_16(struct sf_hex_tbl_fmt * fmt,unsigned char * data,size_t len)24 void sf_hex_tabulate_16(struct sf_hex_tbl_fmt *fmt, unsigned char *data,
25 			size_t len)
26 {
27 	uint32_t idx;
28 	uint32_t cpos;     /* Current position. */
29 	uint32_t ca;       /* Current address. */
30 	uint32_t ea;       /* End address. */
31 
32 	if (!len) {
33 		return;
34 	}
35 
36 	/* Set the end address (since we modify len in the write loop). */
37 	ea = fmt->addr + len;
38 
39 	/* Check if we need to render the top address bar. */
40 	if (fmt->addr_label) {
41 		/* Render the top address bar. */
42 		printf("\n");
43 		printf("          ");
44 		printf("0  1  2  3  4  5  6  7  8  9  ");
45 		printf("A  B  C  D  E  F\n");
46 		printf("%08X ", fmt->addr - (fmt->addr % 16));
47 	}
48 
49 	/* Insert offset padding for first row if necessary. */
50 	cpos = fmt->addr % 16;
51 	if (cpos != 0) {
52 		for (idx = 0; idx < cpos; idx++) {
53 			printf("   ");
54 		}
55 	}
56 
57 	/* Print data row by row. */
58 	idx = 0;
59 	ca = fmt->addr;
60 	while (len) {
61 		/* Print the current value. */
62 		printf("%02X ", data[idx++]);
63 		cpos++;
64 		ca++;
65 
66 		/* Wrap around to the next line if necessary. */
67 		if (cpos == 16 || ca == ea) {
68 			/* Render ASCII equiv at end of row if requested. */
69 			if (fmt->ascii) {
70 				if (ca == ea) {
71 					/* Handle last/single row. */
72 					if (ca % 16) {
73 						/* PARTIAL row (< 16 vals). */
74 						printf("%.*s",
75 						       (16 - ca % 16) * 3,
76 						       "                "
77 						       "                "
78 						       "                ");
79 						sf_hex_ascii(
80 							&data[idx - (ca % 16)],
81 							ca - fmt->addr < 16 ?
82 							idx % 16 : ca % 16,
83 							'.');
84 					} else {
85 						/* FULL row. */
86 						sf_hex_ascii(
87 							&data[idx - 16],
88 							16, '.');
89 					}
90 				} else if (ca < fmt->addr + 15) {
91 					/* Handle first row. */
92 					printf("%.*s", fmt->addr % 16,
93 					       "                ");
94 					sf_hex_ascii(data,
95 						     16 - fmt->addr % 16, '.');
96 				} else {
97 					/* Full row. */
98 					sf_hex_ascii(&data[idx - 16], 16, '.');
99 				}
100 			}
101 
102 			/* Wrap around if this isn't the last row. */
103 			printf("\n");
104 			if (ca != ea) {
105 				/* Render the next base row addr. */
106 				if (fmt->addr_label) {
107 					printf("%08X ", ca);
108 				}
109 			}
110 			cpos = 0;
111 		}
112 		len--;
113 	}
114 	printf("\n");
115 }
116