GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/hexdump/parse.c Lines: 0 233 0.0 %
Date: 2016-12-06 Branches: 0 195 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: parse.c,v 1.20 2016/03/15 04:19:13 mmcc Exp $	*/
2
/*	$NetBSD: parse.c,v 1.12 2001/12/07 13:37:39 bjh21 Exp $	*/
3
4
/*
5
 * Copyright (c) 1989, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <sys/file.h>
35
36
#include <ctype.h>
37
#include <err.h>
38
#include <errno.h>
39
#include <fcntl.h>
40
#include <stdio.h>
41
#include <stdlib.h>
42
#include <string.h>
43
44
#include "hexdump.h"
45
46
FU *endfu;					/* format at end-of-data */
47
48
static __dead void	 badcnt(char *);
49
static __dead void	 badconv(char *);
50
static __dead void	 badfmt(const char *);
51
static __dead void	 badsfmt(void);
52
static void		 escape(char *);
53
54
void
55
addfile(char *name)
56
{
57
	FILE *fp;
58
	size_t len;
59
	char *buf, *lbuf, *p;
60
61
	if ((fp = fopen(name, "r")) == NULL)
62
		err(1, "fopen %s", name);
63
64
	lbuf = NULL;
65
	while ((buf = fgetln(fp, &len))) {
66
		if (buf[len - 1] == '\n')
67
			buf[len - 1] = '\0';
68
		else {
69
			/* EOF without EOL, copy and add the NUL */
70
			if ((lbuf = malloc(len + 1)) == NULL)
71
				err(1, NULL);
72
			memcpy(lbuf, buf, len);
73
			lbuf[len] = '\0';
74
			buf = lbuf;
75
		}
76
		for (p = buf; isspace((unsigned char)*p); ++p);
77
		if (!*p || *p == '#')
78
			continue;
79
		add(p);
80
	}
81
	free(lbuf);
82
	(void)fclose(fp);
83
}
84
85
void
86
add(const char *fmt)
87
{
88
	const char *p;
89
	static FS **nextfs;
90
	FS *tfs;
91
	FU *tfu, **nextfu;
92
	const char *savep;
93
94
	/* start new linked list of format units */
95
	if ((tfs = calloc(1, sizeof(FS))) == NULL)
96
		err(1, NULL);
97
	if (!fshead)
98
		fshead = tfs;
99
	else
100
		*nextfs = tfs;
101
	nextfs = &tfs->nextfs;
102
	nextfu = &tfs->nextfu;
103
104
	/* take the format string and break it up into format units */
105
	for (p = fmt;;) {
106
		/* skip leading white space */
107
		for (; isspace((unsigned char)*p); ++p);
108
		if (!*p)
109
			break;
110
111
		/* allocate a new format unit and link it in */
112
		if ((tfu = calloc(1, sizeof(FU))) == NULL)
113
			err(1, NULL);
114
		*nextfu = tfu;
115
		nextfu = &tfu->nextfu;
116
		tfu->reps = 1;
117
118
		/* if leading digit, repetition count */
119
		if (isdigit((unsigned char)*p)) {
120
			for (savep = p; isdigit((unsigned char)*p); ++p);
121
			if (!isspace((unsigned char)*p) && *p != '/')
122
				badfmt(fmt);
123
			/* may overwrite either white space or slash */
124
			tfu->reps = atoi(savep);
125
			tfu->flags = F_SETREP;
126
			/* skip trailing white space */
127
			for (++p; isspace((unsigned char)*p); ++p);
128
		}
129
130
		/* skip slash and trailing white space */
131
		if (*p == '/')
132
			while (isspace((unsigned char)*++p));
133
134
		/* byte count */
135
		if (isdigit((unsigned char)*p)) {
136
			for (savep = p; isdigit((unsigned char)*p); ++p);
137
			if (!isspace((unsigned char)*p))
138
				badfmt(fmt);
139
			tfu->bcnt = atoi(savep);
140
			/* skip trailing white space */
141
			for (++p; isspace((unsigned char)*p); ++p);
142
		}
143
144
		/* format */
145
		if (*p != '"')
146
			badfmt(fmt);
147
		for (savep = ++p; *p != '"';)
148
			if (*p++ == 0)
149
				badfmt(fmt);
150
		tfu->fmt = strndup(savep, p - savep);
151
		if (tfu->fmt == NULL)
152
			err(1, NULL);
153
		escape(tfu->fmt);
154
		p++;
155
	}
156
}
157
158
static const char *spec = ".#-+ 0123456789";
159
160
int
161
size(FS *fs)
162
{
163
	FU *fu;
164
	int bcnt, cursize;
165
	char *fmt;
166
	int prec;
167
168
	/* figure out the data block size needed for each format unit */
169
	for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
170
		if (fu->bcnt) {
171
			cursize += fu->bcnt * fu->reps;
172
			continue;
173
		}
174
		for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
175
			if (*fmt != '%')
176
				continue;
177
			/*
178
			 * skip any special chars -- save precision in
179
			 * case it's a %s format.
180
			 */
181
			while (*++fmt && strchr(spec + 1, *fmt));
182
			if (*fmt == '.' && isdigit((unsigned char)*++fmt)) {
183
				prec = atoi(fmt);
184
				while (isdigit((unsigned char)*++fmt));
185
			}
186
			switch(*fmt) {
187
			case 'c':
188
				bcnt += 1;
189
				break;
190
			case 'd': case 'i': case 'o': case 'u':
191
			case 'x': case 'X':
192
				bcnt += 4;
193
				break;
194
			case 'e': case 'E': case 'f': case 'g': case 'G':
195
				bcnt += 8;
196
				break;
197
			case 's':
198
				bcnt += prec;
199
				break;
200
			case '_':
201
				switch(*++fmt) {
202
				case 'c': case 'p': case 'u':
203
					bcnt += 1;
204
					break;
205
				}
206
			}
207
		}
208
		cursize += bcnt * fu->reps;
209
	}
210
	return (cursize);
211
}
212
213
void
214
rewrite(FS *fs)
215
{
216
	enum { NOTOKAY, USEBCNT, USEPREC } sokay;
217
	PR *pr, **nextpr;
218
	FU *fu;
219
	char *p1, *p2;
220
	char savech, *fmtp, cs[3];
221
	int nconv, prec;
222
	size_t len;
223
224
	nextpr = NULL;
225
	prec = 0;
226
	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
227
		/*
228
		 * Break each format unit into print units; each conversion
229
		 * character gets its own.
230
		 */
231
		for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
232
			if ((pr = calloc(1, sizeof(PR))) == NULL)
233
				err(1, NULL);
234
			if (!fu->nextpr)
235
				fu->nextpr = pr;
236
			else
237
				*nextpr = pr;
238
239
			/* Skip preceding text and up to the next % sign. */
240
			for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
241
242
			/* Only text in the string. */
243
			if (!*p1) {
244
				pr->fmt = fmtp;
245
				pr->flags = F_TEXT;
246
				break;
247
			}
248
249
			/*
250
			 * Get precision for %s -- if have a byte count, don't
251
			 * need it.
252
			 */
253
			if (fu->bcnt) {
254
				sokay = USEBCNT;
255
				/* Skip to conversion character. */
256
				for (++p1; *p1 && strchr(spec, *p1); ++p1);
257
			} else {
258
				/* Skip any special chars, field width. */
259
				while (*++p1 && strchr(spec + 1, *p1));
260
				if (*p1 == '.' &&
261
				    isdigit((unsigned char)*++p1)) {
262
					sokay = USEPREC;
263
					prec = atoi(p1);
264
					while (isdigit((unsigned char)*++p1))
265
						continue;
266
				} else
267
					sokay = NOTOKAY;
268
			}
269
270
			p2 = *p1 ? p1 + 1 : p1;	/* Set end pointer. */
271
			cs[0] = *p1;		/* Set conversion string. */
272
			cs[1] = '\0';
273
274
			/*
275
			 * Figure out the byte count for each conversion;
276
			 * rewrite the format as necessary, set up blank-
277
			 * padding for end of data.
278
			 */
279
			switch(cs[0]) {
280
			case 'c':
281
				pr->flags = F_CHAR;
282
				switch(fu->bcnt) {
283
				case 0: case 1:
284
					pr->bcnt = 1;
285
					break;
286
				default:
287
					p1[1] = '\0';
288
					badcnt(p1);
289
				}
290
				break;
291
			case 'd': case 'i':
292
			case 'o': case 'u': case 'x': case 'X':
293
				if (cs[0] == 'd' || cs[0] == 'i')
294
					pr->flags = F_INT;
295
				else
296
					pr->flags = F_UINT;
297
298
				cs[2] = '\0';
299
				cs[1] = cs[0];
300
				cs[0] = 'q';
301
				switch(fu->bcnt) {
302
				case 0: case 4:
303
					pr->bcnt = 4;
304
					break;
305
				case 1:
306
					pr->bcnt = 1;
307
					break;
308
				case 2:
309
					pr->bcnt = 2;
310
					break;
311
				case 8:
312
					pr->bcnt = 8;
313
					break;
314
				default:
315
					p1[1] = '\0';
316
					badcnt(p1);
317
				}
318
				break;
319
			case 'e': case 'E': case 'f': case 'g': case 'G':
320
				pr->flags = F_DBL;
321
				switch(fu->bcnt) {
322
				case 0: case 8:
323
					pr->bcnt = 8;
324
					break;
325
				case 4:
326
					pr->bcnt = 4;
327
					break;
328
				default:
329
					p1[1] = '\0';
330
					badcnt(p1);
331
				}
332
				break;
333
			case 's':
334
				pr->flags = F_STR;
335
				switch(sokay) {
336
				case NOTOKAY:
337
					badsfmt();
338
				case USEBCNT:
339
					pr->bcnt = fu->bcnt;
340
					break;
341
				case USEPREC:
342
					pr->bcnt = prec;
343
					break;
344
				}
345
				break;
346
			case '_':
347
				++p2;
348
				switch(p1[1]) {
349
				case 'A':
350
					endfu = fu;
351
					fu->flags |= F_IGNORE;
352
					/* FALLTHROUGH */
353
				case 'a':
354
					pr->flags = F_ADDRESS;
355
					++p2;
356
					switch(p1[2]) {
357
					case 'd': case 'o': case'x':
358
						cs[0] = 'q';
359
						cs[1] = p1[2];
360
						cs[2] = '\0';
361
						break;
362
					default:
363
						if (p1[2])
364
							p1[3] = '\0';
365
						badconv(p1);
366
					}
367
					break;
368
				case 'c':
369
				case 'p':
370
				case 'u':
371
					if (p1[1] == 'c') {
372
						pr->flags = F_C;
373
						/* cs[0] = 'c';	set in conv_c */
374
					} else if (p1[1] == 'p') {
375
						pr->flags = F_P;
376
						cs[0] = 'c';
377
					} else {
378
						pr->flags = F_U;
379
						/* cs[0] = 'c';	set in conv_u */
380
					}
381
382
					switch(fu->bcnt) {
383
					case 0: case 1:
384
						pr->bcnt = 1;
385
						break;
386
					default:
387
						p1[2] = '\0';
388
						badcnt(p1);
389
					}
390
					break;
391
				default:
392
					if (p1[1])
393
						p1[2] = '\0';
394
					badconv(p1);
395
				}
396
				break;
397
			default:
398
				if (cs[0])
399
					p1[1] = '\0';
400
				badconv(p1);
401
			}
402
403
			/*
404
			 * Copy to PR format string, set conversion character
405
			 * pointer, update original.
406
			 */
407
			savech = *p2;
408
			p1[0] = '\0';
409
			len = strlen(fmtp) + strlen(cs) + 1;
410
			if ((pr->fmt = calloc(1, len)) == NULL)
411
				err(1, NULL);
412
			snprintf(pr->fmt, len, "%s%s", fmtp, cs);
413
			*p2 = savech;
414
			pr->cchar = pr->fmt + (p1 - fmtp);
415
			fmtp = p2;
416
417
			/* Only one conversion character if byte count. */
418
			if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
419
				errx(1,
420
			    "byte count with multiple conversion characters");
421
		}
422
		/*
423
		 * If format unit byte count not specified, figure it out
424
		 * so can adjust rep count later.
425
		 */
426
		if (!fu->bcnt)
427
			for (pr = fu->nextpr; pr; pr = pr->nextpr)
428
				fu->bcnt += pr->bcnt;
429
	}
430
	/*
431
	 * If the format string interprets any data at all, and it's
432
	 * not the same as the blocksize, and its last format unit
433
	 * interprets any data at all, and has no iteration count,
434
	 * repeat it as necessary.
435
	 *
436
	 * If, rep count is greater than 1, no trailing whitespace
437
	 * gets output from the last iteration of the format unit.
438
	 */
439
	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
440
		if (!fu->nextfu && fs->bcnt < blocksize &&
441
		    !(fu->flags&F_SETREP) && fu->bcnt)
442
			fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
443
		if (fu->reps > 1) {
444
			if (!fu->nextpr)
445
				break;
446
			for (pr = fu->nextpr;; pr = pr->nextpr)
447
				if (!pr->nextpr)
448
					break;
449
			for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
450
				p2 = isspace((unsigned char)*p1) ? p1 : NULL;
451
			if (p2)
452
				pr->nospace = p2;
453
		}
454
	}
455
#ifdef DEBUG
456
	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
457
		(void)printf("fmt:");
458
		for (pr = fu->nextpr; pr; pr = pr->nextpr)
459
			(void)printf(" {%s}", pr->fmt);
460
		(void)printf("\n");
461
	}
462
#endif
463
}
464
465
static void
466
escape(char *p1)
467
{
468
	char *p2;
469
470
	/* alphabetic escape sequences have to be done in place */
471
	for (p2 = p1;; ++p1, ++p2) {
472
		if (!*p1) {
473
			*p2 = *p1;
474
			break;
475
		}
476
		if (*p1 == '\\') {
477
			switch(*++p1) {
478
			case '\0':
479
				*p2++ = '\\';
480
				*p2 = '\0';
481
				return;	/* incomplete escape sequence */
482
			case 'a':
483
			     /* *p2 = '\a'; */
484
				*p2 = '\007';
485
				break;
486
			case 'b':
487
				*p2 = '\b';
488
				break;
489
			case 'f':
490
				*p2 = '\f';
491
				break;
492
			case 'n':
493
				*p2 = '\n';
494
				break;
495
			case 'r':
496
				*p2 = '\r';
497
				break;
498
			case 't':
499
				*p2 = '\t';
500
				break;
501
			case 'v':
502
				*p2 = '\v';
503
				break;
504
			default:
505
				*p2 = *p1;
506
				break;
507
			}
508
		} else
509
			*p2 = *p1;
510
	}
511
}
512
513
static __dead void
514
badcnt(char *s)
515
{
516
	errx(1, "%s: bad byte count", s);
517
}
518
519
static __dead void
520
badsfmt(void)
521
{
522
	errx(1, "%%s: requires a precision or a byte count");
523
}
524
525
static __dead void
526
badfmt(const char *fmt)
527
{
528
	errx(1, "\"%s\": bad format", fmt);
529
}
530
531
static __dead void
532
badconv(char *ch)
533
{
534
	errx(1, "%%%s: bad conversion character", ch);
535
}