Mercurial > hg > xemacs-beta
diff src/doprnt.c @ 203:850242ba4a81 r20-3b28
Import from CVS: tag r20-3b28
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:02:21 +0200 |
parents | b405438285a2 |
children | 92f8ad5d0d3f |
line wrap: on
line diff
--- a/src/doprnt.c Mon Aug 13 10:01:24 2007 +0200 +++ b/src/doprnt.c Mon Aug 13 10:02:21 2007 +0200 @@ -54,6 +54,7 @@ unsigned int zero_flag:1; unsigned int h_flag:1; unsigned int l_flag:1; + unsigned int forwarding_precision:1; char converter; /* converter character or 0 for dummy marker indicating literal text at the end of the specification */ @@ -168,6 +169,14 @@ fmt++; \ } while (0) +#define RESOLVE_FLAG_CONFLICTS(spec) \ + do { \ + if (spec.space_flag && spec.plus_flag) \ + spec.space_flag = 0; \ + if (spec.zero_flag && spec.space_flag) \ + spec.zero_flag = 0; \ + } while (0) + static printf_spec_dynarr * parse_doprnt_spec (CONST Bufbyte *format, Bytecount format_length) { @@ -240,17 +249,56 @@ /* Parse off the minimum field width */ fmt--; /* back up */ - fmt = parse_off_posnum (fmt, fmt_end, &spec.minwidth); - if (spec.minwidth == -1) - spec.minwidth = 0; + + /* + * * means the field width was passed as an argument. + * Mark the current spec as one that forwards its + * field width and flags to the next spec in the array. + * Then create a new spec and continue with the parsing. + */ + if (fmt != fmt_end && *fmt == '*') + { + spec.converter = '*'; + RESOLVE_FLAG_CONFLICTS(spec); + Dynarr_add (specs, spec); + memset (&spec, 0, sizeof (spec)); + spec.argnum = ++prev_argnum; + fmt++; + } + else + { + fmt = parse_off_posnum (fmt, fmt_end, &spec.minwidth); + if (spec.minwidth == -1) + spec.minwidth = 0; + } /* Parse off any precision specified */ NEXT_ASCII_BYTE (ch); if (ch == '.') { - fmt = parse_off_posnum (fmt, fmt_end, &spec.precision); - if (spec.precision == -1) - spec.precision = 0; + /* + * * means the precision was passed as an argument. + * Mark the current spec as one that forwards its + * fieldwidth, flags and precision to the next spec in + * the array. Then create a new spec and continue + * with the parse. + */ + if (fmt != fmt_end && *fmt == '*') + { + spec.converter = '*'; + spec.forwarding_precision = 1; + RESOLVE_FLAG_CONFLICTS(spec); + Dynarr_add (specs, spec); + memset (&spec, 0, sizeof (spec)); + spec.argnum = ++prev_argnum; + fmt++; + } + else + { + fmt = parse_off_posnum (fmt, fmt_end, &spec.precision); + if (spec.precision == -1) + spec.precision = 0; + } NEXT_ASCII_BYTE (ch); } else @@ -272,11 +320,7 @@ spec.converter = ch; } - if (spec.space_flag && spec.plus_flag) - spec.space_flag = 0; - if (spec.zero_flag && spec.space_flag) - spec.zero_flag = 0; - + RESOLVE_FLAG_CONFLICTS(spec); Dynarr_add (specs, spec); } @@ -436,6 +480,36 @@ continue; } + /* + * * as converter means the field width, precision was specified + * as an argument. Extract the data and forward it to the + * next spec, to which it will apply. + */ + if (ch == '*') + { + struct printf_spec *nextspec = Dynarr_atp (specs, i + 1); + Lisp_Object obj = largs[spec->argnum - 1]; + + if (INTP (obj)) + { + if (spec->forwarding_precision) + { + nextspec->precision = XINT (obj); + nextspec->minwidth = spec->minwidth; + } + else + { + nextspec->minwidth = XINT (obj); + } + nextspec->minus_flag = spec->minus_flag; + nextspec->plus_flag = spec->plus_flag; + nextspec->space_flag = spec->space_flag; + nextspec->number_flag = spec->number_flag; + nextspec->zero_flag = spec->zero_flag; + } + continue; + } + if (largs && (spec->argnum < 1 || spec->argnum > nargs)) error ("Invalid repositioning argument %d", spec->argnum);