aboutsummaryrefslogtreecommitdiff
path: root/libbb/dump.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/dump.c')
-rw-r--r--libbb/dump.c171
1 files changed, 85 insertions, 86 deletions
diff --git a/libbb/dump.c b/libbb/dump.c
index 154be5d80..87c1dce13 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -14,12 +14,12 @@
14#include "libbb.h" 14#include "libbb.h"
15#include "dump.h" 15#include "dump.h"
16 16
17static const char index_str[] ALIGN1 = ".#-+ 0123456789"; 17static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
18 18
19static const char size_conv_str[] ALIGN1 = 19static const char size_conv_str[] ALIGN1 =
20"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG"; 20"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
21 21
22static const char lcc[] ALIGN1 = "diouxX"; 22static const char int_convs[] ALIGN1 = "diouxX";
23 23
24 24
25typedef struct priv_dumper_t { 25typedef struct priv_dumper_t {
@@ -71,7 +71,7 @@ static NOINLINE int bb_dump_size(FS *fs)
71 * skip any special chars -- save precision in 71 * skip any special chars -- save precision in
72 * case it's a %s format. 72 * case it's a %s format.
73 */ 73 */
74 while (strchr(index_str + 1, *++fmt)) 74 while (strchr(dot_flags_width_chars + 1, *++fmt))
75 continue; 75 continue;
76 if (*fmt == '.' && isdigit(*++fmt)) { 76 if (*fmt == '.' && isdigit(*++fmt)) {
77 prec = atoi(fmt); 77 prec = atoi(fmt);
@@ -82,14 +82,15 @@ static NOINLINE int bb_dump_size(FS *fs)
82 if (!p) { 82 if (!p) {
83 if (*fmt == 's') { 83 if (*fmt == 's') {
84 bcnt += prec; 84 bcnt += prec;
85 } else if (*fmt == '_') { 85 }
86 if (*fmt == '_') {
86 ++fmt; 87 ++fmt;
87 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) { 88 if ((*fmt == 'c') || (*fmt == 'p') || (*fmt == 'u')) {
88 bcnt += 1; 89 bcnt += 1;
89 } 90 }
90 } 91 }
91 } else { 92 } else {
92 bcnt += size_conv_str[p - (size_conv_str + 12)]; 93 bcnt += p[-12];
93 } 94 }
94 } 95 }
95 cur_size += bcnt * fu->reps; 96 cur_size += bcnt * fu->reps;
@@ -99,32 +100,30 @@ static NOINLINE int bb_dump_size(FS *fs)
99 100
100static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) 101static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
101{ 102{
102 enum { NOTOKAY, USEBCNT, USEPREC } sokay;
103 FU *fu; 103 FU *fu;
104 PR *pr;
105 char *p1, *p2, *p3;
106 char savech, *fmtp;
107 const char *byte_count_str;
108 int nconv, prec = 0;
109 104
110 for (fu = fs->nextfu; fu; fu = fu->nextfu) { 105 for (fu = fs->nextfu; fu; fu = fu->nextfu) {
106 PR *pr;
107 char *p1, *p2, *p3;
108 char *fmtp;
109 int nconv = 0;
111 /* 110 /*
112 * break each format unit into print units; each 111 * break each format unit into print units; each
113 * conversion character gets its own. 112 * conversion character gets its own.
114 */ 113 */
115 for (nconv = 0, fmtp = fu->fmt; *fmtp; ) { 114 for (fmtp = fu->fmt; *fmtp; ) {
116 /* NOSTRICT */ 115 unsigned len;
117 /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/ 116 const char *prec;
118 pr = xzalloc(sizeof(PR)); 117 const char *byte_count_str;
118
119 /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL */
120 pr = xzalloc(sizeof(*pr));
119 if (!fu->nextpr) 121 if (!fu->nextpr)
120 fu->nextpr = pr; 122 fu->nextpr = pr;
121 123
122 /* skip preceding text and up to the next % sign */ 124 /* skip preceding text and up to the next % sign */
123 for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) 125 p1 = strchr(fmtp, '%');
124 continue; 126 if (!p1) { /* only text in the string */
125
126 /* only text in the string */
127 if (!*p1) {
128 pr->fmt = fmtp; 127 pr->fmt = fmtp;
129 pr->flags = F_TEXT; 128 pr->flags = F_TEXT;
130 break; 129 break;
@@ -134,22 +133,20 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
134 * get precision for %s -- if have a byte count, don't 133 * get precision for %s -- if have a byte count, don't
135 * need it. 134 * need it.
136 */ 135 */
136 prec = NULL;
137 if (fu->bcnt) { 137 if (fu->bcnt) {
138 sokay = USEBCNT;
139 /* skip to conversion character */ 138 /* skip to conversion character */
140 for (++p1; strchr(index_str, *p1); ++p1) 139 while (strchr(dot_flags_width_chars, *++p1))
141 continue; 140 continue;
142 } else { 141 } else {
143 /* skip any special chars, field width */ 142 /* skip any special chars, field width */
144 while (strchr(index_str + 1, *++p1)) 143 while (strchr(dot_flags_width_chars + 1, *++p1))
145 continue; 144 continue;
146 if (*p1 == '.' && isdigit(*++p1)) { 145 if (*p1 == '.' && isdigit(*++p1)) {
147 sokay = USEPREC; 146 prec = p1;
148 prec = atoi(p1);
149 while (isdigit(*++p1)) 147 while (isdigit(*++p1))
150 continue; 148 continue;
151 } else 149 }
152 sokay = NOTOKAY;
153 } 150 }
154 151
155 p2 = p1 + 1; /* set end pointer */ 152 p2 = p1 + 1; /* set end pointer */
@@ -165,74 +162,72 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
165 byte_count_str = "\001"; 162 byte_count_str = "\001";
166 DO_BYTE_COUNT: 163 DO_BYTE_COUNT:
167 if (fu->bcnt) { 164 if (fu->bcnt) {
168 do { 165 for (;;) {
169 if (fu->bcnt == *byte_count_str) { 166 if (fu->bcnt == *byte_count_str)
170 break; 167 break;
171 } 168 if (*++byte_count_str == 0)
172 } while (*++byte_count_str); 169 bb_error_msg_and_die("bad byte count for conversion character %s", p1);
170 }
173 } 171 }
174 /* Unlike the original, output the remainder of the format string. */ 172 /* Unlike the original, output the remainder of the format string. */
175 if (!*byte_count_str) {
176 bb_error_msg_and_die("bad byte count for conversion character %s", p1);
177 }
178 pr->bcnt = *byte_count_str; 173 pr->bcnt = *byte_count_str;
179 } else if (*p1 == 'l') { 174 } else
175 if (*p1 == 'l') { /* %ld etc */
176 const char *e;
177
180 ++p2; 178 ++p2;
181 ++p1; 179 ++p1;
182 DO_INT_CONV: 180 DO_INT_CONV:
183 { 181 e = strchr(int_convs, *p1); /* "diouxX"? */
184 const char *e; 182 if (!e)
185 e = strchr(lcc, *p1); 183 goto DO_BAD_CONV_CHAR;
186 if (!e) { 184 pr->flags = F_INT;
187 goto DO_BAD_CONV_CHAR; 185 if (e > int_convs + 1) /* not d or i? */
188 } 186 pr->flags = F_UINT;
189 pr->flags = F_INT; 187 byte_count_str = "\004\002\001";
190 if (e > lcc + 1) { 188 goto DO_BYTE_COUNT;
191 pr->flags = F_UINT; 189 } else
192 } 190 if (strchr(int_convs, *p1)) { /* %d etc */
193 byte_count_str = "\004\002\001";
194 goto DO_BYTE_COUNT;
195 }
196 /* NOTREACHED */
197 } else if (strchr(lcc, *p1)) {
198 goto DO_INT_CONV; 191 goto DO_INT_CONV;
199 } else if (strchr("eEfgG", *p1)) { 192 } else
193 if (strchr("eEfgG", *p1)) { /* floating point */
200 pr->flags = F_DBL; 194 pr->flags = F_DBL;
201 byte_count_str = "\010\004"; 195 byte_count_str = "\010\004";
202 goto DO_BYTE_COUNT; 196 goto DO_BYTE_COUNT;
203 } else if (*p1 == 's') { 197 } else
198 if (*p1 == 's') {
204 pr->flags = F_STR; 199 pr->flags = F_STR;
205 if (sokay == USEBCNT) { 200 pr->bcnt = fu->bcnt;
206 pr->bcnt = fu->bcnt; 201 if (fu->bcnt == 0) {
207 } else if (sokay == USEPREC) { 202 if (!prec)
208 pr->bcnt = prec; 203 bb_error_msg_and_die("%%s needs precision or byte count");
209 } else { /* NOTOKAY */ 204 pr->bcnt = atoi(prec);
210 bb_error_msg_and_die("%%s requires a precision or a byte count");
211 } 205 }
212 } else if (*p1 == '_') { 206 } else
213 ++p2; 207 if (*p1 == '_') {
208 p2++; /* move past a in "%_a" */
214 switch (p1[1]) { 209 switch (p1[1]) {
215 case 'A': 210 case 'A': /* %_A[dox]: print address and the end */
216 dumper->endfu = fu; 211 dumper->endfu = fu;
217 fu->flags |= F_IGNORE; 212 fu->flags |= F_IGNORE;
218 /* FALLTHROUGH */ 213 /* FALLTHROUGH */
219 case 'a': 214 case 'a': /* %_a[dox]: current address */
220 pr->flags = F_ADDRESS; 215 pr->flags = F_ADDRESS;
221 ++p2; 216 p2++; /* move past x in "%_ax" */
222 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) { 217 if ((p1[2] != 'd') && (p1[2] != 'o') && (p1[2] != 'x')) {
223 goto DO_BAD_CONV_CHAR; 218 goto DO_BAD_CONV_CHAR;
224 } 219 }
225 *p1 = p1[2]; 220 *p1 = p1[2];
226 break; 221 break;
227 case 'c': 222 case 'c': /* %_c: chars, \ooo, \n \r \t etc */
228 pr->flags = F_C; 223 pr->flags = F_C;
229 /* *p1 = 'c'; set in conv_c */ 224 /* *p1 = 'c'; set in conv_c */
230 goto DO_BYTE_COUNT_1; 225 goto DO_BYTE_COUNT_1;
231 case 'p': 226 case 'p': /* %_p: chars, dots for nonprintable */
232 pr->flags = F_P; 227 pr->flags = F_P;
233 *p1 = 'c'; 228 *p1 = 'c';
234 goto DO_BYTE_COUNT_1; 229 goto DO_BYTE_COUNT_1;
235 case 'u': 230 case 'u': /* %_p: chars, 'nul', 'esc' etc for nonprintable */
236 pr->flags = F_U; 231 pr->flags = F_U;
237 /* *p1 = 'c'; set in conv_u */ 232 /* *p1 = 'c'; set in conv_u */
238 goto DO_BYTE_COUNT_1; 233 goto DO_BYTE_COUNT_1;
@@ -248,13 +243,8 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
248 * copy to PR format string, set conversion character 243 * copy to PR format string, set conversion character
249 * pointer, update original. 244 * pointer, update original.
250 */ 245 */
251 savech = *p2; 246 len = (p1 - fmtp) + 1;
252 p1[1] = '\0'; 247 pr->fmt = xstrndup(fmtp, len);
253 pr->fmt = xstrdup(fmtp);
254 *p2 = savech;
255 //Too early! xrealloc can move pr->fmt!
256 //pr->cchar = pr->fmt + (p1 - fmtp);
257
258 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost. 248 /* DBU:[dave@cray.com] w/o this, trailing fmt text, space is lost.
259 * Skip subsequent text and up to the next % sign and tack the 249 * Skip subsequent text and up to the next % sign and tack the
260 * additional text onto fmt: eg. if fmt is "%x is a HEX number", 250 * additional text onto fmt: eg. if fmt is "%x is a HEX number",
@@ -262,16 +252,17 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
262 */ 252 */
263 for (p3 = p2; *p3 && *p3 != '%'; p3++) 253 for (p3 = p2; *p3 && *p3 != '%'; p3++)
264 continue; 254 continue;
265 if (p3 > p2) { 255 if ((p3 - p2) != 0) {
266 savech = *p3; 256 char *d;
267 *p3 = '\0'; 257 pr->fmt = d = xrealloc(pr->fmt, len + (p3 - p2) + 1);
268 pr->fmt = xrealloc(pr->fmt, strlen(pr->fmt) + (p3-p2) + 1); 258 d += len;
269 strcat(pr->fmt, p2); 259 do {
270 *p3 = savech; 260 *d++ = *p2++;
271 p2 = p3; 261 } while (p2 != p3);
262 *d = '\0';
263 /* now p2 = p3 */
272 } 264 }
273 265 pr->cchar = pr->fmt + len - 1; /* must be after realloc! */
274 pr->cchar = pr->fmt + (p1 - fmtp);
275 fmtp = p2; 266 fmtp = p2;
276 267
277 /* only one conversion character if byte count */ 268 /* only one conversion character if byte count */
@@ -283,7 +274,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
283 * if format unit byte count not specified, figure it out 274 * if format unit byte count not specified, figure it out
284 * so can adjust rep count later. 275 * so can adjust rep count later.
285 */ 276 */
286 if (!fu->bcnt) 277 if (fu->bcnt == 0)
287 for (pr = fu->nextpr; pr; pr = pr->nextpr) 278 for (pr = fu->nextpr; pr; pr = pr->nextpr)
288 fu->bcnt += pr->bcnt; 279 fu->bcnt += pr->bcnt;
289 } 280 }
@@ -305,16 +296,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
305 fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; 296 fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt;
306 } 297 }
307 if (fu->reps > 1 && fu->nextpr) { 298 if (fu->reps > 1 && fu->nextpr) {
299 PR *pr;
300 char *p1, *p2;
301
308 for (pr = fu->nextpr;; pr = pr->nextpr) 302 for (pr = fu->nextpr;; pr = pr->nextpr)
309 if (!pr->nextpr) 303 if (!pr->nextpr)
310 break; 304 break;
311 for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) 305 p2 = NULL;
306 for (p1 = pr->fmt; *p1; ++p1)
312 p2 = isspace(*p1) ? p1 : NULL; 307 p2 = isspace(*p1) ? p1 : NULL;
313 if (p2) 308 if (p2)
314 pr->nospace = p2; 309 pr->nospace = p2;
315 } 310 }
316 if (!fu->nextfu)
317 break;
318 } 311 }
319} 312}
320 313
@@ -358,6 +351,7 @@ static NOINLINE int next(priv_dumper_t *dumper)
358 if (dumper->next__done) 351 if (dumper->next__done)
359 return 0; /* no next file */ 352 return 0; /* no next file */
360 dumper->next__done = 1; 353 dumper->next__done = 1;
354//why stat of stdin is specially prohibited?
361 statok = 0; 355 statok = 0;
362 } 356 }
363 if (dumper->pub.dump_skip) 357 if (dumper->pub.dump_skip)
@@ -762,6 +756,11 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
762 if (!isspace(*p)) { 756 if (!isspace(*p)) {
763 bb_error_msg_and_die("bad format {%s}", fmt); 757 bb_error_msg_and_die("bad format {%s}", fmt);
764 } 758 }
759// Above check prohibits formats such as '/1"%02x"' - it requires space after 1.
760// Other than this, formats can be pretty much jammed together:
761// "%07_ax:"8/2 "%04x|""\n"
762// but this space is required. The check *can* be removed, but
763// keeping it to stay compat with util-linux hexdump.
765 tfu->bcnt = atoi(savep); 764 tfu->bcnt = atoi(savep);
766 /* skip trailing white space */ 765 /* skip trailing white space */
767 p = skip_whitespace(p + 1); 766 p = skip_whitespace(p + 1);