diff options
| author | Paul Eggert | 2017-06-04 08:39:37 -0700 |
|---|---|---|
| committer | Paul Eggert | 2017-06-04 08:42:53 -0700 |
| commit | d5fcf9e458053af1c50f0d4dad4c59db056790e5 (patch) | |
| tree | f6fe65eb1823c49d771d520c4e6d66b92525ac2d /src | |
| parent | 6ad42aecc243d378d38468fd3efd89bc1fbfb187 (diff) | |
| download | emacs-d5fcf9e458053af1c50f0d4dad4c59db056790e5.tar.gz emacs-d5fcf9e458053af1c50f0d4dad4c59db056790e5.zip | |
Tune ‘format’ after recent fix
* doc/lispref/strings.texi (Formatting Strings):
* src/editfns.c (Fformat): Format field numbers no longer need
to be unique, reverting the previous doc change since that has
now been fixed. Also, document that %% should not have modifiers.
* src/editfns.c (styled_format): Improve performance. Remove
the need for the new prepass over the format string, by using
a typically-more-generous bound for the info array size.
Initialize the info array lazily. Move string inspection to
the same area to help caching. Avoid the need for a
converted_to_string bitfield by using EQ. Cache arg in a
local and avoid some potential aliasing issues to help the
compiler. Info array is now 0-origin, not 1-origin.
Diffstat (limited to 'src')
| -rw-r--r-- | src/editfns.c | 154 |
1 files changed, 66 insertions, 88 deletions
diff --git a/src/editfns.c b/src/editfns.c index 56aa8ce1a72..43b17f9f116 100644 --- a/src/editfns.c +++ b/src/editfns.c | |||
| @@ -3891,8 +3891,8 @@ the next available argument, or the argument explicitly specified: | |||
| 3891 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. | 3891 | The argument used for %d, %o, %x, %e, %f, %g or %c must be a number. |
| 3892 | Use %% to put a single % into the output. | 3892 | Use %% to put a single % into the output. |
| 3893 | 3893 | ||
| 3894 | A %-sequence may contain optional field number, flag, width, and | 3894 | A %-sequence other than %% may contain optional field number, flag, |
| 3895 | precision specifiers, as follows: | 3895 | width, and precision specifiers, as follows: |
| 3896 | 3896 | ||
| 3897 | %<field><flags><width><precision>character | 3897 | %<field><flags><width><precision>character |
| 3898 | 3898 | ||
| @@ -3901,10 +3901,9 @@ where field is [0-9]+ followed by a literal dollar "$", flags is | |||
| 3901 | followed by [0-9]+. | 3901 | followed by [0-9]+. |
| 3902 | 3902 | ||
| 3903 | If a %-sequence is numbered with a field with positive value N, the | 3903 | If a %-sequence is numbered with a field with positive value N, the |
| 3904 | Nth argument is substituted instead of the next one. A field number | 3904 | Nth argument is substituted instead of the next one. A format can |
| 3905 | should differ from the other field numbers in the same format. A | 3905 | contain either numbered or unnumbered %-sequences but not both, except |
| 3906 | format can contain either numbered or unnumbered %-sequences but not | 3906 | that %% can be mixed with numbered %-sequences. |
| 3907 | both, except that %% can be mixed with numbered %-sequences. | ||
| 3908 | 3907 | ||
| 3909 | The + flag character inserts a + before any positive number, while a | 3908 | The + flag character inserts a + before any positive number, while a |
| 3910 | space inserts a space before any positive number; these flags only | 3909 | space inserts a space before any positive number; these flags only |
| @@ -3980,49 +3979,40 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 3980 | bool arg_intervals = false; | 3979 | bool arg_intervals = false; |
| 3981 | USE_SAFE_ALLOCA; | 3980 | USE_SAFE_ALLOCA; |
| 3982 | 3981 | ||
| 3983 | /* Each element records, for one field, | 3982 | /* Information recorded for each format spec. */ |
| 3984 | the corresponding argument, | ||
| 3985 | the start and end bytepos in the output string, | ||
| 3986 | whether the argument has been converted to string (e.g., due to "%S"), | ||
| 3987 | and whether the argument is a string with intervals. */ | ||
| 3988 | struct info | 3983 | struct info |
| 3989 | { | 3984 | { |
| 3985 | /* The corresponding argument, converted to string if conversion | ||
| 3986 | was needed. */ | ||
| 3990 | Lisp_Object argument; | 3987 | Lisp_Object argument; |
| 3988 | |||
| 3989 | /* The start and end bytepos in the output string. */ | ||
| 3991 | ptrdiff_t start, end; | 3990 | ptrdiff_t start, end; |
| 3992 | bool_bf converted_to_string : 1; | 3991 | |
| 3992 | /* Whether the argument is a string with intervals. */ | ||
| 3993 | bool_bf intervals : 1; | 3993 | bool_bf intervals : 1; |
| 3994 | } *info; | 3994 | } *info; |
| 3995 | 3995 | ||
| 3996 | CHECK_STRING (args[0]); | 3996 | CHECK_STRING (args[0]); |
| 3997 | char *format_start = SSDATA (args[0]); | 3997 | char *format_start = SSDATA (args[0]); |
| 3998 | bool multibyte_format = STRING_MULTIBYTE (args[0]); | ||
| 3998 | ptrdiff_t formatlen = SBYTES (args[0]); | 3999 | ptrdiff_t formatlen = SBYTES (args[0]); |
| 3999 | 4000 | ||
| 4000 | /* The number of percent characters is a safe upper bound for the | 4001 | /* Upper bound on number of format specs. Each uses at least 2 chars. */ |
| 4001 | number of format fields. */ | 4002 | ptrdiff_t nspec_bound = SCHARS (args[0]) >> 1; |
| 4002 | ptrdiff_t num_percent = 0; | ||
| 4003 | for (ptrdiff_t i = 0; i < formatlen; ++i) | ||
| 4004 | if (format_start[i] == '%') | ||
| 4005 | ++num_percent; | ||
| 4006 | 4003 | ||
| 4007 | /* Allocate the info and discarded tables. */ | 4004 | /* Allocate the info and discarded tables. */ |
| 4008 | ptrdiff_t alloca_size; | 4005 | ptrdiff_t alloca_size; |
| 4009 | if (INT_MULTIPLY_WRAPV (num_percent, sizeof *info, &alloca_size) | 4006 | if (INT_MULTIPLY_WRAPV (nspec_bound, sizeof *info, &alloca_size) |
| 4010 | || INT_ADD_WRAPV (sizeof *info, alloca_size, &alloca_size) | ||
| 4011 | || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size) | 4007 | || INT_ADD_WRAPV (formatlen, alloca_size, &alloca_size) |
| 4012 | || SIZE_MAX < alloca_size) | 4008 | || SIZE_MAX < alloca_size) |
| 4013 | memory_full (SIZE_MAX); | 4009 | memory_full (SIZE_MAX); |
| 4014 | /* info[0] is unused. Unused elements have -1 for start. */ | ||
| 4015 | info = SAFE_ALLOCA (alloca_size); | 4010 | info = SAFE_ALLOCA (alloca_size); |
| 4016 | memset (info, 0, alloca_size); | ||
| 4017 | for (ptrdiff_t i = 0; i < num_percent + 1; i++) | ||
| 4018 | { | ||
| 4019 | info[i].argument = Qunbound; | ||
| 4020 | info[i].start = -1; | ||
| 4021 | } | ||
| 4022 | /* discarded[I] is 1 if byte I of the format | 4011 | /* discarded[I] is 1 if byte I of the format |
| 4023 | string was not copied into the output. | 4012 | string was not copied into the output. |
| 4024 | It is 2 if byte I was not the first byte of its character. */ | 4013 | It is 2 if byte I was not the first byte of its character. */ |
| 4025 | char *discarded = (char *) &info[num_percent + 1]; | 4014 | char *discarded = (char *) &info[nspec_bound]; |
| 4015 | memset (discarded, 0, formatlen); | ||
| 4026 | 4016 | ||
| 4027 | /* Try to determine whether the result should be multibyte. | 4017 | /* Try to determine whether the result should be multibyte. |
| 4028 | This is not always right; sometimes the result needs to be multibyte | 4018 | This is not always right; sometimes the result needs to be multibyte |
| @@ -4030,8 +4020,6 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4030 | or because a grave accent or apostrophe is requoted, | 4020 | or because a grave accent or apostrophe is requoted, |
| 4031 | and in that case, we won't know it here. */ | 4021 | and in that case, we won't know it here. */ |
| 4032 | 4022 | ||
| 4033 | /* True if the format is multibyte. */ | ||
| 4034 | bool multibyte_format = STRING_MULTIBYTE (args[0]); | ||
| 4035 | /* True if the output should be a multibyte string, | 4023 | /* True if the output should be a multibyte string, |
| 4036 | which is true if any of the inputs is one. */ | 4024 | which is true if any of the inputs is one. */ |
| 4037 | bool multibyte = multibyte_format; | 4025 | bool multibyte = multibyte_format; |
| @@ -4042,6 +4030,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4042 | int quoting_style = message ? text_quoting_style () : -1; | 4030 | int quoting_style = message ? text_quoting_style () : -1; |
| 4043 | 4031 | ||
| 4044 | ptrdiff_t ispec; | 4032 | ptrdiff_t ispec; |
| 4033 | ptrdiff_t nspec = 0; | ||
| 4045 | 4034 | ||
| 4046 | /* If we start out planning a unibyte result, | 4035 | /* If we start out planning a unibyte result, |
| 4047 | then discover it has to be multibyte, we jump back to retry. */ | 4036 | then discover it has to be multibyte, we jump back to retry. */ |
| @@ -4155,11 +4144,14 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4155 | if (! (n < nargs)) | 4144 | if (! (n < nargs)) |
| 4156 | error ("Not enough arguments for format string"); | 4145 | error ("Not enough arguments for format string"); |
| 4157 | 4146 | ||
| 4158 | eassert (ispec < num_percent); | 4147 | struct info *spec = &info[ispec++]; |
| 4159 | ++ispec; | 4148 | if (nspec < ispec) |
| 4160 | 4149 | { | |
| 4161 | if (EQ (info[ispec].argument, Qunbound)) | 4150 | spec->argument = args[n]; |
| 4162 | info[ispec].argument = args[n]; | 4151 | spec->intervals = false; |
| 4152 | nspec = ispec; | ||
| 4153 | } | ||
| 4154 | Lisp_Object arg = spec->argument; | ||
| 4163 | 4155 | ||
| 4164 | /* For 'S', prin1 the argument, and then treat like 's'. | 4156 | /* For 'S', prin1 the argument, and then treat like 's'. |
| 4165 | For 's', princ any argument that is not a string or | 4157 | For 's', princ any argument that is not a string or |
| @@ -4167,16 +4159,13 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4167 | happen after retrying. */ | 4159 | happen after retrying. */ |
| 4168 | if ((conversion == 'S' | 4160 | if ((conversion == 'S' |
| 4169 | || (conversion == 's' | 4161 | || (conversion == 's' |
| 4170 | && ! STRINGP (info[ispec].argument) | 4162 | && ! STRINGP (arg) && ! SYMBOLP (arg)))) |
| 4171 | && ! SYMBOLP (info[ispec].argument)))) | ||
| 4172 | { | 4163 | { |
| 4173 | if (! info[ispec].converted_to_string) | 4164 | if (EQ (arg, args[n])) |
| 4174 | { | 4165 | { |
| 4175 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; | 4166 | Lisp_Object noescape = conversion == 'S' ? Qnil : Qt; |
| 4176 | info[ispec].argument = | 4167 | spec->argument = arg = Fprin1_to_string (arg, noescape); |
| 4177 | Fprin1_to_string (info[ispec].argument, noescape); | 4168 | if (STRING_MULTIBYTE (arg) && ! multibyte) |
| 4178 | info[ispec].converted_to_string = true; | ||
| 4179 | if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte) | ||
| 4180 | { | 4169 | { |
| 4181 | multibyte = true; | 4170 | multibyte = true; |
| 4182 | goto retry; | 4171 | goto retry; |
| @@ -4186,29 +4175,25 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4186 | } | 4175 | } |
| 4187 | else if (conversion == 'c') | 4176 | else if (conversion == 'c') |
| 4188 | { | 4177 | { |
| 4189 | if (INTEGERP (info[ispec].argument) | 4178 | if (INTEGERP (arg) && ! ASCII_CHAR_P (XINT (arg))) |
| 4190 | && ! ASCII_CHAR_P (XINT (info[ispec].argument))) | ||
| 4191 | { | 4179 | { |
| 4192 | if (!multibyte) | 4180 | if (!multibyte) |
| 4193 | { | 4181 | { |
| 4194 | multibyte = true; | 4182 | multibyte = true; |
| 4195 | goto retry; | 4183 | goto retry; |
| 4196 | } | 4184 | } |
| 4197 | info[ispec].argument = | 4185 | spec->argument = arg = Fchar_to_string (arg); |
| 4198 | Fchar_to_string (info[ispec].argument); | ||
| 4199 | info[ispec].converted_to_string = true; | ||
| 4200 | } | 4186 | } |
| 4201 | 4187 | ||
| 4202 | if (info[ispec].converted_to_string) | 4188 | if (!EQ (arg, args[n])) |
| 4203 | conversion = 's'; | 4189 | conversion = 's'; |
| 4204 | zero_flag = false; | 4190 | zero_flag = false; |
| 4205 | } | 4191 | } |
| 4206 | 4192 | ||
| 4207 | if (SYMBOLP (info[ispec].argument)) | 4193 | if (SYMBOLP (arg)) |
| 4208 | { | 4194 | { |
| 4209 | info[ispec].argument = | 4195 | spec->argument = arg = SYMBOL_NAME (arg); |
| 4210 | SYMBOL_NAME (info[ispec].argument); | 4196 | if (STRING_MULTIBYTE (arg) && ! multibyte) |
| 4211 | if (STRING_MULTIBYTE (info[ispec].argument) && ! multibyte) | ||
| 4212 | { | 4197 | { |
| 4213 | multibyte = true; | 4198 | multibyte = true; |
| 4214 | goto retry; | 4199 | goto retry; |
| @@ -4239,12 +4224,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4239 | else | 4224 | else |
| 4240 | { | 4225 | { |
| 4241 | ptrdiff_t nch, nby; | 4226 | ptrdiff_t nch, nby; |
| 4242 | width = lisp_string_width (info[ispec].argument, | 4227 | width = lisp_string_width (arg, prec, &nch, &nby); |
| 4243 | prec, &nch, &nby); | ||
| 4244 | if (prec < 0) | 4228 | if (prec < 0) |
| 4245 | { | 4229 | { |
| 4246 | nchars_string = SCHARS (info[ispec].argument); | 4230 | nchars_string = SCHARS (arg); |
| 4247 | nbytes = SBYTES (info[ispec].argument); | 4231 | nbytes = SBYTES (arg); |
| 4248 | } | 4232 | } |
| 4249 | else | 4233 | else |
| 4250 | { | 4234 | { |
| @@ -4254,11 +4238,8 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4254 | } | 4238 | } |
| 4255 | 4239 | ||
| 4256 | convbytes = nbytes; | 4240 | convbytes = nbytes; |
| 4257 | if (convbytes && multibyte && | 4241 | if (convbytes && multibyte && ! STRING_MULTIBYTE (arg)) |
| 4258 | ! STRING_MULTIBYTE (info[ispec].argument)) | 4242 | convbytes = count_size_as_multibyte (SDATA (arg), nbytes); |
| 4259 | convbytes = | ||
| 4260 | count_size_as_multibyte (SDATA (info[ispec].argument), | ||
| 4261 | nbytes); | ||
| 4262 | 4243 | ||
| 4263 | ptrdiff_t padding | 4244 | ptrdiff_t padding |
| 4264 | = width < field_width ? field_width - width : 0; | 4245 | = width < field_width ? field_width - width : 0; |
| @@ -4274,20 +4255,18 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4274 | p += padding; | 4255 | p += padding; |
| 4275 | nchars += padding; | 4256 | nchars += padding; |
| 4276 | } | 4257 | } |
| 4277 | info[ispec].start = nchars; | 4258 | spec->start = nchars; |
| 4278 | 4259 | ||
| 4279 | if (p > buf | 4260 | if (p > buf |
| 4280 | && multibyte | 4261 | && multibyte |
| 4281 | && !ASCII_CHAR_P (*((unsigned char *) p - 1)) | 4262 | && !ASCII_CHAR_P (*((unsigned char *) p - 1)) |
| 4282 | && STRING_MULTIBYTE (info[ispec].argument) | 4263 | && STRING_MULTIBYTE (arg) |
| 4283 | && !CHAR_HEAD_P (SREF (info[ispec].argument, 0))) | 4264 | && !CHAR_HEAD_P (SREF (arg, 0))) |
| 4284 | maybe_combine_byte = true; | 4265 | maybe_combine_byte = true; |
| 4285 | 4266 | ||
| 4286 | p += copy_text (SDATA (info[ispec].argument), | 4267 | p += copy_text (SDATA (arg), (unsigned char *) p, |
| 4287 | (unsigned char *) p, | ||
| 4288 | nbytes, | 4268 | nbytes, |
| 4289 | STRING_MULTIBYTE (info[ispec].argument), | 4269 | STRING_MULTIBYTE (arg), multibyte); |
| 4290 | multibyte); | ||
| 4291 | 4270 | ||
| 4292 | nchars += nchars_string; | 4271 | nchars += nchars_string; |
| 4293 | 4272 | ||
| @@ -4297,12 +4276,12 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4297 | p += padding; | 4276 | p += padding; |
| 4298 | nchars += padding; | 4277 | nchars += padding; |
| 4299 | } | 4278 | } |
| 4300 | info[ispec].end = nchars; | 4279 | spec->end = nchars; |
| 4301 | 4280 | ||
| 4302 | /* If this argument has text properties, record where | 4281 | /* If this argument has text properties, record where |
| 4303 | in the result string it appears. */ | 4282 | in the result string it appears. */ |
| 4304 | if (string_intervals (info[ispec].argument)) | 4283 | if (string_intervals (arg)) |
| 4305 | info[ispec].intervals = arg_intervals = true; | 4284 | spec->intervals = arg_intervals = true; |
| 4306 | 4285 | ||
| 4307 | continue; | 4286 | continue; |
| 4308 | } | 4287 | } |
| @@ -4313,8 +4292,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4313 | || conversion == 'X')) | 4292 | || conversion == 'X')) |
| 4314 | error ("Invalid format operation %%%c", | 4293 | error ("Invalid format operation %%%c", |
| 4315 | STRING_CHAR ((unsigned char *) format - 1)); | 4294 | STRING_CHAR ((unsigned char *) format - 1)); |
| 4316 | else if (! (INTEGERP (info[ispec].argument) | 4295 | else if (! (INTEGERP (arg) || (FLOATP (arg) && conversion != 'c'))) |
| 4317 | || (FLOATP (info[ispec].argument) && conversion != 'c'))) | ||
| 4318 | error ("Format specifier doesn't match argument type"); | 4296 | error ("Format specifier doesn't match argument type"); |
| 4319 | else | 4297 | else |
| 4320 | { | 4298 | { |
| @@ -4376,7 +4354,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4376 | if (INT_AS_LDBL) | 4354 | if (INT_AS_LDBL) |
| 4377 | { | 4355 | { |
| 4378 | *f = 'L'; | 4356 | *f = 'L'; |
| 4379 | f += INTEGERP (info[ispec].argument); | 4357 | f += INTEGERP (arg); |
| 4380 | } | 4358 | } |
| 4381 | } | 4359 | } |
| 4382 | else if (conversion != 'c') | 4360 | else if (conversion != 'c') |
| @@ -4408,22 +4386,22 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4408 | ptrdiff_t sprintf_bytes; | 4386 | ptrdiff_t sprintf_bytes; |
| 4409 | if (float_conversion) | 4387 | if (float_conversion) |
| 4410 | { | 4388 | { |
| 4411 | if (INT_AS_LDBL && INTEGERP (info[ispec].argument)) | 4389 | if (INT_AS_LDBL && INTEGERP (arg)) |
| 4412 | { | 4390 | { |
| 4413 | /* Although long double may have a rounding error if | 4391 | /* Although long double may have a rounding error if |
| 4414 | DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1, | 4392 | DIG_BITS_LBOUND * LDBL_MANT_DIG < FIXNUM_BITS - 1, |
| 4415 | it is more accurate than plain 'double'. */ | 4393 | it is more accurate than plain 'double'. */ |
| 4416 | long double x = XINT (info[ispec].argument); | 4394 | long double x = XINT (arg); |
| 4417 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); | 4395 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, x); |
| 4418 | } | 4396 | } |
| 4419 | else | 4397 | else |
| 4420 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, | 4398 | sprintf_bytes = sprintf (sprintf_buf, convspec, prec, |
| 4421 | XFLOATINT (info[ispec].argument)); | 4399 | XFLOATINT (arg)); |
| 4422 | } | 4400 | } |
| 4423 | else if (conversion == 'c') | 4401 | else if (conversion == 'c') |
| 4424 | { | 4402 | { |
| 4425 | /* Don't use sprintf here, as it might mishandle prec. */ | 4403 | /* Don't use sprintf here, as it might mishandle prec. */ |
| 4426 | sprintf_buf[0] = XINT (info[ispec].argument); | 4404 | sprintf_buf[0] = XINT (arg); |
| 4427 | sprintf_bytes = prec != 0; | 4405 | sprintf_bytes = prec != 0; |
| 4428 | } | 4406 | } |
| 4429 | else if (conversion == 'd' || conversion == 'i') | 4407 | else if (conversion == 'd' || conversion == 'i') |
| @@ -4432,11 +4410,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4432 | instead so it also works for values outside | 4410 | instead so it also works for values outside |
| 4433 | the integer range. */ | 4411 | the integer range. */ |
| 4434 | printmax_t x; | 4412 | printmax_t x; |
| 4435 | if (INTEGERP (info[ispec].argument)) | 4413 | if (INTEGERP (arg)) |
| 4436 | x = XINT (info[ispec].argument); | 4414 | x = XINT (arg); |
| 4437 | else | 4415 | else |
| 4438 | { | 4416 | { |
| 4439 | double d = XFLOAT_DATA (info[ispec].argument); | 4417 | double d = XFLOAT_DATA (arg); |
| 4440 | if (d < 0) | 4418 | if (d < 0) |
| 4441 | { | 4419 | { |
| 4442 | x = TYPE_MINIMUM (printmax_t); | 4420 | x = TYPE_MINIMUM (printmax_t); |
| @@ -4456,11 +4434,11 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4456 | { | 4434 | { |
| 4457 | /* Don't sign-extend for octal or hex printing. */ | 4435 | /* Don't sign-extend for octal or hex printing. */ |
| 4458 | uprintmax_t x; | 4436 | uprintmax_t x; |
| 4459 | if (INTEGERP (info[ispec].argument)) | 4437 | if (INTEGERP (arg)) |
| 4460 | x = XUINT (info[ispec].argument); | 4438 | x = XUINT (arg); |
| 4461 | else | 4439 | else |
| 4462 | { | 4440 | { |
| 4463 | double d = XFLOAT_DATA (info[ispec].argument); | 4441 | double d = XFLOAT_DATA (arg); |
| 4464 | if (d < 0) | 4442 | if (d < 0) |
| 4465 | x = 0; | 4443 | x = 0; |
| 4466 | else | 4444 | else |
| @@ -4541,7 +4519,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4541 | exponent_bytes = src + sprintf_bytes - e; | 4519 | exponent_bytes = src + sprintf_bytes - e; |
| 4542 | } | 4520 | } |
| 4543 | 4521 | ||
| 4544 | info[ispec].start = nchars; | 4522 | spec->start = nchars; |
| 4545 | if (! minus_flag) | 4523 | if (! minus_flag) |
| 4546 | { | 4524 | { |
| 4547 | memset (p, ' ', padding); | 4525 | memset (p, ' ', padding); |
| @@ -4572,7 +4550,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4572 | p += padding; | 4550 | p += padding; |
| 4573 | nchars += padding; | 4551 | nchars += padding; |
| 4574 | } | 4552 | } |
| 4575 | info[ispec].end = nchars; | 4553 | spec->end = nchars; |
| 4576 | 4554 | ||
| 4577 | continue; | 4555 | continue; |
| 4578 | } | 4556 | } |
| @@ -4681,7 +4659,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4681 | if (CONSP (props)) | 4659 | if (CONSP (props)) |
| 4682 | { | 4660 | { |
| 4683 | ptrdiff_t bytepos = 0, position = 0, translated = 0; | 4661 | ptrdiff_t bytepos = 0, position = 0, translated = 0; |
| 4684 | ptrdiff_t fieldn = 1; | 4662 | ptrdiff_t fieldn = 0; |
| 4685 | 4663 | ||
| 4686 | /* Adjust the bounds of each text property | 4664 | /* Adjust the bounds of each text property |
| 4687 | to the proper start and end in the output string. */ | 4665 | to the proper start and end in the output string. */ |
| @@ -4747,7 +4725,7 @@ styled_format (ptrdiff_t nargs, Lisp_Object *args, bool message) | |||
| 4747 | 4725 | ||
| 4748 | /* Add text properties from arguments. */ | 4726 | /* Add text properties from arguments. */ |
| 4749 | if (arg_intervals) | 4727 | if (arg_intervals) |
| 4750 | for (ptrdiff_t i = 1; i <= num_percent; i++) | 4728 | for (ptrdiff_t i = 0; i < nspec; i++) |
| 4751 | if (info[i].intervals) | 4729 | if (info[i].intervals) |
| 4752 | { | 4730 | { |
| 4753 | len = make_number (SCHARS (info[i].argument)); | 4731 | len = make_number (SCHARS (info[i].argument)); |