Index: head/usr.bin/hexdump/hexdump.h =================================================================== --- head/usr.bin/hexdump/hexdump.h (revision 346186) +++ head/usr.bin/hexdump/hexdump.h (revision 346187) @@ -1,106 +1,107 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)hexdump.h 8.1 (Berkeley) 6/6/93 * $FreeBSD$ */ #include typedef struct _pr { struct _pr *nextpr; /* next print unit */ #define F_ADDRESS 0x001 /* print offset */ #define F_BPAD 0x002 /* blank pad */ #define F_C 0x004 /* %_c */ #define F_CHAR 0x008 /* %c */ #define F_DBL 0x010 /* %[EefGf] */ #define F_INT 0x020 /* %[di] */ #define F_P 0x040 /* %_p */ #define F_STR 0x080 /* %s */ #define F_U 0x100 /* %_u */ #define F_UINT 0x200 /* %[ouXx] */ #define F_TEXT 0x400 /* no conversions */ u_int flags; /* flag values */ int bcnt; /* byte count */ char *cchar; /* conversion character */ char *fmt; /* printf format */ char *nospace; /* no whitespace version */ int mbleft; /* bytes left of multibyte char. */ mbstate_t mbstate; /* conversion state */ } PR; typedef struct _fu { struct _fu *nextfu; /* next format unit */ struct _pr *nextpr; /* next print unit */ #define F_IGNORE 0x01 /* %_A */ #define F_SETREP 0x02 /* rep count set, not default */ u_int flags; /* flag values */ int reps; /* repetition count */ int bcnt; /* byte count */ char *fmt; /* format string */ } FU; typedef struct _fs { /* format strings */ struct _fs *nextfs; /* linked list of format strings */ struct _fu *nextfu; /* linked list of format units */ int bcnt; } FS; extern FS *fshead; /* head of format strings list */ extern FU *endfu; /* format at end-of-data */ extern int blocksize; /* data block size */ extern int exitval; /* final exit value */ extern int odmode; /* are we acting as od(1)? */ extern int length; /* amount of data to read */ extern off_t skip; /* amount of data to skip at start */ enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */ extern enum _vflag vflag; void add(const char *); void addfile(const char *); void badcnt(const char *); void badconv(const char *); void badfmt(const char *); +void badnoconv(void); void badsfmt(void); void bpad(PR *); void conv_c(PR *, u_char *, size_t); void conv_u(PR *, u_char *); void display(void); void doskip(const char *, int); void escape(char *); u_char *get(void); void newsyntax(int, char ***); int next(char **); void nomem(void); void oldsyntax(int, char ***); size_t peek(u_char *, size_t); void rewrite(FS *); int size(FS *); void usage(void); Index: head/usr.bin/hexdump/parse.c =================================================================== --- head/usr.bin/hexdump/parse.c (revision 346186) +++ head/usr.bin/hexdump/parse.c (revision 346187) @@ -1,514 +1,529 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include "hexdump.h" FU *endfu; /* format at end-of-data */ void addfile(const char *name) { unsigned char *p; FILE *fp; int ch; char buf[2048 + 1]; if ((fp = fopen(name, "r")) == NULL) err(1, "%s", name); while (fgets(buf, sizeof(buf), fp)) { if (!(p = strchr(buf, '\n'))) { warnx("line too long"); while ((ch = getchar()) != '\n' && ch != EOF); continue; } *p = '\0'; for (p = buf; *p && isspace(*p); ++p); if (!*p || *p == '#') continue; add(p); } (void)fclose(fp); } void add(const char *fmt) { unsigned const char *p, *savep; static FS **nextfs; FS *tfs; FU *tfu, **nextfu; /* start new linked list of format units */ if ((tfs = calloc(1, sizeof(FS))) == NULL) err(1, NULL); if (!fshead) fshead = tfs; else *nextfs = tfs; nextfs = &tfs->nextfs; nextfu = &tfs->nextfu; /* take the format string and break it up into format units */ for (p = fmt;;) { /* skip leading white space */ for (; isspace(*p); ++p); if (!*p) break; /* allocate a new format unit and link it in */ if ((tfu = calloc(1, sizeof(FU))) == NULL) err(1, NULL); *nextfu = tfu; nextfu = &tfu->nextfu; tfu->reps = 1; /* if leading digit, repetition count */ if (isdigit(*p)) { for (savep = p; isdigit(*p); ++p); if (!isspace(*p) && *p != '/') badfmt(fmt); /* may overwrite either white space or slash */ tfu->reps = atoi(savep); tfu->flags = F_SETREP; /* skip trailing white space */ for (++p; isspace(*p); ++p); } /* skip slash and trailing white space */ if (*p == '/') while (isspace(*++p)); /* byte count */ if (isdigit(*p)) { for (savep = p; isdigit(*p); ++p); if (!isspace(*p)) badfmt(fmt); tfu->bcnt = atoi(savep); /* skip trailing white space */ for (++p; isspace(*p); ++p); } /* format */ if (*p != '"') badfmt(fmt); for (savep = ++p; *p != '"';) if (*p++ == 0) badfmt(fmt); if (!(tfu->fmt = malloc(p - savep + 1))) err(1, NULL); (void) strlcpy(tfu->fmt, savep, p - savep + 1); escape(tfu->fmt); p++; } } static const char *spec = ".#-+ 0123456789"; int size(FS *fs) { FU *fu; int bcnt, cursize; unsigned char *fmt; int prec; /* figure out the data block size needed for each format unit */ for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { if (fu->bcnt) { cursize += fu->bcnt * fu->reps; continue; } for (bcnt = prec = 0, fmt = fu->fmt; *fmt; ++fmt) { if (*fmt != '%') continue; /* * skip any special chars -- save precision in * case it's a %s format. */ - while (strchr(spec + 1, *++fmt)); + while (*++fmt != 0 && strchr(spec + 1, *fmt) != NULL) + ; + if (*fmt == 0) + badnoconv(); if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); while (isdigit(*++fmt)); } switch(*fmt) { case 'c': bcnt += 1; break; case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': bcnt += 4; break; case 'e': case 'E': case 'f': case 'g': case 'G': bcnt += 8; break; case 's': bcnt += prec; break; case '_': switch(*++fmt) { case 'c': case 'p': case 'u': bcnt += 1; break; } } } cursize += bcnt * fu->reps; } return (cursize); } void rewrite(FS *fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; PR *pr, **nextpr; FU *fu; unsigned char *p1, *p2, *fmtp; char savech, cs[3]; int nconv, prec; prec = 0; for (fu = fs->nextfu; fu; fu = fu->nextfu) { /* * Break each format unit into print units; each conversion * character gets its own. */ nextpr = &fu->nextpr; for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { if ((pr = calloc(1, sizeof(PR))) == NULL) err(1, NULL); *nextpr = pr; /* Skip preceding text and up to the next % sign. */ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1); /* Only text in the string. */ if (!*p1) { pr->fmt = fmtp; pr->flags = F_TEXT; break; } /* * Get precision for %s -- if have a byte count, don't * need it. */ if (fu->bcnt) { sokay = USEBCNT; /* Skip to conversion character. */ - for (++p1; strchr(spec, *p1); ++p1); + while (*++p1 != 0 && strchr(spec, *p1) != NULL) + ; + if (*p1 == 0) + badnoconv(); } else { /* Skip any special chars, field width. */ - while (strchr(spec + 1, *++p1)); + while (*++p1 != 0 && strchr(spec + 1, *p1) != NULL) + ; + if (*p1 == 0) + badnoconv(); if (*p1 == '.' && isdigit(*++p1)) { sokay = USEPREC; prec = atoi(p1); while (isdigit(*++p1)); } else sokay = NOTOKAY; } p2 = *p1 ? p1 + 1 : p1; /* Set end pointer -- make sure * that it's non-NUL/-NULL first * though. */ cs[0] = *p1; /* Set conversion string. */ cs[1] = '\0'; /* * Figure out the byte count for each conversion; * rewrite the format as necessary, set up blank- * padding for end of data. */ switch(cs[0]) { case 'c': pr->flags = F_CHAR; switch(fu->bcnt) { case 0: case 1: pr->bcnt = 1; break; default: p1[1] = '\0'; badcnt(p1); } break; case 'd': case 'i': pr->flags = F_INT; goto isint; case 'o': case 'u': case 'x': case 'X': pr->flags = F_UINT; isint: cs[2] = '\0'; cs[1] = cs[0]; cs[0] = 'q'; switch(fu->bcnt) { case 0: case 4: pr->bcnt = 4; break; case 1: pr->bcnt = 1; break; case 2: pr->bcnt = 2; break; default: p1[1] = '\0'; badcnt(p1); } break; case 'e': case 'E': case 'f': case 'g': case 'G': pr->flags = F_DBL; switch(fu->bcnt) { case 0: case 8: pr->bcnt = 8; break; case 4: pr->bcnt = 4; break; default: if (fu->bcnt == sizeof(long double)) { cs[2] = '\0'; cs[1] = cs[0]; cs[0] = 'L'; pr->bcnt = sizeof(long double); } else { p1[1] = '\0'; badcnt(p1); } } break; case 's': pr->flags = F_STR; switch(sokay) { case NOTOKAY: badsfmt(); case USEBCNT: pr->bcnt = fu->bcnt; break; case USEPREC: pr->bcnt = prec; break; } break; case '_': ++p2; switch(p1[1]) { case 'A': endfu = fu; fu->flags |= F_IGNORE; /* FALLTHROUGH */ case 'a': pr->flags = F_ADDRESS; ++p2; switch(p1[2]) { case 'd': case 'o': case'x': cs[0] = 'q'; cs[1] = p1[2]; cs[2] = '\0'; break; default: p1[3] = '\0'; badconv(p1); } break; case 'c': pr->flags = F_C; /* cs[0] = 'c'; set in conv_c */ goto isint2; case 'p': pr->flags = F_P; cs[0] = 'c'; goto isint2; case 'u': pr->flags = F_U; /* cs[0] = 'c'; set in conv_u */ isint2: switch(fu->bcnt) { case 0: case 1: pr->bcnt = 1; break; default: p1[2] = '\0'; badcnt(p1); } break; default: p1[2] = '\0'; badconv(p1); } break; default: p1[1] = '\0'; badconv(p1); } /* * Copy to PR format string, set conversion character * pointer, update original. */ savech = *p2; p1[0] = '\0'; if (asprintf(&pr->fmt, "%s%s", fmtp, cs) == -1) err(1, NULL); *p2 = savech; pr->cchar = pr->fmt + (p1 - fmtp); fmtp = p2; /* Only one conversion character if byte count. */ if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++) errx(1, "byte count with multiple conversion characters"); } /* * If format unit byte count not specified, figure it out * so can adjust rep count later. */ if (!fu->bcnt) for (pr = fu->nextpr; pr; pr = pr->nextpr) fu->bcnt += pr->bcnt; } /* * If the format string interprets any data at all, and it's * not the same as the blocksize, and its last format unit * interprets any data at all, and has no iteration count, * repeat it as necessary. * * If, rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ for (fu = fs->nextfu; fu; fu = fu->nextfu) { if (!fu->nextfu && fs->bcnt < blocksize && !(fu->flags&F_SETREP) && fu->bcnt) fu->reps += (blocksize - fs->bcnt) / fu->bcnt; if (fu->reps > 1) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; for (p1 = pr->fmt, p2 = NULL; *p1; ++p1) p2 = isspace(*p1) ? p1 : NULL; if (p2) pr->nospace = p2; } } #ifdef DEBUG for (fu = fs->nextfu; fu; fu = fu->nextfu) { (void)printf("fmt:"); for (pr = fu->nextpr; pr; pr = pr->nextpr) (void)printf(" {%s}", pr->fmt); (void)printf("\n"); } #endif } void escape(char *p1) { char *p2; /* alphabetic escape sequences have to be done in place */ for (p2 = p1;; p1++, p2++) { if (*p1 == '\\') { p1++; switch(*p1) { case '\0': *p2 = '\\'; *++p2 = '\0'; return; case 'a': /* *p2 = '\a'; */ *p2 = '\007'; break; case 'b': *p2 = '\b'; break; case 'f': *p2 = '\f'; break; case 'n': *p2 = '\n'; break; case 'r': *p2 = '\r'; break; case 't': *p2 = '\t'; break; case 'v': *p2 = '\v'; break; default: *p2 = *p1; break; } } else { *p2 = *p1; if (*p1 == '\0') return; } } } void badcnt(const char *s) { errx(1, "%s: bad byte count", s); } void badsfmt(void) { errx(1, "%%s: requires a precision or a byte count"); } void badfmt(const char *fmt) { errx(1, "\"%s\": bad format", fmt); } void badconv(const char *ch) { errx(1, "%%%s: bad conversion character", ch); +} + +void +badnoconv(void) +{ + errx(1, "missing conversion character"); } Index: head/usr.bin/hexdump/tests/hexdump_test.sh =================================================================== --- head/usr.bin/hexdump/tests/hexdump_test.sh (revision 346186) +++ head/usr.bin/hexdump/tests/hexdump_test.sh (revision 346187) @@ -1,191 +1,205 @@ # # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2017 Kyle Evans # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ atf_test_case b_flag b_flag_head() { atf_set "descr" "Verify -b output" } b_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_bflag_a.out" \ hexdump -b "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_bflag_b.out" \ hexdump -b "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_bflag_c.out" \ hexdump -b "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case c_flag c_flag_head() { atf_set "descr" "Verify -c output" } c_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_cflag_a.out" \ hexdump -c "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_cflag_b.out" \ hexdump -c "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_cflag_c.out" \ hexdump -c "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case C_flag C_flag_head() { atf_set "descr" "Verify -C output" } C_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_a.out" \ hexdump -C "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_b.out" \ hexdump -C "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_c.out" \ hexdump -C "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case hd_name hd_name_head() { atf_set "descr" "Verify hd output matching -C output" } hd_name_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_a.out" \ hd "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_b.out" \ hd "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_UCflag_c.out" \ hd "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case d_flag d_flag_head() { atf_set "descr" "Verify -d output" } d_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_dflag_a.out" \ hexdump -d "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_dflag_b.out" \ hexdump -d "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_dflag_c.out" \ hexdump -d "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case n_flag n_flag_head() { atf_set "descr" "Check -n functionality" } n_flag_body() { atf_check -o empty hexdump -bn 0 "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_nflag_a.out" \ hexdump -bn 1 "$(atf_get_srcdir)/d_hexdump_a.in" } atf_test_case o_flag o_flag_head() { atf_set "descr" "Verify -o output" } o_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_oflag_a.out" \ hexdump -o "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_oflag_b.out" \ hexdump -o "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_oflag_c.out" \ hexdump -o "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case s_flag s_flag_head() { atf_set "descr" "Verify -s output" } s_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_sflag_a.out" \ hexdump -bs 4 "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o not-empty hexdump -n 100 -s 1024 /dev/random } atf_test_case v_flag v_flag_head() { atf_set "descr" "Verify -v functionality" } v_flag_body() { for i in $(seq 0 7); do atf_check -o match:"^\*$" \ hexdump -s ${i} "$(atf_get_srcdir)/d_hexdump_c.in" atf_check -o not-match:"^\*$" \ hexdump -vs ${i} "$(atf_get_srcdir)/d_hexdump_c.in" done atf_check -o not-match:"^\*$" \ hexdump -s 8 "$(atf_get_srcdir)/d_hexdump_c.in" atf_check -o not-match:"^\*$" \ hexdump -vs 8 "$(atf_get_srcdir)/d_hexdump_c.in" } atf_test_case x_flag x_flag_head() { atf_set "descr" "Verify -x output" } x_flag_body() { atf_check -o file:"$(atf_get_srcdir)/d_hexdump_xflag_a.out" \ hexdump -x "$(atf_get_srcdir)/d_hexdump_a.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_xflag_b.out" \ hexdump -x "$(atf_get_srcdir)/d_hexdump_b.in" atf_check -o file:"$(atf_get_srcdir)/d_hexdump_xflag_c.out" \ hexdump -x "$(atf_get_srcdir)/d_hexdump_c.in" } +atf_test_case no_conv_err +no_conv_err() +{ + atf_set "descr" "Verify missing conversion char error handling" +} +no_conv_err_body() +{ + atf_check -s exit:1 -e ignore \ + hexdump -e '"%"' + atf_check -s exit:1 -e ignore \ + hexdump -e '4/2 "%"' +} + atf_init_test_cases() { atf_add_test_case b_flag atf_add_test_case c_flag atf_add_test_case C_flag atf_add_test_case hd_name atf_add_test_case d_flag atf_add_test_case n_flag atf_add_test_case o_flag atf_add_test_case s_flag atf_add_test_case v_flag atf_add_test_case x_flag + atf_add_test_case no_conv_err }