X-Git-Url: https://git.distorted.org.uk/~mdw/mLib/blobdiff_plain/13ee740655965453b2f3fcd7093d2d8b13839903..5c0f2e080603967952db43eb7b12d44dd64f7169:/test/tvec-types.c diff --git a/test/tvec-types.c b/test/tvec-types.c index 20c2930..dc70dbd 100644 --- a/test/tvec-types.c +++ b/test/tvec-types.c @@ -173,6 +173,7 @@ static int signed_from_buf(buf *b, long *i_out) * @const struct tvec_irange *ir@ = range specification, * or null * @struct tvec_state *tv@ = test vector state + * @const char *what@ = description of value * * Returns: Zero on success, or @-1@ on error. * @@ -182,11 +183,11 @@ static int signed_from_buf(buf *b, long *i_out) static int check_signed_range(long i, const struct tvec_irange *ir, - struct tvec_state *tv) + struct tvec_state *tv, const char *what) { if (ir && (ir->min > i || i > ir->max)) { - tvec_error(tv, "integer %ld out of range (must be in [%ld .. %ld])", - i, ir->min, ir->max); + tvec_error(tv, "%s %ld out of range (must be in [%ld .. %ld])", + what, i, ir->min, ir->max); return (-1); } return (0); @@ -194,11 +195,11 @@ static int check_signed_range(long i, static int check_unsigned_range(unsigned long u, const struct tvec_urange *ur, - struct tvec_state *tv) + struct tvec_state *tv, const char *what) { if (ur && (ur->min > u || u > ur->max)) { - tvec_error(tv, "integer %lu out of range (must be in [%lu .. %lu])", - u, ur->min, ur->max); + tvec_error(tv, "%s %lu out of range (must be in [%lu .. %lu])", + what, u, ur->min, ur->max); return (-1); } return (0); @@ -370,7 +371,7 @@ static int parse_unsigned(unsigned long *u_out, const char *p, if (parse_unsigned_integer(&u, &q, p)) return (tvec_error(tv, "invalid unsigned integer `%s'", p)); if (*q) return (tvec_syntax(tv, *q, "end-of-line")); - if (check_unsigned_range(u, ur, tv)) return (-1); + if (check_unsigned_range(u, ur, tv, "integer")) return (-1); *u_out = u; return (0); } @@ -384,15 +385,15 @@ static int parse_signed(long *i_out, const char *p, if (parse_signed_integer(&i, &q, p)) return (tvec_error(tv, "invalid signed integer `%s'", p)); if (*q) return (tvec_syntax(tv, *q, "end-of-line")); - if (check_signed_range(i, ir, tv)) return (-1); + if (check_signed_range(i, ir, tv, "integer")) return (-1); *i_out = i; return (0); } static const char size_units[] = "kMGTPEZY"; -/* --- @parse_size@ --- * +/* --- @parse_szint@ --- * * * Arguments: @struct tvec_state *tv@ = test-vector state - * @size_t *u_out@ = where to put the answer + * @unsigned long *u_out@ = where to put the answer * @const char *delims@ = delimiters * @const char *what@ = description of what we're parsing * @@ -401,8 +402,8 @@ static const char size_units[] = "kMGTPEZY"; * Use: Parse a memory size. */ -static int parse_size(struct tvec_state *tv, size_t *u_out, - const char *delims, const char *what) +static int parse_szint(struct tvec_state *tv, unsigned long *u_out, + const char *delims, const char *what) { dstr d = DSTR_INIT; const char *p, *unit; @@ -416,9 +417,8 @@ static int parse_size(struct tvec_state *tv, size_t *u_out, if (parse_unsigned_integer(&u, &p, p)) goto bad; if (!*p) tvec_readword(tv, &d, &p, delims, 0); - if (u > (size_t)-1) goto rangerr; for (t = u, unit = size_units; *unit; unit++) { - if (t > (size_t)-1/1024) f |= f_range; + if (t > ULONG_MAX/1024) f |= f_range; else t *= 1024; if (*p == *unit) { if (f&f_range) goto rangerr; @@ -462,7 +462,9 @@ static void format_size(const struct gprintf_ops *gops, void *go, { const char *unit; - if (!u || u%1024) + if (style&TVSF_RAW) + gprintf(gops, go, "%lu", u); + else if (!u || u%1024) gprintf(gops, go, "%lu%sB", u, style&TVSF_COMPACT ? "" : " "); else { for (unit = size_units, u /= 1024; @@ -479,8 +481,8 @@ static void format_size(const struct gprintf_ops *gops, void *go, * Arguments: @double x, y@ = two numbers to compare * @const struct tvec_floatinfo *fi@ = floating-point info * - * Returns: Nonzero if the comparand @y@ is sufficiently close to the - * reference @x@, or zero if it's definitely different. + * Returns: Nonzero if the comparand @x@ is sufficiently close to the + * reference @y@, or zero if it's definitely different. */ static int eqish_floating_p(double x, double y, @@ -497,7 +499,7 @@ static int eqish_floating_p(double x, double y, case TVFF_ABSDELTA: t = x - y; if (t < 0) t = -t; return (t < fi->delta); case TVFF_RELDELTA: - t = 1.0 - y/x; if (t < 0) t = -t; return (t < fi->delta); + t = 1.0 - x/y; if (t < 0) t = -t; return (t < fi->delta); default: abort(); } @@ -1220,6 +1222,7 @@ static int read_compound_string(void **p_inout, size_t *sz_inout, if (cdc && flush_codec(cdc, &d, tv)) { rc = -1; goto end; } cdc = 0; DRESET(&w); tvec_readword(tv, &w, 0, ";", "character name"); + if (STRCMP(w.buf, ==, "#empty")) break; if (read_charname(&ch, w.buf, RCF_EOFOK)) { rc = tvec_error(tv, "unknown character name `%s'", d.buf); goto end; @@ -1502,9 +1505,9 @@ static void dump_int(const union tvec_regval *rv, unsigned style, const struct gprintf_ops *gops, void *go) { - + if (style&TVSF_RAW) gprintf(gops, go, "int:"); gprintf(gops, go, "%ld", rv->i); - if (!(style&TVSF_COMPACT)) { + if (!(style&(TVSF_COMPACT | TVSF_RAW))) { gprintf(gops, go, " ; = "); format_signed_hex(gops, go, rv->i); maybe_format_signed_char(gops, go, rv->i); @@ -1516,8 +1519,9 @@ static void dump_uint(const union tvec_regval *rv, unsigned style, const struct gprintf_ops *gops, void *go) { + if (style&TVSF_RAW) gprintf(gops, go, "uint:"); gprintf(gops, go, "%lu", rv->u); - if (!(style&TVSF_COMPACT)) { + if (!(style&(TVSF_COMPACT | TVSF_RAW))) { gprintf(gops, go, " ; = "); format_unsigned_hex(gops, go, rv->u); maybe_format_unsigned_char(gops, go, rv->u); @@ -1604,6 +1608,100 @@ int tvec_claimeq_uint(struct tvec_state *tv, return (tvec_claimeq(tv, &tvty_uint, 0, file, lno, expr)); } +/*----- Size type ---------------------------------------------------------*/ + +/* --- @parse_size@ --- * + * + * Arguments: @union tvec_regval *rv@ = register value + * @const struct tvec_regdef *rd@ = register definition + * @struct tvec_state *tv@ = test-vector state + * + * Returns: Zero on success, %$-1$% on error. + * + * Use: Parse a register value from an input file. + * + * The input format for a size value consists of an unsigned + * integer followed by an optional unit specifier consisting of + * an SI unit prefix and (optionally) the letter `B'. */ + +static int parse_size(union tvec_regval *rv, const struct tvec_regdef *rd, + struct tvec_state *tv) +{ + unsigned long sz; + int rc; + + if (parse_szint(tv, &sz, ";", "size")) { rc = -1; goto end; } + if (check_unsigned_range(sz, rd->arg.p, tv, "size")) { rc = -1; goto end; } + if (tvec_flushtoeol(tv, 0)) { rc = -1; goto end; } + rv->u = sz; rc = 0; +end: + return (rc); +} + +/* --- @dump_size@ --- * + * + * Arguments: @const union tvec_regval *rv@ = register value + * @const struct tvec_regdef *rd@ = register definition + * @unsigned style@ = output style (@TVSF_...@) + * @const struct gprintf_ops *gops@, @void *gp@ = format output + * + * Returns: --- + * + * Use: Dump a register value to the format output. + * + * Size values are dumped with a unit specifier, with a unit + * prefox only if the size is an exact multiple of the relevant + * power of two. Unless compact style is requested, the plain + * decimal and hex representations of the value are also + * printed. + */ + +static void dump_size(const union tvec_regval *rv, + const struct tvec_regdef *rd, + unsigned style, + const struct gprintf_ops *gops, void *go) +{ + if (style&TVSF_RAW) gprintf(gops, go, "size:"); + format_size(gops, go, rv->u, style); + if (!(style&(TVSF_COMPACT | TVSF_RAW))) { + gprintf(gops, go, " ; = %lu", (unsigned long)rv->u); + gprintf(gops, go, " = "); format_unsigned_hex(gops, go, rv->u); + maybe_format_unsigned_char(gops, go, rv->u); + } +} + +/* Size type definitions. */ +const struct tvec_regty tvty_size = { + init_uint, trivial_release, eq_uint, + tobuf_uint, frombuf_uint, + parse_size, dump_size +}; + +/* --- @tvec_claimeq_size@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * @unsigned long sz0, sz1@ = two sizes + * @const char *file@, @unsigned @lno@ = calling file and line + * @const char *expr@ = the expression to quote on failure + * + * Returns: Nonzero if @sz0@ and @sz1@ are equal, otherwise zero. + * + * Use: Check that values of @u0@ and @u1@ are equal. As for + * @tvec_claim@ above, a test case is automatically begun and + * ended if none is already underway. If the values are + * unequal, then @tvec_fail@ is called, quoting @expr@, and the + * mismatched values are dumped: @u0@ is printed as the output + * value and @u1@ is printed as the input reference. + */ + +int tvec_claimeq_size(struct tvec_state *tv, + unsigned long sz0, unsigned long sz1, + const char *file, unsigned lno, const char *expr) +{ + tv->out[0].v.u = sz0; tv->in[0].v.u = sz1; + return (tvec_claimeq(tv, &tvty_size, 0, file, lno, expr)); +} + /*----- Floating-point type -----------------------------------------------*/ /* --- @int_float@ --- * @@ -1731,7 +1829,10 @@ static void dump_float(const union tvec_regval *rv, const struct tvec_regdef *rd, unsigned style, const struct gprintf_ops *gops, void *go) - { format_floating(gops, go, rv->f); } +{ + if (style&TVSF_RAW) gprintf(gops, go, "float:"); + format_floating(gops, go, rv->f); +} /* Floating-point type definition. */ const struct tvec_regty tvty_float = { @@ -1754,7 +1855,7 @@ const struct tvec_floatinfo * @const char *file@, @unsigned @lno@ = calling file and line * @const char *expr@ = the expression to quote on failure * - * Returns: Nonzero if @f0@ and @u1@ are sufficiently close, otherwise + * Returns: Nonzero if @f0@ and @f1@ are sufficiently close, otherwise * zero. * * Use: Check that values of @f0@ and @f1@ are sufficiently close. @@ -1781,8 +1882,11 @@ const struct tvec_floatinfo * %$y$% when %$|x - y| < \delta$%. * * * If @f&TVFF_EQMASK@ is @TVFF_RELDELTA@, then %$x$% matches - * %$y$% when %$|1 - y/x| < \delta$%. (Note that this - * criterion is asymmetric FIXME + * %$y$% when %$|1 - x/y| < \delta$%. (Note that this + * criterion is asymmetric. Write %$x \approx_\delta y$% + * if and only if %$|1 - x/y < \delta$%. Then, for example, + * if %$y/(1 + \delta) < x < y (1 - \delta)$%, then + * %$x \approx_\delta y$%, but %$y \not\approx_\delta x$%.) */ int tvec_claimeqish_float(struct tvec_state *tv, @@ -1805,7 +1909,7 @@ int tvec_claimeqish_float(struct tvec_state *tv, * @const char *file@, @unsigned @lno@ = calling file and line * @const char *expr@ = the expression to quote on failure * - * Returns: Nonzero if @f0@ and @u1@ are identical, otherwise zero. + * Returns: Nonzero if @f0@ and @f1@ are identical, otherwise zero. * * Use: Check that values of @f0@ and @f1@ are identical. The * function is exactly equivalent to @tvec_claimeqish_float@ @@ -1971,17 +2075,23 @@ static void dump_duration(const union tvec_regval *rv, const struct duration_unit *u; double t = rv->f; - if (!t) u = 0; - else { - for (u = duration_units; u->scale > t && u[1].unit; u++); - t /= u->scale; - } - - gprintf(gops, go, "%.4g %s", t, u ? u->unit : "s"); - if (!(style&TVSF_COMPACT)) { - gprintf(gops, go, "; = "); + if (style&TVSF_RAW) { + gprintf(gops, go, "duration:"); format_floating(gops, go, rv->f); - gprintf(gops, go, " s"); + gprintf(gops, go, "s"); + } else { + if (!t) u = 0; + else { + for (u = duration_units; u->scale > t && u[1].unit; u++); + t /= u->scale; + } + gprintf(gops, go, "%.4g %s", t, u ? u->unit : "s"); + + if (!(style&TVSF_COMPACT)) { + gprintf(gops, go, "; = "); + format_floating(gops, go, rv->f); + gprintf(gops, go, " s"); + } } } @@ -1992,6 +2102,59 @@ const struct tvec_regty tvty_duration = { parse_duration, dump_duration }; +/* --- @tvec_claimeqish_duration@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * @double to, t1@ = two durations + * @unsigned f@ = flags (@TVFF_...@) + * @double delta@ = maximum tolerable difference + * @const char *file@, @unsigned @lno@ = calling file and line + * @const char *expr@ = the expression to quote on failure + * + * Returns: Nonzero if @t0@ and @t1@ are sufficiently close, otherwise + * zero. + * + * Use: Check that values of @t0@ and @t1@ are sufficiently close. + * This is essentially the same as @tvec_claimeqish_float@, only + * it dumps the values as durations on a mismatch. + */ + +int tvec_claimeqish_duration(struct tvec_state *tv, + double t0, double t1, unsigned f, double delta, + const char *file, unsigned lno, + const char *expr) +{ + struct tvec_floatinfo fi; + union tvec_misc arg; + + fi.f = f; fi.min = fi.max = 0.0; fi.delta = delta; arg.p = &fi; + tv->out[0].v.f = t0; tv->in[0].v.f = t1; + return (tvec_claimeq(tv, &tvty_duration, &arg, file, lno, expr)); +} + +/* --- @tvec_claimeq_duration@ --- * + * + * Arguments: @struct tvec_state *tv@ = test-vector state + * @double t0, t1@ = two durations + * @const char *file@, @unsigned @lno@ = calling file and line + * @const char *expr@ = the expression to quote on failure + * + * Returns: Nonzero if @t0@ and @t1@ are identical, otherwise zero. + * + * Use: Check that values of @t0@ and @t1@ are identical. The + * function is exactly equivalent to @tvec_claimeqish_duration@ + * with @f == TVFF_EXACT@. + */ + +int tvec_claimeq_duration(struct tvec_state *tv, + double t0, double t1, + const char *file, unsigned lno, + const char *expr) +{ + return (tvec_claimeqish_duration(tv, t0, t1, TVFF_EXACT, 0.0, + file, lno, expr)); +} + /*----- Enumerations ------------------------------------------------------*/ /* --- @init_tenum@ --- * @@ -2145,7 +2308,8 @@ static int frombuf_penum(buf *b, union tvec_regval *rv, dstr d = DSTR_INIT; \ int rc; \ \ - if (tvec_readword(tv, &d, 0, ";", "enumeration tag or " LITSTR_##tag_)) \ + if (tvec_readword(tv, &d, 0, \ + ";", "%s tag or " LITSTR_##tag_, ei->name)) \ { rc = -1; goto end; } \ for (a = ei->av; a->tag; a++) \ if (STRCMP(a->tag, ==, d.buf)) { FOUND_##tag_ goto done; } \ @@ -2234,6 +2398,7 @@ TVEC_MISCSLOTS(DEFPARSE_ENUM) const struct tvec_##slot##enuminfo *ei = rd->arg.p; \ const struct tvec_##slot##assoc *a; \ \ + if (style&TVSF_RAW) gprintf(gops, go, #slot "enum/%s:", ei->name); \ for (a = ei->av; a->tag; a++) \ if (rv->slot == a->slot) { \ gprintf(gops, go, "%s", a->tag); \ @@ -2406,7 +2571,7 @@ static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd, /* Read the next item. */ DRESET(&d); - if (tvec_readword(tv, &d, 0, "|;", "flag name or integer")) + if (tvec_readword(tv, &d, 0, "|;", "%s flag name or integer", fi->name)) { rc = -1; goto end; } /* Try to find a matching entry in the table. */ @@ -2430,8 +2595,10 @@ static int parse_flags(union tvec_regval *rv, const struct tvec_regdef *rd, if (tvec_nexttoken(tv)) break; ch = getc(tv->fp); if (ch != '|') { tvec_syntax(tv, ch, "`|'"); rc = -1; goto end; } - if (tvec_nexttoken(tv)) - { tvec_syntax(tv, '\n', "flag name or integer"); rc = -1; goto end; } + if (tvec_nexttoken(tv)) { + tvec_syntax(tv, '\n', "%s flag name or integer", fi->name); + rc = -1; goto end; + } } /* Done. */ @@ -2476,6 +2643,8 @@ static void dump_flags(const union tvec_regval *rv, unsigned long m = ~0ul, v = rv->u; const char *sep; + if (style&TVSF_RAW) gprintf(gops, go, "flags/%s:", fi->name); + for (f = fi->fv, sep = ""; f->tag; f++) if ((m&f->m) && (v&f->m) == f->v) { gprintf(gops, go, "%s%s", sep, f->tag); m &= ~f->m; @@ -2484,7 +2653,7 @@ static void dump_flags(const union tvec_regval *rv, if (v&m) gprintf(gops, go, "%s0x%0*lx", sep, hex_width(v), v&m); - if (m != ~0ul && !(style&TVSF_COMPACT)) + if (m != ~0ul && !(style&(TVSF_COMPACT | TVSF_RAW))) gprintf(gops, go, " ; = 0x%0*lx", hex_width(rv->u), rv->u); } @@ -2765,35 +2934,45 @@ static void dump_char(const union tvec_regval *rv, unsigned f = 0; #define f_semi 1u - /* Print a character name if we can find one. */ - p = find_charname(rv->i, (style&TVSF_COMPACT) ? CTF_SHORT : CTF_PREFER); - if (p) { - gprintf(gops, go, "%s", p); - if (style&TVSF_COMPACT) return; - else { gprintf(gops, go, " ;"); f |= f_semi; } - } + if (style&TVSF_RAW) { + /* Print the raw character unconditionally in single quotes. */ - /* If the character isn't @EOF@ then print it as a single-quoted thing. - * In compact style, see if we can omit the quotes. - */ - if (rv->i >= 0) { - if (f&f_semi) gprintf(gops, go, " = "); - switch (rv->i) { - case ' ': case '\\': case '\'': quote: - format_char(gops, go, rv->i); - break; - default: - if (!(style&TVSF_COMPACT) || !isprint(rv->i)) goto quote; - gprintf(gops, go, "%c", (int)rv->i); - return; + gprintf(gops, go, "char:'"); + format_char(gops, go, rv->i); + gprintf(gops, go, "'"); + } else { + /* Print ina pleasant human-readable way. */ + + /* Print a character name if we can find one. */ + p = find_charname(rv->i, (style&TVSF_COMPACT) ? CTF_SHORT : CTF_PREFER); + if (p) { + gprintf(gops, go, "%s", p); + if (style&TVSF_COMPACT) return; + else { gprintf(gops, go, " ;"); f |= f_semi; } } - } - /* And the character code as an integer. */ - if (!(style&TVSF_COMPACT)) { - if (!(f&f_semi)) gprintf(gops, go, " ;"); - gprintf(gops, go, " = %ld = ", rv->i); - format_signed_hex(gops, go, rv->i); + /* If the character isn't @EOF@ then print it as a single-quoted thing. + * In compact style, see if we can omit the quotes. + */ + if (rv->i >= 0) { + if (f&f_semi) gprintf(gops, go, " = "); + switch (rv->i) { + case ' ': case '\\': case '\'': quote: + format_char(gops, go, rv->i); + break; + default: + if (!(style&TVSF_COMPACT) || !isprint(rv->i)) goto quote; + gprintf(gops, go, "%c", (int)rv->i); + return; + } + } + + /* And the character code as an integer. */ + if (!(style&TVSF_COMPACT)) { + if (!(f&f_semi)) gprintf(gops, go, " ;"); + gprintf(gops, go, " = %ld = ", rv->i); + format_signed_hex(gops, go, rv->i); + } } #undef f_semi @@ -3071,9 +3250,19 @@ static int parse_bytes(union tvec_regval *rv, const struct tvec_regdef *rd, * groups of hex digits, with comments showing the offset (if * the string is long enough) and the corresponding plain text. * - * Empty strings are dumped as %|""|%. + * Empty strings are dumped as %|#empty|%. */ +static void dump_empty(const char *ty, unsigned style, + const struct gprintf_ops *gops, void *go) +{ + if (style&TVSF_RAW) gprintf(gops, go, "%s:", ty); + if (!(style&TVSF_COMPACT)) gprintf(gops, go, "#empty"); + if (!(style&(TVSF_COMPACT | TVSF_RAW))) gprintf(gops, go, " ; = "); + if (!(style&TVSF_RAW)) gprintf(gops, go, "\"\""); +} + + static void dump_text(const union tvec_regval *rv, const struct tvec_regdef *rd, unsigned style, @@ -3084,9 +3273,12 @@ static void dump_text(const union tvec_regval *rv, #define f_nonword 1u #define f_newline 2u - if (!rv->text.sz) { gprintf(gops, go, "\"\""); return; } + if (!rv->text.sz) { dump_empty("text", style, gops, go); return; } p = (const unsigned char *)rv->text.p; l = p + rv->text.sz; + if (style&TVSF_RAW) { gprintf(gops, go, "text:"); goto quote; } + else if (style&TVSF_COMPACT) goto quote; + switch (*p) { case '!': case '#': case ';': case '"': case '\'': case '(': case '{': case '[': case ']': case '}': case ')': @@ -3094,7 +3286,7 @@ static void dump_text(const union tvec_regval *rv, } for (q = p; q < l; q++) if (*q == '\n' && q != l - 1) f |= f_newline; - else if (!*q || !isgraph(*q) || *q == '\\') f |= f_nonword; + else if (!*q || !ISGRAPH(*q) || *q == '\\') f |= f_nonword; if (f&f_newline) { gprintf(gops, go, "\n\t"); goto quote; } else if (f&f_nonword) goto quote; @@ -3104,7 +3296,7 @@ static void dump_text(const union tvec_regval *rv, quote: gprintf(gops, go, "\""); for (q = p; q < l; q++) - if (!isprint(*q) || *q == '"') { + if (!ISPRINT(*q) || *q == '"') { if (p < q) gops->putm(go, (const char *)p, q - p); if (*q != '\n' || (style&TVSF_COMPACT)) format_charesc(gops, go, *q, FCF_BRACE); @@ -3131,12 +3323,9 @@ static void dump_bytes(const union tvec_regval *rv, unsigned i, n; int wd; - if (!sz) { - gprintf(gops, go, style&TVSF_COMPACT ? "\"\"" : "\"\" ; empty"); - return; - } + if (!rv->text.sz) { dump_empty("bytes", style, gops, go); return; } - if (style&TVSF_COMPACT) { + if (style&(TVSF_COMPACT | TVSF_RAW)) { while (p < l) gprintf(gops, go, "%02x", *p++); return; } @@ -3412,23 +3601,24 @@ static int frombuf_buffer(buf *b, union tvec_regval *rv, * * Use: Parse a register value from an input file. * - * The input format for a buffer value consists of an unsigned - * integer followed by an optional unit specifier consisting of - * an SI unit prefix and (optionally) the letter `B'. Unit - * prefixes denote %%\emph{binary}%% multipliers, not decimal. + * The input format for a buffer value is a size, followed by an + * optional `%|@$%' and an alignment quantum and a further + * optional `%|+|%' and an alignment offset. The size, quantum, + * and offset are syntactically sizes. * - * The buffer is allocated and filled with a distinctive - * pattern. + * The buffer is not allocated. */ static int parse_buffer(union tvec_regval *rv, const struct tvec_regdef *rd, struct tvec_state *tv) { - size_t sz, a = 0, m = 0; + unsigned long sz, a = 0, m = 0; int ch, rc; - if (parse_size(tv, &sz, "@;", "buffer length")) { rc = -1; goto end; } + if (parse_szint(tv, &sz, "@;", "buffer length")) { rc = -1; goto end; } + if (check_unsigned_range(sz, &tvrange_size, tv, "buffer length")) + { rc = -1; goto end; } if (check_string_length(sz, rd->arg.p, tv)) { rc = -1; goto end; } tvec_skipspc(tv); @@ -3436,7 +3626,9 @@ static int parse_buffer(union tvec_regval *rv, if (ch == ';' || ch == '\n') { ungetc(ch, tv->fp); goto done; } else if (ch != '@') { rc = tvec_syntax(tv, ch, "`@'"); goto end; } - if (parse_size(tv, &m, "+;", "alignment quantum")) { rc = -1; goto end; } + if (parse_szint(tv, &m, "+;", "alignment quantum")) { rc = -1; goto end; } + if (check_unsigned_range(a, &tvrange_size, tv, "alignment quantum")) + { rc = -1; goto end; } if (m == 1) m = 0; tvec_skipspc(tv); @@ -3444,7 +3636,9 @@ static int parse_buffer(union tvec_regval *rv, if (ch == ';' || ch == '\n') { ungetc(ch, tv->fp); goto done; } else if (ch != '+') { rc = tvec_syntax(tv, ch, "`+'"); goto end; } - if (parse_size(tv, &a, ";", "alignment offset")) { rc = -1; goto end; } + if (parse_szint(tv, &a, ";", "alignment offset")) { rc = -1; goto end; } + if (check_unsigned_range(m, &tvrange_size, tv, "alignment offset")) + { rc = -1; goto end; } if (a >= m) { rc = tvec_error(tv, "alignment offset %lu >= quantum %lu", (unsigned long)a, (unsigned long)m); @@ -3470,9 +3664,8 @@ end: * * Use: Dump a register value to the format output. * - * Buffer values are dumped as their size with an appropriate - * unit specifier. A unit prefix is only used if the size is an - * exact multiple of the relevant power of two. + * Buffer values are dumped as their size, with the alignment + * quantum and alignment offset if these are non-default. */ static void dump_buffer(const union tvec_regval *rv, @@ -3482,10 +3675,10 @@ static void dump_buffer(const union tvec_regval *rv, { format_size(gops, go, rv->buf.sz, style); if (rv->buf.m) { - gprintf(gops, go, style&TVSF_COMPACT ? "@" : " @ "); + gprintf(gops, go, style&(TVSF_COMPACT | TVSF_RAW) ? "@" : " @ "); format_size(gops, go, rv->buf.m, style); if (rv->buf.a) { - gprintf(gops, go, style&TVSF_COMPACT ? "+" : " + "); + gprintf(gops, go, style&(TVSF_COMPACT | TVSF_RAW) ? "+" : " + "); format_size(gops, go, rv->buf.a, style); } } @@ -3516,18 +3709,18 @@ const struct tvec_regty tvty_buffer = { /* --- @tvec_initbuffer@ --- * * * Arguments: @union tvec_regval *rv@ = register value - * @const union tvec_regval *src@ = source buffer + * @const union tvec_regval *ref@ = source buffer * @size_t sz@ = size to allocate * * Returns: --- * - * Use: Initialize the alignment parameters in @rv@ to match @src@, + * Use: Initialize the alignment parameters in @rv@ to match @ref@, * and the size to @sz@. */ void tvec_initbuffer(union tvec_regval *rv, - const union tvec_regval *src, size_t sz) - { rv->buf.sz = sz; rv->buf.a = src->buf.a; rv->buf.m = src->buf.m; } + const union tvec_regval *ref, size_t sz) + { rv->buf.sz = sz; rv->buf.a = ref->buf.a; rv->buf.m = ref->buf.m; } /* --- @tvec_allocbuffer@ --- * *