comparison src/message.c @ 25567:0082503ff2ff v8.2.3320

patch 8.2.3320: some local functions are not static Commit: https://github.com/vim/vim/commit/8ee52affe7fd4daa03e002bc06611f0a8c3bcd5b Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Mon Aug 9 19:59:06 2021 +0200 patch 8.2.3320: some local functions are not static Problem: Some local functions are not static. Solution: Add "static". Move snprintf() related code to strings.c. (Yegappan Lakshmanan, closes #8734)
author Bram Moolenaar <Bram@vim.org>
date Mon, 09 Aug 2021 20:00:06 +0200
parents a9ea83a3659a
children f8bcd21e6e24
comparison
equal deleted inserted replaced
25566:e1c7aa26ddf5 25567:0082503ff2ff
10 /* 10 /*
11 * message.c: functions for displaying messages on the command line 11 * message.c: functions for displaying messages on the command line
12 */ 12 */
13 13
14 #define MESSAGE_FILE // don't include prototype for smsg() 14 #define MESSAGE_FILE // don't include prototype for smsg()
15 #define USING_FLOAT_STUFF
16 15
17 #include "vim.h" 16 #include "vim.h"
18 17
19 static void add_msg_hist(char_u *s, int len, int attr); 18 static void add_msg_hist(char_u *s, int len, int attr);
20 static void hit_return_msg(void); 19 static void hit_return_msg(void);
4106 } 4105 }
4107 return VIM_CANCEL; 4106 return VIM_CANCEL;
4108 } 4107 }
4109 4108
4110 #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG 4109 #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG
4111
4112 #if defined(FEAT_EVAL)
4113 static char *e_printf = N_("E766: Insufficient arguments for printf()");
4114
4115 /*
4116 * Get number argument from "idxp" entry in "tvs". First entry is 1.
4117 */
4118 static varnumber_T
4119 tv_nr(typval_T *tvs, int *idxp)
4120 {
4121 int idx = *idxp - 1;
4122 varnumber_T n = 0;
4123 int err = FALSE;
4124
4125 if (tvs[idx].v_type == VAR_UNKNOWN)
4126 emsg(_(e_printf));
4127 else
4128 {
4129 ++*idxp;
4130 n = tv_get_number_chk(&tvs[idx], &err);
4131 if (err)
4132 n = 0;
4133 }
4134 return n;
4135 }
4136
4137 /*
4138 * Get string argument from "idxp" entry in "tvs". First entry is 1.
4139 * If "tofree" is NULL tv_get_string_chk() is used. Some types (e.g. List)
4140 * are not converted to a string.
4141 * If "tofree" is not NULL echo_string() is used. All types are converted to
4142 * a string with the same format as ":echo". The caller must free "*tofree".
4143 * Returns NULL for an error.
4144 */
4145 static char *
4146 tv_str(typval_T *tvs, int *idxp, char_u **tofree)
4147 {
4148 int idx = *idxp - 1;
4149 char *s = NULL;
4150 static char_u numbuf[NUMBUFLEN];
4151
4152 if (tvs[idx].v_type == VAR_UNKNOWN)
4153 emsg(_(e_printf));
4154 else
4155 {
4156 ++*idxp;
4157 if (tofree != NULL)
4158 s = (char *)echo_string(&tvs[idx], tofree, numbuf, get_copyID());
4159 else
4160 s = (char *)tv_get_string_chk(&tvs[idx]);
4161 }
4162 return s;
4163 }
4164
4165 # ifdef FEAT_FLOAT
4166 /*
4167 * Get float argument from "idxp" entry in "tvs". First entry is 1.
4168 */
4169 static double
4170 tv_float(typval_T *tvs, int *idxp)
4171 {
4172 int idx = *idxp - 1;
4173 double f = 0;
4174
4175 if (tvs[idx].v_type == VAR_UNKNOWN)
4176 emsg(_(e_printf));
4177 else
4178 {
4179 ++*idxp;
4180 if (tvs[idx].v_type == VAR_FLOAT)
4181 f = tvs[idx].vval.v_float;
4182 else if (tvs[idx].v_type == VAR_NUMBER)
4183 f = (double)tvs[idx].vval.v_number;
4184 else
4185 emsg(_("E807: Expected Float argument for printf()"));
4186 }
4187 return f;
4188 }
4189 # endif
4190 #endif
4191
4192 #ifdef FEAT_FLOAT
4193 /*
4194 * Return the representation of infinity for printf() function:
4195 * "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
4196 */
4197 static const char *
4198 infinity_str(int positive,
4199 char fmt_spec,
4200 int force_sign,
4201 int space_for_positive)
4202 {
4203 static const char *table[] =
4204 {
4205 "-inf", "inf", "+inf", " inf",
4206 "-INF", "INF", "+INF", " INF"
4207 };
4208 int idx = positive * (1 + force_sign + force_sign * space_for_positive);
4209
4210 if (ASCII_ISUPPER(fmt_spec))
4211 idx += 4;
4212 return table[idx];
4213 }
4214 #endif
4215
4216 /*
4217 * This code was included to provide a portable vsnprintf() and snprintf().
4218 * Some systems may provide their own, but we always use this one for
4219 * consistency.
4220 *
4221 * This code is based on snprintf.c - a portable implementation of snprintf
4222 * by Mark Martinec <mark.martinec@ijs.si>, Version 2.2, 2000-10-06.
4223 * Included with permission. It was heavily modified to fit in Vim.
4224 * The original code, including useful comments, can be found here:
4225 * http://www.ijs.si/software/snprintf/
4226 *
4227 * This snprintf() only supports the following conversion specifiers:
4228 * s, c, d, u, o, x, X, p (and synonyms: i, D, U, O - see below)
4229 * with flags: '-', '+', ' ', '0' and '#'.
4230 * An asterisk is supported for field width as well as precision.
4231 *
4232 * Limited support for floating point was added: 'f', 'F', 'e', 'E', 'g', 'G'.
4233 *
4234 * Length modifiers 'h' (short int) and 'l' (long int) and 'll' (long long int)
4235 * are supported. NOTE: for 'll' the argument is varnumber_T or uvarnumber_T.
4236 *
4237 * The locale is not used, the string is used as a byte string. This is only
4238 * relevant for double-byte encodings where the second byte may be '%'.
4239 *
4240 * It is permitted for "str_m" to be zero, and it is permitted to specify NULL
4241 * pointer for resulting string argument if "str_m" is zero (as per ISO C99).
4242 *
4243 * The return value is the number of characters which would be generated
4244 * for the given input, excluding the trailing NUL. If this value
4245 * is greater or equal to "str_m", not all characters from the result
4246 * have been stored in str, output bytes beyond the ("str_m"-1) -th character
4247 * are discarded. If "str_m" is greater than zero it is guaranteed
4248 * the resulting string will be NUL-terminated.
4249 */
4250
4251 /*
4252 * When va_list is not supported we only define vim_snprintf().
4253 *
4254 * vim_vsnprintf_typval() can be invoked with either "va_list" or a list of
4255 * "typval_T". When the latter is not used it must be NULL.
4256 */
4257
4258 // When generating prototypes all of this is skipped, cproto doesn't
4259 // understand this.
4260 #ifndef PROTO
4261
4262 // Like vim_vsnprintf() but append to the string.
4263 int
4264 vim_snprintf_add(char *str, size_t str_m, const char *fmt, ...)
4265 {
4266 va_list ap;
4267 int str_l;
4268 size_t len = STRLEN(str);
4269 size_t space;
4270
4271 if (str_m <= len)
4272 space = 0;
4273 else
4274 space = str_m - len;
4275 va_start(ap, fmt);
4276 str_l = vim_vsnprintf(str + len, space, fmt, ap);
4277 va_end(ap);
4278 return str_l;
4279 }
4280
4281 int
4282 vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
4283 {
4284 va_list ap;
4285 int str_l;
4286
4287 va_start(ap, fmt);
4288 str_l = vim_vsnprintf(str, str_m, fmt, ap);
4289 va_end(ap);
4290 return str_l;
4291 }
4292
4293 int
4294 vim_vsnprintf(
4295 char *str,
4296 size_t str_m,
4297 const char *fmt,
4298 va_list ap)
4299 {
4300 return vim_vsnprintf_typval(str, str_m, fmt, ap, NULL);
4301 }
4302
4303 int
4304 vim_vsnprintf_typval(
4305 char *str,
4306 size_t str_m,
4307 const char *fmt,
4308 va_list ap,
4309 typval_T *tvs)
4310 {
4311 size_t str_l = 0;
4312 const char *p = fmt;
4313 int arg_idx = 1;
4314
4315 if (p == NULL)
4316 p = "";
4317 while (*p != NUL)
4318 {
4319 if (*p != '%')
4320 {
4321 char *q = strchr(p + 1, '%');
4322 size_t n = (q == NULL) ? STRLEN(p) : (size_t)(q - p);
4323
4324 // Copy up to the next '%' or NUL without any changes.
4325 if (str_l < str_m)
4326 {
4327 size_t avail = str_m - str_l;
4328
4329 mch_memmove(str + str_l, p, n > avail ? avail : n);
4330 }
4331 p += n;
4332 str_l += n;
4333 }
4334 else
4335 {
4336 size_t min_field_width = 0, precision = 0;
4337 int zero_padding = 0, precision_specified = 0, justify_left = 0;
4338 int alternate_form = 0, force_sign = 0;
4339
4340 // If both the ' ' and '+' flags appear, the ' ' flag should be
4341 // ignored.
4342 int space_for_positive = 1;
4343
4344 // allowed values: \0, h, l, L
4345 char length_modifier = '\0';
4346
4347 // temporary buffer for simple numeric->string conversion
4348 # if defined(FEAT_FLOAT)
4349 # define TMP_LEN 350 // On my system 1e308 is the biggest number possible.
4350 // That sounds reasonable to use as the maximum
4351 // printable.
4352 # else
4353 # define TMP_LEN 66
4354 # endif
4355 char tmp[TMP_LEN];
4356
4357 // string address in case of string argument
4358 const char *str_arg = NULL;
4359
4360 // natural field width of arg without padding and sign
4361 size_t str_arg_l;
4362
4363 // unsigned char argument value - only defined for c conversion.
4364 // N.B. standard explicitly states the char argument for the c
4365 // conversion is unsigned
4366 unsigned char uchar_arg;
4367
4368 // number of zeros to be inserted for numeric conversions as
4369 // required by the precision or minimal field width
4370 size_t number_of_zeros_to_pad = 0;
4371
4372 // index into tmp where zero padding is to be inserted
4373 size_t zero_padding_insertion_ind = 0;
4374
4375 // current conversion specifier character
4376 char fmt_spec = '\0';
4377
4378 // buffer for 's' and 'S' specs
4379 char_u *tofree = NULL;
4380
4381
4382 p++; // skip '%'
4383
4384 // parse flags
4385 while (*p == '0' || *p == '-' || *p == '+' || *p == ' '
4386 || *p == '#' || *p == '\'')
4387 {
4388 switch (*p)
4389 {
4390 case '0': zero_padding = 1; break;
4391 case '-': justify_left = 1; break;
4392 case '+': force_sign = 1; space_for_positive = 0; break;
4393 case ' ': force_sign = 1;
4394 // If both the ' ' and '+' flags appear, the ' '
4395 // flag should be ignored
4396 break;
4397 case '#': alternate_form = 1; break;
4398 case '\'': break;
4399 }
4400 p++;
4401 }
4402 // If the '0' and '-' flags both appear, the '0' flag should be
4403 // ignored.
4404
4405 // parse field width
4406 if (*p == '*')
4407 {
4408 int j;
4409
4410 p++;
4411 j =
4412 # if defined(FEAT_EVAL)
4413 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4414 # endif
4415 va_arg(ap, int);
4416 if (j >= 0)
4417 min_field_width = j;
4418 else
4419 {
4420 min_field_width = -j;
4421 justify_left = 1;
4422 }
4423 }
4424 else if (VIM_ISDIGIT((int)(*p)))
4425 {
4426 // size_t could be wider than unsigned int; make sure we treat
4427 // argument like common implementations do
4428 unsigned int uj = *p++ - '0';
4429
4430 while (VIM_ISDIGIT((int)(*p)))
4431 uj = 10 * uj + (unsigned int)(*p++ - '0');
4432 min_field_width = uj;
4433 }
4434
4435 // parse precision
4436 if (*p == '.')
4437 {
4438 p++;
4439 precision_specified = 1;
4440 if (*p == '*')
4441 {
4442 int j;
4443
4444 j =
4445 # if defined(FEAT_EVAL)
4446 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4447 # endif
4448 va_arg(ap, int);
4449 p++;
4450 if (j >= 0)
4451 precision = j;
4452 else
4453 {
4454 precision_specified = 0;
4455 precision = 0;
4456 }
4457 }
4458 else if (VIM_ISDIGIT((int)(*p)))
4459 {
4460 // size_t could be wider than unsigned int; make sure we
4461 // treat argument like common implementations do
4462 unsigned int uj = *p++ - '0';
4463
4464 while (VIM_ISDIGIT((int)(*p)))
4465 uj = 10 * uj + (unsigned int)(*p++ - '0');
4466 precision = uj;
4467 }
4468 }
4469
4470 // parse 'h', 'l' and 'll' length modifiers
4471 if (*p == 'h' || *p == 'l')
4472 {
4473 length_modifier = *p;
4474 p++;
4475 if (length_modifier == 'l' && *p == 'l')
4476 {
4477 // double l = __int64 / varnumber_T
4478 length_modifier = 'L';
4479 p++;
4480 }
4481 }
4482 fmt_spec = *p;
4483
4484 // common synonyms:
4485 switch (fmt_spec)
4486 {
4487 case 'i': fmt_spec = 'd'; break;
4488 case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
4489 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
4490 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
4491 default: break;
4492 }
4493
4494 # if defined(FEAT_EVAL)
4495 switch (fmt_spec)
4496 {
4497 case 'd': case 'u': case 'o': case 'x': case 'X':
4498 if (tvs != NULL && length_modifier == '\0')
4499 length_modifier = 'L';
4500 }
4501 # endif
4502
4503 // get parameter value, do initial processing
4504 switch (fmt_spec)
4505 {
4506 // '%' and 'c' behave similar to 's' regarding flags and field
4507 // widths
4508 case '%':
4509 case 'c':
4510 case 's':
4511 case 'S':
4512 str_arg_l = 1;
4513 switch (fmt_spec)
4514 {
4515 case '%':
4516 str_arg = p;
4517 break;
4518
4519 case 'c':
4520 {
4521 int j;
4522
4523 j =
4524 # if defined(FEAT_EVAL)
4525 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4526 # endif
4527 va_arg(ap, int);
4528 // standard demands unsigned char
4529 uchar_arg = (unsigned char)j;
4530 str_arg = (char *)&uchar_arg;
4531 break;
4532 }
4533
4534 case 's':
4535 case 'S':
4536 str_arg =
4537 # if defined(FEAT_EVAL)
4538 tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) :
4539 # endif
4540 va_arg(ap, char *);
4541 if (str_arg == NULL)
4542 {
4543 str_arg = "[NULL]";
4544 str_arg_l = 6;
4545 }
4546 // make sure not to address string beyond the specified
4547 // precision !!!
4548 else if (!precision_specified)
4549 str_arg_l = strlen(str_arg);
4550 // truncate string if necessary as requested by precision
4551 else if (precision == 0)
4552 str_arg_l = 0;
4553 else
4554 {
4555 // Don't put the #if inside memchr(), it can be a
4556 // macro.
4557 // memchr on HP does not like n > 2^31 !!!
4558 char *q = memchr(str_arg, '\0',
4559 precision <= (size_t)0x7fffffffL ? precision
4560 : (size_t)0x7fffffffL);
4561 str_arg_l = (q == NULL) ? precision
4562 : (size_t)(q - str_arg);
4563 }
4564 if (fmt_spec == 'S')
4565 {
4566 if (min_field_width != 0)
4567 min_field_width += STRLEN(str_arg)
4568 - mb_string2cells((char_u *)str_arg, -1);
4569 if (precision)
4570 {
4571 char_u *p1;
4572 size_t i = 0;
4573
4574 for (p1 = (char_u *)str_arg; *p1;
4575 p1 += mb_ptr2len(p1))
4576 {
4577 i += (size_t)mb_ptr2cells(p1);
4578 if (i > precision)
4579 break;
4580 }
4581 str_arg_l = precision = p1 - (char_u *)str_arg;
4582 }
4583 }
4584 break;
4585
4586 default:
4587 break;
4588 }
4589 break;
4590
4591 case 'd': case 'u':
4592 case 'b': case 'B':
4593 case 'o':
4594 case 'x': case 'X':
4595 case 'p':
4596 {
4597 // NOTE: the u, b, o, x, X and p conversion specifiers
4598 // imply the value is unsigned; d implies a signed
4599 // value
4600
4601 // 0 if numeric argument is zero (or if pointer is
4602 // NULL for 'p'), +1 if greater than zero (or nonzero
4603 // for unsigned arguments), -1 if negative (unsigned
4604 // argument is never negative)
4605 int arg_sign = 0;
4606
4607 // only set for length modifier h, or for no length
4608 // modifiers
4609 int int_arg = 0;
4610 unsigned int uint_arg = 0;
4611
4612 // only set for length modifier l
4613 long int long_arg = 0;
4614 unsigned long int ulong_arg = 0;
4615
4616 // only set for length modifier ll
4617 varnumber_T llong_arg = 0;
4618 uvarnumber_T ullong_arg = 0;
4619
4620 // only set for b conversion
4621 uvarnumber_T bin_arg = 0;
4622
4623 // pointer argument value -only defined for p
4624 // conversion
4625 void *ptr_arg = NULL;
4626
4627 if (fmt_spec == 'p')
4628 {
4629 length_modifier = '\0';
4630 ptr_arg =
4631 # if defined(FEAT_EVAL)
4632 tvs != NULL ? (void *)tv_str(tvs, &arg_idx,
4633 NULL) :
4634 # endif
4635 va_arg(ap, void *);
4636 if (ptr_arg != NULL)
4637 arg_sign = 1;
4638 }
4639 else if (fmt_spec == 'b' || fmt_spec == 'B')
4640 {
4641 bin_arg =
4642 # if defined(FEAT_EVAL)
4643 tvs != NULL ?
4644 (uvarnumber_T)tv_nr(tvs, &arg_idx) :
4645 # endif
4646 va_arg(ap, uvarnumber_T);
4647 if (bin_arg != 0)
4648 arg_sign = 1;
4649 }
4650 else if (fmt_spec == 'd')
4651 {
4652 // signed
4653 switch (length_modifier)
4654 {
4655 case '\0':
4656 case 'h':
4657 // char and short arguments are passed as int.
4658 int_arg =
4659 # if defined(FEAT_EVAL)
4660 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4661 # endif
4662 va_arg(ap, int);
4663 if (int_arg > 0)
4664 arg_sign = 1;
4665 else if (int_arg < 0)
4666 arg_sign = -1;
4667 break;
4668 case 'l':
4669 long_arg =
4670 # if defined(FEAT_EVAL)
4671 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4672 # endif
4673 va_arg(ap, long int);
4674 if (long_arg > 0)
4675 arg_sign = 1;
4676 else if (long_arg < 0)
4677 arg_sign = -1;
4678 break;
4679 case 'L':
4680 llong_arg =
4681 # if defined(FEAT_EVAL)
4682 tvs != NULL ? tv_nr(tvs, &arg_idx) :
4683 # endif
4684 va_arg(ap, varnumber_T);
4685 if (llong_arg > 0)
4686 arg_sign = 1;
4687 else if (llong_arg < 0)
4688 arg_sign = -1;
4689 break;
4690 }
4691 }
4692 else
4693 {
4694 // unsigned
4695 switch (length_modifier)
4696 {
4697 case '\0':
4698 case 'h':
4699 uint_arg =
4700 # if defined(FEAT_EVAL)
4701 tvs != NULL ? (unsigned)
4702 tv_nr(tvs, &arg_idx) :
4703 # endif
4704 va_arg(ap, unsigned int);
4705 if (uint_arg != 0)
4706 arg_sign = 1;
4707 break;
4708 case 'l':
4709 ulong_arg =
4710 # if defined(FEAT_EVAL)
4711 tvs != NULL ? (unsigned long)
4712 tv_nr(tvs, &arg_idx) :
4713 # endif
4714 va_arg(ap, unsigned long int);
4715 if (ulong_arg != 0)
4716 arg_sign = 1;
4717 break;
4718 case 'L':
4719 ullong_arg =
4720 # if defined(FEAT_EVAL)
4721 tvs != NULL ? (uvarnumber_T)
4722 tv_nr(tvs, &arg_idx) :
4723 # endif
4724 va_arg(ap, uvarnumber_T);
4725 if (ullong_arg != 0)
4726 arg_sign = 1;
4727 break;
4728 }
4729 }
4730
4731 str_arg = tmp;
4732 str_arg_l = 0;
4733
4734 // NOTE:
4735 // For d, i, u, o, x, and X conversions, if precision is
4736 // specified, the '0' flag should be ignored. This is so
4737 // with Solaris 2.6, Digital UNIX 4.0, HPUX 10, Linux,
4738 // FreeBSD, NetBSD; but not with Perl.
4739 if (precision_specified)
4740 zero_padding = 0;
4741 if (fmt_spec == 'd')
4742 {
4743 if (force_sign && arg_sign >= 0)
4744 tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
4745 // leave negative numbers for sprintf to handle, to
4746 // avoid handling tricky cases like (short int)-32768
4747 }
4748 else if (alternate_form)
4749 {
4750 if (arg_sign != 0
4751 && (fmt_spec == 'b' || fmt_spec == 'B'
4752 || fmt_spec == 'x' || fmt_spec == 'X') )
4753 {
4754 tmp[str_arg_l++] = '0';
4755 tmp[str_arg_l++] = fmt_spec;
4756 }
4757 // alternate form should have no effect for p
4758 // conversion, but ...
4759 }
4760
4761 zero_padding_insertion_ind = str_arg_l;
4762 if (!precision_specified)
4763 precision = 1; // default precision is 1
4764 if (precision == 0 && arg_sign == 0)
4765 {
4766 // When zero value is formatted with an explicit
4767 // precision 0, the resulting formatted string is
4768 // empty (d, i, u, b, B, o, x, X, p).
4769 }
4770 else
4771 {
4772 char f[6];
4773 int f_l = 0;
4774
4775 // construct a simple format string for sprintf
4776 f[f_l++] = '%';
4777 if (!length_modifier)
4778 ;
4779 else if (length_modifier == 'L')
4780 {
4781 # ifdef MSWIN
4782 f[f_l++] = 'I';
4783 f[f_l++] = '6';
4784 f[f_l++] = '4';
4785 # else
4786 f[f_l++] = 'l';
4787 f[f_l++] = 'l';
4788 # endif
4789 }
4790 else
4791 f[f_l++] = length_modifier;
4792 f[f_l++] = fmt_spec;
4793 f[f_l++] = '\0';
4794
4795 if (fmt_spec == 'p')
4796 str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg);
4797 else if (fmt_spec == 'b' || fmt_spec == 'B')
4798 {
4799 char b[8 * sizeof(uvarnumber_T)];
4800 size_t b_l = 0;
4801 uvarnumber_T bn = bin_arg;
4802
4803 do
4804 {
4805 b[sizeof(b) - ++b_l] = '0' + (bn & 0x1);
4806 bn >>= 1;
4807 }
4808 while (bn != 0);
4809
4810 memcpy(tmp + str_arg_l, b + sizeof(b) - b_l, b_l);
4811 str_arg_l += b_l;
4812 }
4813 else if (fmt_spec == 'd')
4814 {
4815 // signed
4816 switch (length_modifier)
4817 {
4818 case '\0': str_arg_l += sprintf(
4819 tmp + str_arg_l, f,
4820 int_arg);
4821 break;
4822 case 'h': str_arg_l += sprintf(
4823 tmp + str_arg_l, f,
4824 (short)int_arg);
4825 break;
4826 case 'l': str_arg_l += sprintf(
4827 tmp + str_arg_l, f, long_arg);
4828 break;
4829 case 'L': str_arg_l += sprintf(
4830 tmp + str_arg_l, f, llong_arg);
4831 break;
4832 }
4833 }
4834 else
4835 {
4836 // unsigned
4837 switch (length_modifier)
4838 {
4839 case '\0': str_arg_l += sprintf(
4840 tmp + str_arg_l, f,
4841 uint_arg);
4842 break;
4843 case 'h': str_arg_l += sprintf(
4844 tmp + str_arg_l, f,
4845 (unsigned short)uint_arg);
4846 break;
4847 case 'l': str_arg_l += sprintf(
4848 tmp + str_arg_l, f, ulong_arg);
4849 break;
4850 case 'L': str_arg_l += sprintf(
4851 tmp + str_arg_l, f, ullong_arg);
4852 break;
4853 }
4854 }
4855
4856 // include the optional minus sign and possible
4857 // "0x" in the region before the zero padding
4858 // insertion point
4859 if (zero_padding_insertion_ind < str_arg_l
4860 && tmp[zero_padding_insertion_ind] == '-')
4861 zero_padding_insertion_ind++;
4862 if (zero_padding_insertion_ind + 1 < str_arg_l
4863 && tmp[zero_padding_insertion_ind] == '0'
4864 && (tmp[zero_padding_insertion_ind + 1] == 'x'
4865 || tmp[zero_padding_insertion_ind + 1] == 'X'))
4866 zero_padding_insertion_ind += 2;
4867 }
4868
4869 {
4870 size_t num_of_digits = str_arg_l
4871 - zero_padding_insertion_ind;
4872
4873 if (alternate_form && fmt_spec == 'o'
4874 // unless zero is already the first
4875 // character
4876 && !(zero_padding_insertion_ind < str_arg_l
4877 && tmp[zero_padding_insertion_ind] == '0'))
4878 {
4879 // assure leading zero for alternate-form
4880 // octal numbers
4881 if (!precision_specified
4882 || precision < num_of_digits + 1)
4883 {
4884 // precision is increased to force the
4885 // first character to be zero, except if a
4886 // zero value is formatted with an
4887 // explicit precision of zero
4888 precision = num_of_digits + 1;
4889 }
4890 }
4891 // zero padding to specified precision?
4892 if (num_of_digits < precision)
4893 number_of_zeros_to_pad = precision - num_of_digits;
4894 }
4895 // zero padding to specified minimal field width?
4896 if (!justify_left && zero_padding)
4897 {
4898 int n = (int)(min_field_width - (str_arg_l
4899 + number_of_zeros_to_pad));
4900 if (n > 0)
4901 number_of_zeros_to_pad += n;
4902 }
4903 break;
4904 }
4905
4906 # ifdef FEAT_FLOAT
4907 case 'f':
4908 case 'F':
4909 case 'e':
4910 case 'E':
4911 case 'g':
4912 case 'G':
4913 {
4914 // Floating point.
4915 double f;
4916 double abs_f;
4917 char format[40];
4918 int l;
4919 int remove_trailing_zeroes = FALSE;
4920
4921 f =
4922 # if defined(FEAT_EVAL)
4923 tvs != NULL ? tv_float(tvs, &arg_idx) :
4924 # endif
4925 va_arg(ap, double);
4926 abs_f = f < 0 ? -f : f;
4927
4928 if (fmt_spec == 'g' || fmt_spec == 'G')
4929 {
4930 // Would be nice to use %g directly, but it prints
4931 // "1.0" as "1", we don't want that.
4932 if ((abs_f >= 0.001 && abs_f < 10000000.0)
4933 || abs_f == 0.0)
4934 fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
4935 else
4936 fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
4937 remove_trailing_zeroes = TRUE;
4938 }
4939
4940 if ((fmt_spec == 'f' || fmt_spec == 'F') &&
4941 # ifdef VAX
4942 abs_f > 1.0e38
4943 # else
4944 abs_f > 1.0e307
4945 # endif
4946 )
4947 {
4948 // Avoid a buffer overflow
4949 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
4950 force_sign, space_for_positive));
4951 str_arg_l = STRLEN(tmp);
4952 zero_padding = 0;
4953 }
4954 else
4955 {
4956 if (isnan(f))
4957 {
4958 // Not a number: nan or NAN
4959 STRCPY(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN"
4960 : "nan");
4961 str_arg_l = 3;
4962 zero_padding = 0;
4963 }
4964 else if (isinf(f))
4965 {
4966 STRCPY(tmp, infinity_str(f > 0.0, fmt_spec,
4967 force_sign, space_for_positive));
4968 str_arg_l = STRLEN(tmp);
4969 zero_padding = 0;
4970 }
4971 else
4972 {
4973 // Regular float number
4974 format[0] = '%';
4975 l = 1;
4976 if (force_sign)
4977 format[l++] = space_for_positive ? ' ' : '+';
4978 if (precision_specified)
4979 {
4980 size_t max_prec = TMP_LEN - 10;
4981
4982 // Make sure we don't get more digits than we
4983 // have room for.
4984 if ((fmt_spec == 'f' || fmt_spec == 'F')
4985 && abs_f > 1.0)
4986 max_prec -= (size_t)log10(abs_f);
4987 if (precision > max_prec)
4988 precision = max_prec;
4989 l += sprintf(format + l, ".%d", (int)precision);
4990 }
4991 format[l] = fmt_spec == 'F' ? 'f' : fmt_spec;
4992 format[l + 1] = NUL;
4993
4994 str_arg_l = sprintf(tmp, format, f);
4995 }
4996
4997 if (remove_trailing_zeroes)
4998 {
4999 int i;
5000 char *tp;
5001
5002 // Using %g or %G: remove superfluous zeroes.
5003 if (fmt_spec == 'f' || fmt_spec == 'F')
5004 tp = tmp + str_arg_l - 1;
5005 else
5006 {
5007 tp = (char *)vim_strchr((char_u *)tmp,
5008 fmt_spec == 'e' ? 'e' : 'E');
5009 if (tp != NULL)
5010 {
5011 // Remove superfluous '+' and leading
5012 // zeroes from the exponent.
5013 if (tp[1] == '+')
5014 {
5015 // Change "1.0e+07" to "1.0e07"
5016 STRMOVE(tp + 1, tp + 2);
5017 --str_arg_l;
5018 }
5019 i = (tp[1] == '-') ? 2 : 1;
5020 while (tp[i] == '0')
5021 {
5022 // Change "1.0e07" to "1.0e7"
5023 STRMOVE(tp + i, tp + i + 1);
5024 --str_arg_l;
5025 }
5026 --tp;
5027 }
5028 }
5029
5030 if (tp != NULL && !precision_specified)
5031 // Remove trailing zeroes, but keep the one
5032 // just after a dot.
5033 while (tp > tmp + 2 && *tp == '0'
5034 && tp[-1] != '.')
5035 {
5036 STRMOVE(tp, tp + 1);
5037 --tp;
5038 --str_arg_l;
5039 }
5040 }
5041 else
5042 {
5043 char *tp;
5044
5045 // Be consistent: some printf("%e") use 1.0e+12
5046 // and some 1.0e+012. Remove one zero in the last
5047 // case.
5048 tp = (char *)vim_strchr((char_u *)tmp,
5049 fmt_spec == 'e' ? 'e' : 'E');
5050 if (tp != NULL && (tp[1] == '+' || tp[1] == '-')
5051 && tp[2] == '0'
5052 && vim_isdigit(tp[3])
5053 && vim_isdigit(tp[4]))
5054 {
5055 STRMOVE(tp + 2, tp + 3);
5056 --str_arg_l;
5057 }
5058 }
5059 }
5060 if (zero_padding && min_field_width > str_arg_l
5061 && (tmp[0] == '-' || force_sign))
5062 {
5063 // padding 0's should be inserted after the sign
5064 number_of_zeros_to_pad = min_field_width - str_arg_l;
5065 zero_padding_insertion_ind = 1;
5066 }
5067 str_arg = tmp;
5068 break;
5069 }
5070 # endif
5071
5072 default:
5073 // unrecognized conversion specifier, keep format string
5074 // as-is
5075 zero_padding = 0; // turn zero padding off for non-numeric
5076 // conversion
5077 justify_left = 1;
5078 min_field_width = 0; // reset flags
5079
5080 // discard the unrecognized conversion, just keep *
5081 // the unrecognized conversion character
5082 str_arg = p;
5083 str_arg_l = 0;
5084 if (*p != NUL)
5085 str_arg_l++; // include invalid conversion specifier
5086 // unchanged if not at end-of-string
5087 break;
5088 }
5089
5090 if (*p != NUL)
5091 p++; // step over the just processed conversion specifier
5092
5093 // insert padding to the left as requested by min_field_width;
5094 // this does not include the zero padding in case of numerical
5095 // conversions
5096 if (!justify_left)
5097 {
5098 // left padding with blank or zero
5099 int pn = (int)(min_field_width - (str_arg_l + number_of_zeros_to_pad));
5100
5101 if (pn > 0)
5102 {
5103 if (str_l < str_m)
5104 {
5105 size_t avail = str_m - str_l;
5106
5107 vim_memset(str + str_l, zero_padding ? '0' : ' ',
5108 (size_t)pn > avail ? avail
5109 : (size_t)pn);
5110 }
5111 str_l += pn;
5112 }
5113 }
5114
5115 // zero padding as requested by the precision or by the minimal
5116 // field width for numeric conversions required?
5117 if (number_of_zeros_to_pad == 0)
5118 {
5119 // will not copy first part of numeric right now, *
5120 // force it to be copied later in its entirety
5121 zero_padding_insertion_ind = 0;
5122 }
5123 else
5124 {
5125 // insert first part of numerics (sign or '0x') before zero
5126 // padding
5127 int zn = (int)zero_padding_insertion_ind;
5128
5129 if (zn > 0)
5130 {
5131 if (str_l < str_m)
5132 {
5133 size_t avail = str_m - str_l;
5134
5135 mch_memmove(str + str_l, str_arg,
5136 (size_t)zn > avail ? avail
5137 : (size_t)zn);
5138 }
5139 str_l += zn;
5140 }
5141
5142 // insert zero padding as requested by the precision or min
5143 // field width
5144 zn = (int)number_of_zeros_to_pad;
5145 if (zn > 0)
5146 {
5147 if (str_l < str_m)
5148 {
5149 size_t avail = str_m - str_l;
5150
5151 vim_memset(str + str_l, '0',
5152 (size_t)zn > avail ? avail
5153 : (size_t)zn);
5154 }
5155 str_l += zn;
5156 }
5157 }
5158
5159 // insert formatted string
5160 // (or as-is conversion specifier for unknown conversions)
5161 {
5162 int sn = (int)(str_arg_l - zero_padding_insertion_ind);
5163
5164 if (sn > 0)
5165 {
5166 if (str_l < str_m)
5167 {
5168 size_t avail = str_m - str_l;
5169
5170 mch_memmove(str + str_l,
5171 str_arg + zero_padding_insertion_ind,
5172 (size_t)sn > avail ? avail : (size_t)sn);
5173 }
5174 str_l += sn;
5175 }
5176 }
5177
5178 // insert right padding
5179 if (justify_left)
5180 {
5181 // right blank padding to the field width
5182 int pn = (int)(min_field_width
5183 - (str_arg_l + number_of_zeros_to_pad));
5184
5185 if (pn > 0)
5186 {
5187 if (str_l < str_m)
5188 {
5189 size_t avail = str_m - str_l;
5190
5191 vim_memset(str + str_l, ' ',
5192 (size_t)pn > avail ? avail
5193 : (size_t)pn);
5194 }
5195 str_l += pn;
5196 }
5197 }
5198 vim_free(tofree);
5199 }
5200 }
5201
5202 if (str_m > 0)
5203 {
5204 // make sure the string is nul-terminated even at the expense of
5205 // overwriting the last character (shouldn't happen, but just in case)
5206 //
5207 str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0';
5208 }
5209
5210 if (tvs != NULL && tvs[arg_idx - 1].v_type != VAR_UNKNOWN)
5211 emsg(_("E767: Too many arguments to printf()"));
5212
5213 // Return the number of characters formatted (excluding trailing nul
5214 // character), that is, the number of characters that would have been
5215 // written to the buffer if it were large enough.
5216 return (int)str_l;
5217 }
5218
5219 #endif // PROTO