parse.c revision 99112
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 99112 2002-06-30 05:25:07Z obrien $");
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
551590Srgrimesaddfile(name)
561590Srgrimes	char *name;
571590Srgrimes{
5830921Sache	register unsigned char *p;
591590Srgrimes	FILE *fp;
601590Srgrimes	int ch;
611590Srgrimes	char buf[2048 + 1];
621590Srgrimes
631590Srgrimes	if ((fp = fopen(name, "r")) == NULL)
6427315Scharnier		err(1, "%s", name);
651590Srgrimes	while (fgets(buf, sizeof(buf), fp)) {
661590Srgrimes		if (!(p = index(buf, '\n'))) {
6727315Scharnier			warnx("line too long");
681590Srgrimes			while ((ch = getchar()) != '\n' && ch != EOF);
691590Srgrimes			continue;
701590Srgrimes		}
711590Srgrimes		*p = '\0';
721590Srgrimes		for (p = buf; *p && isspace(*p); ++p);
731590Srgrimes		if (!*p || *p == '#')
741590Srgrimes			continue;
751590Srgrimes		add(p);
761590Srgrimes	}
771590Srgrimes	(void)fclose(fp);
781590Srgrimes}
791590Srgrimes
801590Srgrimesvoid
811590Srgrimesadd(fmt)
8287203Smarkm	const char *fmt;
831590Srgrimes{
8487203Smarkm	unsigned const char *p, *savep;
851590Srgrimes	static FS **nextfs;
861590Srgrimes	FS *tfs;
871590Srgrimes	FU *tfu, **nextfu;
881590Srgrimes
891590Srgrimes	/* start new linked list of format units */
9080290Sobrien	if ((tfs = calloc(1, sizeof(FS))) == NULL)
9180290Sobrien		err(1, NULL);
921590Srgrimes	if (!fshead)
931590Srgrimes		fshead = tfs;
941590Srgrimes	else
951590Srgrimes		*nextfs = tfs;
961590Srgrimes	nextfs = &tfs->nextfs;
971590Srgrimes	nextfu = &tfs->nextfu;
981590Srgrimes
991590Srgrimes	/* take the format string and break it up into format units */
1001590Srgrimes	for (p = fmt;;) {
1011590Srgrimes		/* skip leading white space */
1021590Srgrimes		for (; isspace(*p); ++p);
1031590Srgrimes		if (!*p)
1041590Srgrimes			break;
1051590Srgrimes
1061590Srgrimes		/* allocate a new format unit and link it in */
10780290Sobrien		if ((tfu = calloc(1, sizeof(FU))) == NULL)
10880290Sobrien			err(1, NULL);
1091590Srgrimes		*nextfu = tfu;
1101590Srgrimes		nextfu = &tfu->nextfu;
1111590Srgrimes		tfu->reps = 1;
1121590Srgrimes
1131590Srgrimes		/* if leading digit, repetition count */
1141590Srgrimes		if (isdigit(*p)) {
1151590Srgrimes			for (savep = p; isdigit(*p); ++p);
1161590Srgrimes			if (!isspace(*p) && *p != '/')
1171590Srgrimes				badfmt(fmt);
1181590Srgrimes			/* may overwrite either white space or slash */
1191590Srgrimes			tfu->reps = atoi(savep);
1201590Srgrimes			tfu->flags = F_SETREP;
1211590Srgrimes			/* skip trailing white space */
1221590Srgrimes			for (++p; isspace(*p); ++p);
1231590Srgrimes		}
1241590Srgrimes
1251590Srgrimes		/* skip slash and trailing white space */
1261590Srgrimes		if (*p == '/')
1271590Srgrimes			while (isspace(*++p));
1281590Srgrimes
1291590Srgrimes		/* byte count */
1301590Srgrimes		if (isdigit(*p)) {
1311590Srgrimes			for (savep = p; isdigit(*p); ++p);
1321590Srgrimes			if (!isspace(*p))
1331590Srgrimes				badfmt(fmt);
1341590Srgrimes			tfu->bcnt = atoi(savep);
1351590Srgrimes			/* skip trailing white space */
1361590Srgrimes			for (++p; isspace(*p); ++p);
1371590Srgrimes		}
1381590Srgrimes
1391590Srgrimes		/* format */
1401590Srgrimes		if (*p != '"')
1411590Srgrimes			badfmt(fmt);
1421590Srgrimes		for (savep = ++p; *p != '"';)
1431590Srgrimes			if (*p++ == 0)
1441590Srgrimes				badfmt(fmt);
1451590Srgrimes		if (!(tfu->fmt = malloc(p - savep + 1)))
14680290Sobrien			err(1, NULL);
1471590Srgrimes		(void) strncpy(tfu->fmt, savep, p - savep);
1481590Srgrimes		tfu->fmt[p - savep] = '\0';
1491590Srgrimes		escape(tfu->fmt);
1501590Srgrimes		p++;
1511590Srgrimes	}
1521590Srgrimes}
1531590Srgrimes
15491840Sobrienstatic const char *spec = ".#-+ 0123456789";
1551590Srgrimes
1561590Srgrimesint
1571590Srgrimessize(fs)
1581590Srgrimes	FS *fs;
1591590Srgrimes{
1601590Srgrimes	register FU *fu;
1611590Srgrimes	register int bcnt, cursize;
16230921Sache	register unsigned char *fmt;
1631590Srgrimes	int prec;
1641590Srgrimes
1651590Srgrimes	/* figure out the data block size needed for each format unit */
1661590Srgrimes	for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
1671590Srgrimes		if (fu->bcnt) {
1681590Srgrimes			cursize += fu->bcnt * fu->reps;
1691590Srgrimes			continue;
1701590Srgrimes		}
1711590Srgrimes		for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) {
1721590Srgrimes			if (*fmt != '%')
1731590Srgrimes				continue;
1741590Srgrimes			/*
1751590Srgrimes			 * skip any special chars -- save precision in
1761590Srgrimes			 * case it's a %s format.
1771590Srgrimes			 */
1781590Srgrimes			while (index(spec + 1, *++fmt));
1791590Srgrimes			if (*fmt == '.' && isdigit(*++fmt)) {
1801590Srgrimes				prec = atoi(fmt);
1811590Srgrimes				while (isdigit(*++fmt));
1821590Srgrimes			}
1831590Srgrimes			switch(*fmt) {
1841590Srgrimes			case 'c':
1851590Srgrimes				bcnt += 1;
1861590Srgrimes				break;
1871590Srgrimes			case 'd': case 'i': case 'o': case 'u':
1881590Srgrimes			case 'x': case 'X':
1891590Srgrimes				bcnt += 4;
1901590Srgrimes				break;
1911590Srgrimes			case 'e': case 'E': case 'f': case 'g': case 'G':
1921590Srgrimes				bcnt += 8;
1931590Srgrimes				break;
1941590Srgrimes			case 's':
1951590Srgrimes				bcnt += prec;
1961590Srgrimes				break;
1971590Srgrimes			case '_':
1981590Srgrimes				switch(*++fmt) {
1991590Srgrimes				case 'c': case 'p': case 'u':
2001590Srgrimes					bcnt += 1;
2011590Srgrimes					break;
2021590Srgrimes				}
2031590Srgrimes			}
2041590Srgrimes		}
2051590Srgrimes		cursize += bcnt * fu->reps;
2061590Srgrimes	}
2071590Srgrimes	return (cursize);
2081590Srgrimes}
2091590Srgrimes
2101590Srgrimesvoid
2111590Srgrimesrewrite(fs)
2121590Srgrimes	FS *fs;
2131590Srgrimes{
2141590Srgrimes	enum { NOTOKAY, USEBCNT, USEPREC } sokay;
2151590Srgrimes	register PR *pr, **nextpr;
2161590Srgrimes	register FU *fu;
21730921Sache	unsigned char *p1, *p2, *fmtp;
21830921Sache	char savech, cs[3];
2191590Srgrimes	int nconv, prec;
2201590Srgrimes
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';
39880290Sobrien			if ((pr->fmt = calloc(1, strlen(fmtp) + 2)) == NULL)
39980290Sobrien				err(1, NULL);
4001590Srgrimes			(void)strcpy(pr->fmt, fmtp);
4011590Srgrimes			(void)strcat(pr->fmt, 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
4521590Srgrimesescape(p1)
4531590Srgrimes	register char *p1;
4541590Srgrimes{
4551590Srgrimes	register char *p2;
4561590Srgrimes
4571590Srgrimes	/* alphabetic escape sequences have to be done in place */
4581590Srgrimes	for (p2 = p1;; ++p1, ++p2) {
4591590Srgrimes		if (!*p1) {
4601590Srgrimes			*p2 = *p1;
4611590Srgrimes			break;
4621590Srgrimes		}
4631590Srgrimes		if (*p1 == '\\')
4641590Srgrimes			switch(*++p1) {
4651590Srgrimes			case 'a':
4661590Srgrimes			     /* *p2 = '\a'; */
4671590Srgrimes				*p2 = '\007';
4681590Srgrimes				break;
4691590Srgrimes			case 'b':
4701590Srgrimes				*p2 = '\b';
4711590Srgrimes				break;
4721590Srgrimes			case 'f':
4731590Srgrimes				*p2 = '\f';
4741590Srgrimes				break;
4751590Srgrimes			case 'n':
4761590Srgrimes				*p2 = '\n';
4771590Srgrimes				break;
4781590Srgrimes			case 'r':
4791590Srgrimes				*p2 = '\r';
4801590Srgrimes				break;
4811590Srgrimes			case 't':
4821590Srgrimes				*p2 = '\t';
4831590Srgrimes				break;
4841590Srgrimes			case 'v':
4851590Srgrimes				*p2 = '\v';
4861590Srgrimes				break;
4871590Srgrimes			default:
4881590Srgrimes				*p2 = *p1;
4891590Srgrimes				break;
4901590Srgrimes			}
4911590Srgrimes	}
4921590Srgrimes}
4931590Srgrimes
4941590Srgrimesvoid
4951590Srgrimesbadcnt(s)
4961590Srgrimes	char *s;
4971590Srgrimes{
49827315Scharnier	errx(1, "%s: bad byte count", s);
4991590Srgrimes}
5001590Srgrimes
5011590Srgrimesvoid
5021590Srgrimesbadsfmt()
5031590Srgrimes{
50427315Scharnier	errx(1, "%%s: requires a precision or a byte count");
5051590Srgrimes}
5061590Srgrimes
5071590Srgrimesvoid
5081590Srgrimesbadfmt(fmt)
50987203Smarkm	const char *fmt;
5101590Srgrimes{
51127315Scharnier	errx(1, "\"%s\": bad format", fmt);
5121590Srgrimes}
5131590Srgrimes
5141590Srgrimesvoid
5151590Srgrimesbadconv(ch)
5161590Srgrimes	char *ch;
5171590Srgrimes{
51827315Scharnier	errx(1, "%%%s: bad conversion character", ch);
5191590Srgrimes}
520