Mercurial > emacs
diff src/editfns.c @ 48764:4a69081f2ff4
(Fformat): Handle precision in string conversion specifiers like libc
functions do (ie, print at most that many characters). From Matthew
Swift <swift@alum.mit.edu>.
| author | Kai Gro?johann <kgrossjo@eu.uu.net> |
|---|---|
| date | Mon, 09 Dec 2002 10:44:25 +0000 |
| parents | ef2b87569c38 |
| children | d17f48c1b40f |
line wrap: on
line diff
--- a/src/editfns.c Mon Dec 09 08:33:40 2002 +0000 +++ b/src/editfns.c Mon Dec 09 10:44:25 2002 +0000 @@ -3207,6 +3207,12 @@ must consider such a situation or not. */ int maybe_combine_byte; unsigned char *this_format; + /* Precision for each spec, or -1, a flag value meaning no precision + was given in that spec. Element 0, corresonding to the format + string itself, will not be used. Element NARGS, corresponding to + no argument, *will* be assigned to in the case that a `%' and `.' + occur after the final format specifier. */ + int precision[nargs]; int longest_format; Lisp_Object val; struct info @@ -3221,9 +3227,12 @@ This is not always right; sometimes the result needs to be multibyte because of an object that we will pass through prin1, and in that case, we won't know it here. */ - for (n = 0; n < nargs; n++) + for (n = 0; n < nargs; n++) { if (STRINGP (args[n]) && STRING_MULTIBYTE (args[n])) multibyte = 1; + /* Piggyback on this loop to initialize precision[N]. */ + precision[n] = -1; + } CHECK_STRING (args[0]); @@ -3247,7 +3256,7 @@ int thissize = 0; int actual_width = 0; unsigned char *this_format_start = format - 1; - int field_width, precision; + int field_width = 0; /* General format specifications look like @@ -3263,12 +3272,17 @@ the output should be padded with blanks, iff the output string is shorter than field-width. - if precision is specified, it specifies the number of + If precision is specified, it specifies the number of digits to print after the '.' for floats, or the max. number of chars to print from a string. */ - precision = field_width = 0; - + /* NOTE the handling of specifiers here differs in some ways + from the libc model. There are bugs in this code that lead + to incorrect formatting when flags recognized by C but + neither parsed nor rejected here are used. Further + revisions will be made soon. */ + + /* incorrect list of flags to skip; will be fixed */ while (index ("-*# 0", *format)) ++format; @@ -3278,11 +3292,13 @@ field_width = 10 * field_width + *format - '0'; } + /* N is not incremented for another few lines below, so refer to + element N+1 (which might be precision[NARGS]). */ if (*format == '.') { ++format; - for (precision = 0; *format >= '0' && *format <= '9'; ++format) - precision = 10 * precision + *format - '0'; + for (precision[n+1] = 0; *format >= '0' && *format <= '9'; ++format) + precision[n+1] = 10 * precision[n+1] + *format - '0'; } if (format - this_format_start + 1 > longest_format) @@ -3322,7 +3338,10 @@ string: if (*format != 's' && *format != 'S') error ("Format specifier doesn't match argument type"); - thissize = CONVERTED_BYTE_SIZE (multibyte, args[n]); + /* In the case (PRECISION[N] > 0), THISSIZE may not need + to be as large as is calculated here. Easy check for + the case PRECISION = 0. */ + thissize = precision[n] ? CONVERTED_BYTE_SIZE (multibyte, args[n]) : 0; actual_width = lisp_string_width (args[n], -1, NULL, NULL); } /* Would get MPV otherwise, since Lisp_Int's `point' to low memory. */ @@ -3366,7 +3385,10 @@ /* Note that we're using sprintf to print floats, so we have to take into account what that function prints. */ - thissize = MAX_10_EXP + 100 + precision; + /* Filter out flag value of -1. This is a conditional with omitted + operand: the value is PRECISION[N] if the conditional is >=0 and + otherwise is 0. */ + thissize = MAX_10_EXP + 100 + (precision[n] > 0 ? : 0); } else { @@ -3416,10 +3438,14 @@ format++; /* Process a numeric arg and skip it. */ + /* NOTE atoi is the wrong thing to use here; will be fixed */ minlen = atoi (format); if (minlen < 0) minlen = - minlen, negative = 1; + /* NOTE the parsing here is not consistent with the first + pass, and neither attempt is what we want to do. Will be + fixed. */ while ((*format >= '0' && *format <= '9') || *format == '-' || *format == ' ' || *format == '.') format++; @@ -3435,8 +3461,28 @@ if (STRINGP (args[n])) { - int padding, nbytes, start, end; - int width = lisp_string_width (args[n], -1, NULL, NULL); + /* handle case (precision[n] >= 0) */ + + int width, padding; + int nbytes, start, end; + int nchars_string; + + /* lisp_string_width ignores a precision of 0, but GNU + libc functions print 0 characters when the precision + is 0. Imitate libc behavior here. Changing + lisp_string_width is the right thing, and will be + done, but meanwhile we work with it. */ + + if (precision[n] == 0) + width = nchars_string = nbytes = 0; + else if (precision[n] > 0) + width = lisp_string_width (args[n], precision[n], &nchars_string, &nbytes); + else + { /* no precision spec given for this argument */ + width = lisp_string_width (args[n], -1, NULL, NULL); + nbytes = SBYTES (args[n]); + nchars_string = SCHARS (args[n]); + } /* If spec requires it, pad on right with spaces. */ padding = minlen - width; @@ -3448,19 +3494,19 @@ } start = nchars; - + nchars += nchars_string; + end = nchars; + if (p > buf && multibyte && !ASCII_BYTE_P (*((unsigned char *) p - 1)) && STRING_MULTIBYTE (args[n]) && !CHAR_HEAD_P (SREF (args[n], 0))) maybe_combine_byte = 1; - nbytes = copy_text (SDATA (args[n]), p, - SBYTES (args[n]), - STRING_MULTIBYTE (args[n]), multibyte); - p += nbytes; - nchars += SCHARS (args[n]); - end = nchars; + + p += copy_text (SDATA (args[n]), p, + nbytes, + STRING_MULTIBYTE (args[n]), multibyte); if (negative) while (padding-- > 0)
