parse.c revision 161132
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1989, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3527315Scharnier#if 0
361590Srgrimesstatic char sccsid[] = "@(#)parse.c	8.1 (Berkeley) 6/6/93";
3727315Scharnier#endif
381590Srgrimes#endif /* not lint */
3999112Sobrien#include <sys/cdefs.h>
4099112Sobrien__FBSDID("$FreeBSD: head/usr.bin/hexdump/parse.c 161132 2006-08-09 19:12:10Z maxim $");
411590Srgrimes
421590Srgrimes#include <sys/types.h>
431590Srgrimes
4427315Scharnier#include <err.h>
451590Srgrimes#include <fcntl.h>
461590Srgrimes#include <stdio.h>
471590Srgrimes#include <stdlib.h>
481590Srgrimes#include <ctype.h>
491590Srgrimes#include <string.h>
501590Srgrimes#include "hexdump.h"
511590Srgrimes
521590SrgrimesFU *endfu;					/* format at end-of-data */
531590Srgrimes
541590Srgrimesvoid
55102944Sdwmaloneaddfile(char *name)
561590Srgrimes{
57102944Sdwmalone	unsigned char *p;
581590Srgrimes	FILE *fp;
591590Srgrimes	int ch;
601590Srgrimes	char buf[2048 + 1];
611590Srgrimes
621590Srgrimes	if ((fp = fopen(name, "r")) == NULL)
6327315Scharnier		err(1, "%s", name);
641590Srgrimes	while (fgets(buf, sizeof(buf), fp)) {
651590Srgrimes		if (!(p = index(buf, '\n'))) {
6627315Scharnier			warnx("line too long");
671590Srgrimes			while ((ch = getchar()) != '\n' && ch != EOF);
681590Srgrimes			continue;
691590Srgrimes		}
701590Srgrimes		*p = '\0';
711590Srgrimes		for (p = buf; *p && isspace(*p); ++p);
721590Srgrimes		if (!*p || *p == '#')
731590Srgrimes			continue;
741590Srgrimes		add(p);
751590Srgrimes	}
761590Srgrimes	(void)fclose(fp);
771590Srgrimes}
781590Srgrimes
791590Srgrimesvoid
80102944Sdwmaloneadd(const char *fmt)
811590Srgrimes{
8287203Smarkm	unsigned const char *p, *savep;
831590Srgrimes	static FS **nextfs;
841590Srgrimes	FS *tfs;
851590Srgrimes	FU *tfu, **nextfu;
861590Srgrimes
871590Srgrimes	/* start new linked list of format units */
8880290Sobrien	if ((tfs = calloc(1, sizeof(FS))) == NULL)
8980290Sobrien		err(1, NULL);
901590Srgrimes	if (!fshead)
911590Srgrimes		fshead = tfs;
921590Srgrimes	else
931590Srgrimes		*nextfs = tfs;
941590Srgrimes	nextfs = &tfs->nextfs;
951590Srgrimes	nextfu = &tfs->nextfu;
961590Srgrimes
971590Srgrimes	/* take the format string and break it up into format units */
981590Srgrimes	for (p = fmt;;) {
991590Srgrimes		/* skip leading white space */
1001590Srgrimes		for (; isspace(*p); ++p);
1011590Srgrimes		if (!*p)
1021590Srgrimes			break;
1031590Srgrimes
1041590Srgrimes		/* allocate a new format unit and link it in */
10580290Sobrien		if ((tfu = calloc(1, sizeof(FU))) == NULL)
10680290Sobrien			err(1, NULL);
1071590Srgrimes		*nextfu = tfu;
1081590Srgrimes		nextfu = &tfu->nextfu;
1091590Srgrimes		tfu->reps = 1;
1101590Srgrimes
1111590Srgrimes		/* if leading digit, repetition count */
1121590Srgrimes		if (isdigit(*p)) {
1131590Srgrimes			for (savep = p; isdigit(*p); ++p);
1141590Srgrimes			if (!isspace(*p) && *p != '/')
1151590Srgrimes				badfmt(fmt);
1161590Srgrimes			/* may overwrite either white space or slash */
1171590Srgrimes			tfu->reps = atoi(savep);
1181590Srgrimes			tfu->flags = F_SETREP;
1191590Srgrimes			/* skip trailing white space */
1201590Srgrimes			for (++p; isspace(*p); ++p);
1211590Srgrimes		}
1221590Srgrimes
1231590Srgrimes		/* skip slash and trailing white space */
1241590Srgrimes		if (*p == '/')
1251590Srgrimes			while (isspace(*++p));
1261590Srgrimes
1271590Srgrimes		/* byte count */
1281590Srgrimes		if (isdigit(*p)) {
1291590Srgrimes			for (savep = p; isdigit(*p); ++p);
1301590Srgrimes			if (!isspace(*p))
1311590Srgrimes				badfmt(fmt);
1321590Srgrimes			tfu->bcnt = atoi(savep);
1331590Srgrimes			/* skip trailing white space */
1341590Srgrimes			for (++p; isspace(*p); ++p);
1351590Srgrimes		}
1361590Srgrimes
1371590Srgrimes		/* format */
1381590Srgrimes		if (*p != '"')
1391590Srgrimes			badfmt(fmt);
1401590Srgrimes		for (savep = ++p; *p != '"';)
1411590Srgrimes			if (*p++ == 0)
1421590Srgrimes				badfmt(fmt);
1431590Srgrimes		if (!(tfu->fmt = malloc(p - savep + 1)))
14480290Sobrien			err(1, NULL);
1451590Srgrimes		(void) strncpy(tfu->fmt, savep, p - savep);
1461590Srgrimes		tfu->fmt[p - savep] = '\0';
1471590Srgrimes		escape(tfu->fmt);
1481590Srgrimes		p++;
1491590Srgrimes	}
1501590Srgrimes}
1511590Srgrimes
15291840Sobrienstatic const char *spec = ".#-+ 0123456789";
1531590Srgrimes
1541590Srgrimesint
155102944Sdwmalonesize(FS *fs)
1561590Srgrimes{
157102944Sdwmalone	FU *fu;
158102944Sdwmalone	int bcnt, cursize;
159102944Sdwmalone	unsigned char *fmt;
1601590Srgrimes	int prec;
1611590Srgrimes
1621590Srgrimes	/* figure out the data block size needed for each format unit */
1631590Srgrimes	for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
1641590Srgrimes		if (fu->bcnt) {
1651590Srgrimes			cursize += fu->bcnt * fu->reps;
1661590Srgrimes			continue;
1671590Srgrimes		}
1681590Srgrimes		for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
1691590Srgrimes			if (*fmt != '%')
1701590Srgrimes				continue;
1711590Srgrimes			/*
1721590Srgrimes			 * skip any special chars -- save precision in
1731590Srgrimes			 * case it's a %s format.
1741590Srgrimes			 */
1751590Srgrimes			while (index(spec + 1, *++fmt));
1761590Srgrimes			if (*fmt == '.' && isdigit(*++fmt)) {
1771590Srgrimes				prec = atoi(fmt);
1781590Srgrimes				while (isdigit(*++fmt));
1791590Srgrimes			}
1801590Srgrimes			switch(*fmt) {
1811590Srgrimes			case 'c':
1821590Srgrimes				bcnt += 1;
1831590Srgrimes				break;
1841590Srgrimes			case 'd': case 'i': case 'o': case 'u':
1851590Srgrimes			case 'x': case 'X':
1861590Srgrimes				bcnt += 4;
1871590Srgrimes				break;
1881590Srgrimes			case 'e': case 'E': case 'f': case 'g': case 'G':
1891590Srgrimes				bcnt += 8;
1901590Srgrimes				break;
1911590Srgrimes			case 's':
1921590Srgrimes				bcnt += prec;
1931590Srgrimes				break;
1941590Srgrimes			case '_':
1951590Srgrimes				switch(*++fmt) {
1961590Srgrimes				case 'c': case 'p': case 'u':
1971590Srgrimes					bcnt += 1;
1981590Srgrimes					break;
1991590Srgrimes				}
2001590Srgrimes			}
2011590Srgrimes		}
2021590Srgrimes		cursize += bcnt * fu->reps;
2031590Srgrimes	}
2041590Srgrimes	return (cursize);
2051590Srgrimes}
2061590Srgrimes
2071590Srgrimesvoid
208102944Sdwmalonerewrite(FS *fs)
2091590Srgrimes{
2101590Srgrimes	enum { NOTOKAY, USEBCNT, USEPREC } sokay;
211102944Sdwmalone	PR *pr, **nextpr;
212102944Sdwmalone	FU *fu;
21330921Sache	unsigned char *p1, *p2, *fmtp;
21430921Sache	char savech, cs[3];
2151590Srgrimes	int nconv, prec;
216161132Smaxim	size_t len;
2171590Srgrimes
218132541Sjohan	nextpr = NULL;
219132541Sjohan	prec = 0;
220132541Sjohan
2211590Srgrimes	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
2221590Srgrimes		/*
2231590Srgrimes		 * Break each format unit into print units; each conversion
2241590Srgrimes		 * character gets its own.
2251590Srgrimes		 */
2261590Srgrimes		for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) {
22780290Sobrien			if ((pr = calloc(1, sizeof(PR))) == NULL)
22880290Sobrien				err(1, NULL);
2291590Srgrimes			if (!fu->nextpr)
2301590Srgrimes				fu->nextpr = pr;
2311590Srgrimes			else
2321590Srgrimes				*nextpr = pr;
2331590Srgrimes
2341590Srgrimes			/* Skip preceding text and up to the next % sign. */
2351590Srgrimes			for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
2361590Srgrimes
2371590Srgrimes			/* Only text in the string. */
2381590Srgrimes			if (!*p1) {
2391590Srgrimes				pr->fmt = fmtp;
2401590Srgrimes				pr->flags = F_TEXT;
2411590Srgrimes				break;
2421590Srgrimes			}
2431590Srgrimes
2441590Srgrimes			/*
2451590Srgrimes			 * Get precision for %s -- if have a byte count, don't
2461590Srgrimes			 * need it.
2471590Srgrimes			 */
2481590Srgrimes			if (fu->bcnt) {
2491590Srgrimes				sokay = USEBCNT;
2501590Srgrimes				/* Skip to conversion character. */
2511590Srgrimes				for (++p1; index(spec, *p1); ++p1);
2521590Srgrimes			} else {
2531590Srgrimes				/* Skip any special chars, field width. */
2541590Srgrimes				while (index(spec + 1, *++p1));
2551590Srgrimes				if (*p1 == '.' && isdigit(*++p1)) {
2561590Srgrimes					sokay = USEPREC;
2571590Srgrimes					prec = atoi(p1);
2581590Srgrimes					while (isdigit(*++p1));
2591590Srgrimes				} else
2601590Srgrimes					sokay = NOTOKAY;
2611590Srgrimes			}
2621590Srgrimes
2631590Srgrimes			p2 = p1 + 1;		/* Set end pointer. */
2641590Srgrimes			cs[0] = *p1;		/* Set conversion string. */
2651590Srgrimes			cs[1] = '\0';
2661590Srgrimes
2671590Srgrimes			/*
2681590Srgrimes			 * Figure out the byte count for each conversion;
2691590Srgrimes			 * rewrite the format as necessary, set up blank-
2701590Srgrimes			 * padding for end of data.
2711590Srgrimes			 */
2721590Srgrimes			switch(cs[0]) {
2731590Srgrimes			case 'c':
2741590Srgrimes				pr->flags = F_CHAR;
2751590Srgrimes				switch(fu->bcnt) {
2761590Srgrimes				case 0: case 1:
2771590Srgrimes					pr->bcnt = 1;
2781590Srgrimes					break;
2791590Srgrimes				default:
2801590Srgrimes					p1[1] = '\0';
2811590Srgrimes					badcnt(p1);
2821590Srgrimes				}
2831590Srgrimes				break;
2841590Srgrimes			case 'd': case 'i':
2851590Srgrimes				pr->flags = F_INT;
2861590Srgrimes				goto isint;
2871590Srgrimes			case 'o': case 'u': case 'x': case 'X':
2881590Srgrimes				pr->flags = F_UINT;
2891590Srgrimesisint:				cs[2] = '\0';
2901590Srgrimes				cs[1] = cs[0];
2911590Srgrimes				cs[0] = 'q';
2921590Srgrimes				switch(fu->bcnt) {
2931590Srgrimes				case 0: case 4:
2941590Srgrimes					pr->bcnt = 4;
2951590Srgrimes					break;
2961590Srgrimes				case 1:
2971590Srgrimes					pr->bcnt = 1;
2981590Srgrimes					break;
2991590Srgrimes				case 2:
3001590Srgrimes					pr->bcnt = 2;
3011590Srgrimes					break;
3021590Srgrimes				default:
3031590Srgrimes					p1[1] = '\0';
3041590Srgrimes					badcnt(p1);
3051590Srgrimes				}
3061590Srgrimes				break;
3071590Srgrimes			case 'e': case 'E': case 'f': case 'g': case 'G':
3081590Srgrimes				pr->flags = F_DBL;
3091590Srgrimes				switch(fu->bcnt) {
3101590Srgrimes				case 0: case 8:
3111590Srgrimes					pr->bcnt = 8;
3121590Srgrimes					break;
3131590Srgrimes				case 4:
3141590Srgrimes					pr->bcnt = 4;
3151590Srgrimes					break;
3161590Srgrimes				default:
31796795Stjr					if (fu->bcnt == sizeof(long double)) {
31896795Stjr						cs[2] = '\0';
31996795Stjr						cs[1] = cs[0];
32096795Stjr						cs[0] = 'L';
32196795Stjr						pr->bcnt = sizeof(long double);
32296795Stjr					} else {
32396795Stjr						p1[1] = '\0';
32496795Stjr						badcnt(p1);
32596795Stjr					}
3261590Srgrimes				}
3271590Srgrimes				break;
3281590Srgrimes			case 's':
3291590Srgrimes				pr->flags = F_STR;
3301590Srgrimes				switch(sokay) {
3311590Srgrimes				case NOTOKAY:
3321590Srgrimes					badsfmt();
3331590Srgrimes				case USEBCNT:
3341590Srgrimes					pr->bcnt = fu->bcnt;
3351590Srgrimes					break;
3361590Srgrimes				case USEPREC:
3371590Srgrimes					pr->bcnt = prec;
3381590Srgrimes					break;
3391590Srgrimes				}
3401590Srgrimes				break;
3411590Srgrimes			case '_':
3421590Srgrimes				++p2;
3431590Srgrimes				switch(p1[1]) {
3441590Srgrimes				case 'A':
3451590Srgrimes					endfu = fu;
3461590Srgrimes					fu->flags |= F_IGNORE;
3471590Srgrimes					/* FALLTHROUGH */
3481590Srgrimes				case 'a':
3491590Srgrimes					pr->flags = F_ADDRESS;
3501590Srgrimes					++p2;
3511590Srgrimes					switch(p1[2]) {
3521590Srgrimes					case 'd': case 'o': case'x':
3531590Srgrimes						cs[0] = 'q';
3541590Srgrimes						cs[1] = p1[2];
3551590Srgrimes						cs[2] = '\0';
3561590Srgrimes						break;
3571590Srgrimes					default:
3581590Srgrimes						p1[3] = '\0';
3591590Srgrimes						badconv(p1);
3601590Srgrimes					}
3611590Srgrimes					break;
3621590Srgrimes				case 'c':
3631590Srgrimes					pr->flags = F_C;
3641590Srgrimes					/* cs[0] = 'c';	set in conv_c */
3651590Srgrimes					goto isint2;
3661590Srgrimes				case 'p':
3671590Srgrimes					pr->flags = F_P;
3681590Srgrimes					cs[0] = 'c';
3691590Srgrimes					goto isint2;
3701590Srgrimes				case 'u':
3711590Srgrimes					pr->flags = F_U;
3721590Srgrimes					/* cs[0] = 'c';	set in conv_u */
3731590Srgrimesisint2:					switch(fu->bcnt) {
3741590Srgrimes					case 0: case 1:
3751590Srgrimes						pr->bcnt = 1;
3761590Srgrimes						break;
3771590Srgrimes					default:
3781590Srgrimes						p1[2] = '\0';
3791590Srgrimes						badcnt(p1);
3801590Srgrimes					}
3811590Srgrimes					break;
3821590Srgrimes				default:
3831590Srgrimes					p1[2] = '\0';
3841590Srgrimes					badconv(p1);
3851590Srgrimes				}
3861590Srgrimes				break;
3871590Srgrimes			default:
3881590Srgrimes				p1[1] = '\0';
3891590Srgrimes				badconv(p1);
3901590Srgrimes			}
3911590Srgrimes
3921590Srgrimes			/*
3931590Srgrimes			 * Copy to PR format string, set conversion character
3941590Srgrimes			 * pointer, update original.
3951590Srgrimes			 */
3961590Srgrimes			savech = *p2;
3971590Srgrimes			p1[0] = '\0';
398161132Smaxim			len = strlen(fmtp) + strlen(cs) + 1;
399161132Smaxim			if ((pr->fmt = calloc(1, len)) == NULL)
40080290Sobrien				err(1, NULL);
401161132Smaxim			snprintf(pr->fmt, len, "%s%s", fmtp, cs);
4021590Srgrimes			*p2 = savech;
4031590Srgrimes			pr->cchar = pr->fmt + (p1 - fmtp);
4041590Srgrimes			fmtp = p2;
4051590Srgrimes
4061590Srgrimes			/* Only one conversion character if byte count. */
4071590Srgrimes			if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
40827315Scharnier	    errx(1, "byte count with multiple conversion characters");
4091590Srgrimes		}
4101590Srgrimes		/*
4111590Srgrimes		 * If format unit byte count not specified, figure it out
4121590Srgrimes		 * so can adjust rep count later.
4131590Srgrimes		 */
4141590Srgrimes		if (!fu->bcnt)
4151590Srgrimes			for (pr = fu->nextpr; pr; pr = pr->nextpr)
4161590Srgrimes				fu->bcnt += pr->bcnt;
4171590Srgrimes	}
4181590Srgrimes	/*
4191590Srgrimes	 * If the format string interprets any data at all, and it's
4201590Srgrimes	 * not the same as the blocksize, and its last format unit
4211590Srgrimes	 * interprets any data at all, and has no iteration count,
4221590Srgrimes	 * repeat it as necessary.
4231590Srgrimes	 *
4241590Srgrimes	 * If, rep count is greater than 1, no trailing whitespace
4251590Srgrimes	 * gets output from the last iteration of the format unit.
4261590Srgrimes	 */
42797329Stjr	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
4281590Srgrimes		if (!fu->nextfu && fs->bcnt < blocksize &&
4291590Srgrimes		    !(fu->flags&F_SETREP) && fu->bcnt)
4301590Srgrimes			fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
4311590Srgrimes		if (fu->reps > 1) {
4321590Srgrimes			for (pr = fu->nextpr;; pr = pr->nextpr)
4331590Srgrimes				if (!pr->nextpr)
4341590Srgrimes					break;
4351590Srgrimes			for (p1 = pr->fmt, p2 = NULL; *p1; ++p1)
4361590Srgrimes				p2 = isspace(*p1) ? p1 : NULL;
4371590Srgrimes			if (p2)
4381590Srgrimes				pr->nospace = p2;
4391590Srgrimes		}
4401590Srgrimes	}
4411590Srgrimes#ifdef DEBUG
4421590Srgrimes	for (fu = fs->nextfu; fu; fu = fu->nextfu) {
4431590Srgrimes		(void)printf("fmt:");
4441590Srgrimes		for (pr = fu->nextpr; pr; pr = pr->nextpr)
4451590Srgrimes			(void)printf(" {%s}", pr->fmt);
4461590Srgrimes		(void)printf("\n");
4471590Srgrimes	}
4481590Srgrimes#endif
4491590Srgrimes}
4501590Srgrimes
4511590Srgrimesvoid
452102944Sdwmaloneescape(char *p1)
4531590Srgrimes{
454102944Sdwmalone	char *p2;
4551590Srgrimes
4561590Srgrimes	/* alphabetic escape sequences have to be done in place */
4571590Srgrimes	for (p2 = p1;; ++p1, ++p2) {
4581590Srgrimes		if (!*p1) {
4591590Srgrimes			*p2 = *p1;
4601590Srgrimes			break;
4611590Srgrimes		}
4621590Srgrimes		if (*p1 == '\\')
4631590Srgrimes			switch(*++p1) {
4641590Srgrimes			case 'a':
4651590Srgrimes			     /* *p2 = '\a'; */
4661590Srgrimes				*p2 = '\007';
4671590Srgrimes				break;
4681590Srgrimes			case 'b':
4691590Srgrimes				*p2 = '\b';
4701590Srgrimes				break;
4711590Srgrimes			case 'f':
4721590Srgrimes				*p2 = '\f';
4731590Srgrimes				break;
4741590Srgrimes			case 'n':
4751590Srgrimes				*p2 = '\n';
4761590Srgrimes				break;
4771590Srgrimes			case 'r':
4781590Srgrimes				*p2 = '\r';
4791590Srgrimes				break;
4801590Srgrimes			case 't':
4811590Srgrimes				*p2 = '\t';
4821590Srgrimes				break;
4831590Srgrimes			case 'v':
4841590Srgrimes				*p2 = '\v';
4851590Srgrimes				break;
4861590Srgrimes			default:
4871590Srgrimes				*p2 = *p1;
4881590Srgrimes				break;
4891590Srgrimes			}
4901590Srgrimes	}
4911590Srgrimes}
4921590Srgrimes
4931590Srgrimesvoid
494102944Sdwmalonebadcnt(char *s)
4951590Srgrimes{
49627315Scharnier	errx(1, "%s: bad byte count", s);
4971590Srgrimes}
4981590Srgrimes
4991590Srgrimesvoid
500102944Sdwmalonebadsfmt(void)
5011590Srgrimes{
50227315Scharnier	errx(1, "%%s: requires a precision or a byte count");
5031590Srgrimes}
5041590Srgrimes
5051590Srgrimesvoid
506102944Sdwmalonebadfmt(const char *fmt)
5071590Srgrimes{
50827315Scharnier	errx(1, "\"%s\": bad format", fmt);
5091590Srgrimes}
5101590Srgrimes
5111590Srgrimesvoid
512102944Sdwmalonebadconv(char *ch)
5131590Srgrimes{
51427315Scharnier	errx(1, "%%%s: bad conversion character", ch);
5151590Srgrimes}
516