Introduction
Introduction Statistics Contact Development Disclaimer Help
od.c - sbase - suckless unix tools
git clone git://git.suckless.org/sbase
Log
Files
Refs
README
LICENSE
---
od.c (6365B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include <ctype.h>
3 #include <fcntl.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #include "queue.h"
11 #include "util.h"
12
13 struct type {
14 unsigned char format;
15 unsigned int len;
16 TAILQ_ENTRY(type) entry;
17 };
18
19 static TAILQ_HEAD(head, type) head = TAILQ_HEAD_INITIALIZER(head);
20 static unsigned char addr_format = 'o';
21 static off_t skip = 0;
22 static off_t max = -1;
23 static size_t linelen = 1;
24 static int big_endian;
25
26 static void
27 printaddress(off_t addr)
28 {
29 char fmt[] = "%07j#";
30
31 if (addr_format == 'n') {
32 fputc(' ', stdout);
33 } else {
34 fmt[4] = addr_format;
35 printf(fmt, (intmax_t)addr);
36 }
37 }
38
39 static void
40 printchunk(const unsigned char *s, unsigned char format, size_t len)
41 {
42 long long res, basefac;
43 size_t i;
44 char fmt[] = " %#*ll#";
45 unsigned char c;
46
47 const char *namedict[] = {
48 "nul", "soh", "stx", "etx", "eot", "enq", "ack",
49 "bel", "bs", "ht", "nl", "vt", "ff", "cr",
50 "so", "si", "dle", "dc1", "dc2", "dc3", "dc4",
51 "nak", "syn", "etb", "can", "em", "sub", "esc",
52 "fs", "gs", "rs", "us", "sp",
53 };
54 const char *escdict[] = {
55 ['\0'] = "\\0", ['\a'] = "\\a",
56 ['\b'] = "\\b", ['\t'] = "\\t",
57 ['\n'] = "\\n", ['\v'] = "\\v",
58 ['\f'] = "\\f", ['\r'] = "\\r",
59 };
60
61 switch (format) {
62 case 'a':
63 c = *s & ~128; /* clear high bit as required by standard…
64 if (c < LEN(namedict) || c == 127) {
65 printf(" %3s", (c == 127) ? "del" : namedict[c]);
66 } else {
67 printf(" %3c", c);
68 }
69 break;
70 case 'c':
71 if (strchr("\a\b\t\n\v\f\r\0", *s)) {
72 printf(" %3s", escdict[*s]);
73 } else if (!isprint(*s)) {
74 printf(" %3o", *s);
75 } else {
76 printf(" %3c", *s);
77 }
78 break;
79 default:
80 if (big_endian) {
81 for (res = 0, basefac = 1, i = len; i; i--) {
82 res += s[i - 1] * basefac;
83 basefac <<= 8;
84 }
85 } else {
86 for (res = 0, basefac = 1, i = 0; i < len; i++) {
87 res += s[i] * basefac;
88 basefac <<= 8;
89 }
90 }
91 fmt[2] = big_endian ? '-' : ' ';
92 fmt[6] = format;
93 printf(fmt, (int)(3 * len + len - 1), res);
94 }
95 }
96
97 static void
98 printline(const unsigned char *line, size_t len, off_t addr)
99 {
100 struct type *t = NULL;
101 size_t i;
102 int first = 1;
103 unsigned char *tmp;
104
105 if (TAILQ_EMPTY(&head))
106 goto once;
107 TAILQ_FOREACH(t, &head, entry) {
108 once:
109 if (first) {
110 printaddress(addr);
111 first = 0;
112 } else {
113 printf("%*c", (addr_format == 'n') ? 1 : 7, ' ');
114 }
115 for (i = 0; i < len; i += MIN(len - i, t ? t->len : 4)) {
116 if (len - i < (t ? t->len : 4)) {
117 tmp = ecalloc(t ? t->len : 4, 1);
118 memcpy(tmp, line + i, len - i);
119 printchunk(tmp, t ? t->format : 'o',
120 t ? t->len : 4);
121 free(tmp);
122 } else {
123 printchunk(line + i, t ? t->format : 'o',
124 t ? t->len : 4);
125 }
126 }
127 fputc('\n', stdout);
128 if (TAILQ_EMPTY(&head) || (!len && !first))
129 break;
130 }
131 }
132
133 static int
134 od(int fd, char *fname, int last)
135 {
136 static unsigned char *line;
137 static size_t lineoff;
138 static off_t addr;
139 unsigned char buf[BUFSIZ];
140 size_t i, size = sizeof(buf);
141 ssize_t n;
142
143 while (skip - addr > 0) {
144 n = read(fd, buf, MIN(skip - addr, sizeof(buf)));
145 if (n < 0)
146 weprintf("read %s:", fname);
147 if (n <= 0)
148 return n;
149 addr += n;
150 }
151 if (!line)
152 line = emalloc(linelen);
153
154 for (;;) {
155 if (max >= 0)
156 size = MIN(max - (addr - skip), size);
157 if ((n = read(fd, buf, size)) <= 0)
158 break;
159 for (i = 0; i < n; i++, addr++) {
160 line[lineoff++] = buf[i];
161 if (lineoff == linelen) {
162 printline(line, lineoff, addr - lineoff …
163 lineoff = 0;
164 }
165 }
166 }
167 if (n < 0) {
168 weprintf("read %s:", fname);
169 return n;
170 }
171 if (lineoff && last)
172 printline(line, lineoff, addr - lineoff);
173 if (last)
174 printline((unsigned char *)"", 0, addr);
175 return 0;
176 }
177
178 static int
179 lcm(unsigned int a, unsigned int b)
180 {
181 unsigned int c, d, e;
182
183 for (c = a, d = b; c ;) {
184 e = c;
185 c = d % c;
186 d = e;
187 }
188
189 return a / d * b;
190 }
191
192 static void
193 addtype(char format, int len)
194 {
195 struct type *t;
196
197 t = emalloc(sizeof(*t));
198 t->format = format;
199 t->len = len;
200 TAILQ_INSERT_TAIL(&head, t, entry);
201 }
202
203 static void
204 usage(void)
205 {
206 eprintf("usage: %s [-bdosvx] [-A addressformat] [-E | -e] [-j sk…
207 "[-t outputformat] [file ...]\n", argv0);
208 }
209
210 int
211 main(int argc, char *argv[])
212 {
213 int fd;
214 struct type *t;
215 int ret = 0, len;
216 char *s;
217
218 big_endian = (*(uint16_t *)"\0\xff" == 0xff);
219
220 ARGBEGIN {
221 case 'A':
222 s = EARGF(usage());
223 if (strlen(s) != 1 || !strchr("doxn", s[0]))
224 usage();
225 addr_format = s[0];
226 break;
227 case 'b':
228 addtype('o', 1);
229 break;
230 case 'd':
231 addtype('u', 2);
232 break;
233 case 'E':
234 case 'e':
235 big_endian = (ARGC() == 'E');
236 break;
237 case 'j':
238 if ((skip = parseoffset(EARGF(usage()))) < 0)
239 usage();
240 break;
241 case 'N':
242 if ((max = parseoffset(EARGF(usage()))) < 0)
243 usage();
244 break;
245 case 'o':
246 addtype('o', 2);
247 break;
248 case 's':
249 addtype('d', 2);
250 break;
251 case 't':
252 s = EARGF(usage());
253 for (; *s; s++) {
254 switch (*s) {
255 case 'a':
256 case 'c':
257 addtype(*s, 1);
258 break;
259 case 'd':
260 case 'o':
261 case 'u':
262 case 'x':
263 /* todo: allow multiple digits */
264 if (*(s+1) > '0' && *(s+1) <= '9') {
265 len = *(s+1) - '0';
266 } else {
267 switch (*(s+1)) {
268 case 'C':
269 len = sizeof(char);
270 break;
271 case 'S':
272 len = sizeof(short);
273 break;
274 case 'I':
275 len = sizeof(int);
276 break;
277 case 'L':
278 len = sizeof(long);
279 break;
280 default:
281 len = sizeof(int);
282 }
283 }
284 addtype(*s++, len);
285 break;
286 default:
287 usage();
288 }
289 }
290 break;
291 case 'v':
292 /* always set - use uniq(1) to handle duplicate lines */
293 break;
294 case 'x':
295 addtype('x', 2);
296 break;
297 default:
298 usage();
299 } ARGEND
300
301 /* line length is lcm of type lengths and >= 16 by doubling */
302 TAILQ_FOREACH(t, &head, entry)
303 linelen = lcm(linelen, t->len);
304 if (TAILQ_EMPTY(&head))
305 linelen = 16;
306 while (linelen < 16)
307 linelen *= 2;
308
309 if (!argc) {
310 if (od(0, "<stdin>", 1) < 0)
311 ret = 1;
312 } else {
313 for (; *argv; argc--, argv++) {
314 if (!strcmp(*argv, "-")) {
315 *argv = "<stdin>";
316 fd = 0;
317 } else if ((fd = open(*argv, O_RDONLY)) < 0) {
318 weprintf("open %s:", *argv);
319 ret = 1;
320 continue;
321 }
322 if (od(fd, *argv, (!*(argv + 1))) < 0)
323 ret = 1;
324 if (fd != 0)
325 close(fd);
326 }
327 }
328
329 ret |= fshut(stdout, "<stdout>") | fshut(stderr, "<stderr>");
330
331 return ret;
332 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.