Mercurial > vim
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 |