diff options
Diffstat (limited to 'src/nvim/message.c')
| -rw-r--r-- | src/nvim/message.c | 840 | 
1 files changed, 4 insertions, 836 deletions
| diff --git a/src/nvim/message.c b/src/nvim/message.c index 9d44b15f7c..5427ae7793 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -7,7 +7,6 @@  #include <stdbool.h>  #include <stdarg.h>  #include <string.h> -#include <math.h>  #include "nvim/vim.h"  #include "nvim/ascii.h" @@ -726,11 +725,11 @@ int delete_first_msg(void)    return OK;  } -/* - * ":messages" command. - */ -void ex_messages(exarg_T *eap) +/// :messages command implementation +void ex_messages(void *const eap_p) +  FUNC_ATTR_NONNULL_ALL  { +  exarg_T *eap = (exarg_T *)eap_p;    struct msg_hist *p;    int c = 0; @@ -3018,834 +3017,3 @@ int vim_dialog_yesnoallcancel(int type, char_u *title, char_u *message, int dflt    }    return VIM_CANCEL;  } - - - -static char *e_printf = N_("E766: Insufficient arguments for printf()"); - -/* - * Get number argument from "idxp" entry in "tvs".  First entry is 1. - */ -static long tv_nr(typval_T *tvs, int *idxp) -{ -  int idx = *idxp - 1; -  long n = 0; -  int err = FALSE; - -  if (tvs[idx].v_type == VAR_UNKNOWN) -    EMSG(_(e_printf)); -  else { -    ++*idxp; -    n = get_tv_number_chk(&tvs[idx], &err); -    if (err) -      n = 0; -  } -  return n; -} - -/* - * Get string argument from "idxp" entry in "tvs".  First entry is 1. - * Returns NULL for an error. - */ -static char *tv_str(typval_T *tvs, int *idxp) -{ -  int idx = *idxp - 1; -  char        *s = NULL; - -  if (tvs[idx].v_type == VAR_UNKNOWN) -    EMSG(_(e_printf)); -  else { -    ++*idxp; -    s = (char *)get_tv_string_chk(&tvs[idx]); -  } -  return s; -} - -/// Get pointer argument from the next entry in tvs -/// -/// First entry is 1. Returns NULL for an error. -/// -/// @param[in]  tvs  List of typval_T values. -/// @param[in,out]  idxp  Pointer to the index of the current value. -/// -/// @return Pointer stored in typval_T or NULL. -static const void *tv_ptr(const typval_T *const tvs, int *const idxp) -  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT -{ -#define OFF(attr) offsetof(union typval_vval_union, attr) -  STATIC_ASSERT( -      OFF(v_string) == OFF(v_list) -      && OFF(v_string) == OFF(v_dict) -      && OFF(v_string) == OFF(v_partial) -      && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) -      && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) -      && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), -      "Strings, dictionaries, lists and partials are expected to be pointers, " -      "so that all three of them can be accessed via v_string"); -#undef OFF -  const int idx = *idxp - 1; -  if (tvs[idx].v_type == VAR_UNKNOWN) { -    EMSG(_(e_printf)); -    return NULL; -  } else { -    (*idxp)++; -    return tvs[idx].vval.v_string; -  } -} - -/* - * Get float argument from "idxp" entry in "tvs".  First entry is 1. - */ -static double tv_float(typval_T *tvs, int *idxp) -{ -  int idx = *idxp - 1; -  double f = 0; - -  if (tvs[idx].v_type == VAR_UNKNOWN) -    EMSG(_(e_printf)); -  else { -    ++*idxp; -    if (tvs[idx].v_type == VAR_FLOAT) -      f = tvs[idx].vval.v_float; -    else if (tvs[idx].v_type == VAR_NUMBER) -      f = tvs[idx].vval.v_number; -    else -      EMSG(_("E807: Expected Float argument for printf()")); -  } -  return f; -} - -/* - * This code was included to provide a portable vsnprintf() and snprintf(). - * Some systems may provide their own, but we always use this one for - * consistency. - * - * This code is based on snprintf.c - a portable implementation of snprintf - * by Mark Martinec <mark.martinec@ijs.si>, Version 2.2, 2000-10-06. - * Included with permission.  It was heavily modified to fit in Vim. - * The original code, including useful comments, can be found here: - *	http://www.ijs.si/software/snprintf/ - * - * This snprintf() only supports the following conversion specifiers: - * s, c, b, B, d, u, o, x, X, p  (and synonyms: i, D, U, O - see below) - * with flags: '-', '+', ' ', '0' and '#'. - * An asterisk is supported for field width as well as precision. - * - * Limited support for floating point was added: 'f', 'e', 'E', 'g', 'G'. - * - * Length modifiers 'h' (short int) and 'l' (long int) are supported. - * 'll' (long long int) is not supported. - * - * The locale is not used, the string is used as a byte string.  This is only - * relevant for double-byte encodings where the second byte may be '%'. - * - * It is permitted for "str_m" to be zero, and it is permitted to specify NULL - * pointer for resulting string argument if "str_m" is zero (as per ISO C99). - * - * The return value is the number of characters which would be generated - * for the given input, excluding the trailing NUL. If this value - * is greater or equal to "str_m", not all characters from the result - * have been stored in str, output bytes beyond the ("str_m"-1) -th character - * are discarded. If "str_m" is greater than zero it is guaranteed - * the resulting string will be NUL-terminated. - */ - -/* - * When va_list is not supported we only define vim_snprintf(). - * - * vim_vsnprintf() can be invoked with either "va_list" or a list of - * "typval_T".  When the latter is not used it must be NULL. - */ - -/* Like vim_vsnprintf() but append to the string. */ -int vim_snprintf_add(char *str, size_t str_m, char *fmt, ...) -{ -  va_list ap; -  int str_l; -  size_t len = STRLEN(str); -  size_t space; - -  if (str_m <= len) -    space = 0; -  else -    space = str_m - len; -  va_start(ap, fmt); -  str_l = vim_vsnprintf(str + len, space, fmt, ap, NULL); -  va_end(ap); -  return str_l; -} - -int vim_snprintf(char *str, size_t str_m, const char *fmt, ...) -{ -  va_list ap; -  int str_l; - -  va_start(ap, fmt); -  str_l = vim_vsnprintf(str, str_m, fmt, ap, NULL); -  va_end(ap); -  return str_l; -} - -int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap, -                  typval_T *tvs) -{ -  size_t str_l = 0; -  bool str_avail = str_l < str_m; -  const char *p = fmt; -  int arg_idx = 1; - -  if (!p) { -    p = ""; -  } -  while (*p) { -    if (*p != '%') { -      // copy up to the next '%' or NUL without any changes -      size_t n = (size_t)(xstrchrnul(p + 1, '%') - p); -      if (str_avail) { -        size_t avail = str_m - str_l; -        memmove(str + str_l, p, MIN(n, avail)); -        str_avail = n < avail; -      } -      p += n; -      assert(n <= SIZE_MAX - str_l); -      str_l += n; -    } else { -      size_t min_field_width = 0, precision = 0; -      int zero_padding = 0, precision_specified = 0, justify_left = 0; -      int alternate_form = 0, force_sign = 0; - -      // if both ' ' and '+' flags appear, ' ' flag should be ignored -      int space_for_positive = 1; - -      // allowed values: \0, h, l, 2 (for ll), z, L -      char length_modifier = '\0'; - -      // temporary buffer for simple numeric->string conversion -# define TMP_LEN 350    // 1e308 seems reasonable as the maximum printable -      char tmp[TMP_LEN]; - -      // string address in case of string argument -      const char *str_arg; - -      // natural field width of arg without padding and sign -      size_t str_arg_l; - -      // unsigned char argument value (only defined for c conversion); -      // standard explicitly states the char argument for the c -      // conversion is unsigned -      unsigned char uchar_arg; - -      // number of zeros to be inserted for numeric conversions as -      // required by the precision or minimal field width -      size_t number_of_zeros_to_pad = 0; - -      // index into tmp where zero padding is to be inserted -      size_t zero_padding_insertion_ind = 0; - -      // current conversion specifier character -      char fmt_spec = '\0'; - -      str_arg = NULL; -      p++;  // skip '%' - -      // parse flags -      while (*p == '0' || *p == '-' || *p == '+' || *p == ' ' -             || *p == '#' || *p == '\'') { -        switch (*p) { -          case '0': zero_padding = 1; break; -          case '-': justify_left = 1; break; -                    // if both '0' and '-' flags appear, '0' should be ignored -          case '+': force_sign = 1; space_for_positive = 0; break; -          case ' ': force_sign = 1; break; -                    // if both ' ' and '+' flags appear, ' ' should be ignored -          case '#': alternate_form = 1; break; -          case '\'': break; -        } -        p++; -      } - -      // parse field width -      if (*p == '*') { -        p++; -        int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int); -        if (j >= 0) { -          min_field_width = j; -        } else { -          min_field_width = -j; -          justify_left = 1; -        } -      } else if (ascii_isdigit((int)(*p))) { -        // size_t could be wider than unsigned int; make sure we treat -        // argument like common implementations do -        unsigned int uj = *p++ - '0'; - -        while (ascii_isdigit((int)(*p))) { -          uj = 10 * uj + (unsigned int)(*p++ - '0'); -        } -        min_field_width = uj; -      } - -      // parse precision -      if (*p == '.') { -        p++; -        precision_specified = 1; -        if (*p == '*') { -          int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int); -          p++; -          if (j >= 0) { -            precision = j; -          } else { -            precision_specified = 0; -            precision = 0; -          } -        } else if (ascii_isdigit((int)(*p))) { -          // size_t could be wider than unsigned int; make sure we -          // treat argument like common implementations do -          unsigned int uj = *p++ - '0'; - -          while (ascii_isdigit((int)(*p))) { -            uj = 10 * uj + (unsigned int)(*p++ - '0'); -          } -          precision = uj; -        } -      } - -      // parse 'h', 'l', 'll' and 'z' length modifiers -      if (*p == 'h' || *p == 'l' || *p == 'z') { -        length_modifier = *p; -        p++; -        if (length_modifier == 'l' && *p == 'l') { // ll, encoded as 2 -          length_modifier = '2'; -          p++; -        } -      } - -      fmt_spec = *p; - -      // common synonyms -      switch (fmt_spec) { -        case 'i': fmt_spec = 'd'; break; -        case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; -        case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; -        case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; -        case 'F': fmt_spec = 'f'; break; -        default: break; -      } - -      // get parameter value, do initial processing -      switch (fmt_spec) { -      // '%' and 'c' behave similar to 's' regarding flags and field widths -      case '%': case 'c': case 's': case 'S': -        str_arg_l = 1; -        switch (fmt_spec) { -        case '%': -          str_arg = p; -          break; - -        case 'c': { -          int j = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int); -          // standard demands unsigned char -          uchar_arg = (unsigned char)j; -          str_arg = (char *)&uchar_arg; -          break; -        } - -        case 's': -        case 'S': -          str_arg = tvs ? tv_str(tvs, &arg_idx) : va_arg(ap, char *); -          if (!str_arg) { -            str_arg = "[NULL]"; -            str_arg_l = 6; -          } else if (!precision_specified) { -            // make sure not to address string beyond the specified precision -            str_arg_l = strlen(str_arg); -          } else if (precision == 0) { -            // truncate string if necessary as requested by precision -            str_arg_l = 0; -          } else { -            // memchr on HP does not like n > 2^31 -            // TODO(elmart): check if this still holds / is relevant -            str_arg_l = (size_t)((char *)xmemscan(str_arg, -                                                  NUL, -                                                  MIN(precision, 0x7fffffff)) -                                 - str_arg); -          } -          if (fmt_spec == 'S') { -            if (min_field_width != 0) -              min_field_width += strlen(str_arg) -                                 - mb_string2cells((char_u *) str_arg); -            if (precision) { -              char_u *p1 = (char_u *)str_arg; -              for (size_t i = 0; i < precision && *p1; i++) { -                p1 += mb_ptr2len(p1); -              } -              str_arg_l = precision = p1 - (char_u *)str_arg; -            } -          } -          break; - -        default: -          break; -        } -        break; - -      case 'd': -      case 'u': -      case 'b': case 'B': -      case 'o': -      case 'x': case 'X': -      case 'p': { -        // u, b, B, o, x, X and p conversion specifiers imply -        // the value is unsigned; d implies a signed value - -        // 0 if numeric argument is zero (or if pointer is NULL for 'p'), -        // +1 if greater than zero (or non NULL for 'p'), -        // -1 if negative (unsigned argument is never negative) -        int arg_sign = 0; - -        // only defined for length modifier h, or for no length modifiers -        int int_arg = 0; -        unsigned int uint_arg = 0; - -        // only defined for length modifier l -        long int long_arg = 0; -        unsigned long int ulong_arg = 0; - -        // only defined for length modifier ll -        long long int long_long_arg = 0; -        unsigned long long int ulong_long_arg = 0; - -        // only defined for length modifier z -        size_t size_t_arg = 0; - -        // only defined for p conversion -        const void *ptr_arg = NULL; - -        if (fmt_spec == 'p') { -          length_modifier = '\0'; -          ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *); -          if (ptr_arg) { -            arg_sign = 1; -          } -        } else if (fmt_spec == 'd') { -          // signed -          switch (length_modifier) { -          case '\0': -          case 'h': -            // char and short arguments are passed as int -            int_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int); -            if (int_arg > 0) { -              arg_sign =  1; -            } else if (int_arg < 0) { -              arg_sign = -1; -            } -            break; -          case 'l': -            long_arg = tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, long int); -            if (long_arg > 0) { -              arg_sign =  1; -            } else if (long_arg < 0) { -              arg_sign = -1; -            } -            break; -          case '2': -            long_long_arg = tvs ? tv_nr(tvs, &arg_idx) -                                : va_arg(ap, long long int); // NOLINT (runtime/int) -            if (long_long_arg > 0) { -              arg_sign =  1; -            } else if (long_long_arg < 0) { -              arg_sign = -1; -            } -            break; -          } -        } else { -          // unsigned -          switch (length_modifier) { -          case '\0': -          case 'h': -            uint_arg = tvs ? (unsigned)tv_nr(tvs, &arg_idx) -                           : va_arg(ap, unsigned int); -            if (uint_arg != 0) { arg_sign = 1; } -            break; -          case 'l': -            ulong_arg = tvs ? (unsigned long)tv_nr(tvs, &arg_idx) -                            : va_arg(ap, unsigned long int); -            if (ulong_arg != 0) { arg_sign = 1; } -            break; -          case '2': -            ulong_long_arg = tvs -                  ? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int) -                  : va_arg(ap, unsigned long long int);      // NOLINT (runtime/int) -            if (ulong_long_arg) { arg_sign = 1; } -            break; -          case 'z': -            size_t_arg = tvs ? (size_t)tv_nr(tvs, &arg_idx) -                             : va_arg(ap, size_t); -            if (size_t_arg) { arg_sign = 1; } -            break; -          } -        } - -        str_arg = tmp; -        str_arg_l = 0; - -        // For d, i, u, o, x, and X conversions, if precision is specified, -        // '0' flag should be ignored. This is so with Solaris 2.6, Digital UNIX -        // 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. -        if (precision_specified) { -          zero_padding = 0; -        } - -        if (fmt_spec == 'd') { -          if (force_sign && arg_sign >= 0) { -            tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; -          } -          // leave negative numbers for sprintf to handle, to -          // avoid handling tricky cases like (short int)-32768 -        } else if (alternate_form) { -          if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' -                                || fmt_spec == 'b' || fmt_spec == 'B')) { -            tmp[str_arg_l++] = '0'; -            tmp[str_arg_l++] = fmt_spec; -          } -          // alternate form should have no effect for p * conversion, but ... -        } - -        zero_padding_insertion_ind = str_arg_l; -        if (!precision_specified) { -          precision = 1;  // default precision is 1 -        } -        if (precision == 0 && arg_sign == 0) { -          // when zero value is formatted with an explicit precision 0, -          // resulting formatted string is empty (d, i, u, b, B, o, x, X, p) -        } else { -          char f[5]; -          int f_l = 0; - -          // construct a simple format string for sprintf -          f[f_l++] = '%'; -          if (!length_modifier) { -          } else if (length_modifier == '2') { -            f[f_l++] = 'l'; -            f[f_l++] = 'l'; -          } else -            f[f_l++] = length_modifier; -          f[f_l++] = fmt_spec; -          f[f_l++] = '\0'; - -          if (fmt_spec == 'p') -            str_arg_l += sprintf(tmp + str_arg_l, f, ptr_arg); -          else if (fmt_spec == 'd') { -            // signed -            switch (length_modifier) { -            case '\0': -            case 'h': str_arg_l += sprintf(tmp + str_arg_l, f, int_arg); -                      break; -            case 'l': str_arg_l += sprintf(tmp + str_arg_l, f, long_arg); -                      break; -            case '2': str_arg_l += sprintf(tmp + str_arg_l, f, long_long_arg); -                      break; -            } -          } else if (fmt_spec == 'b' || fmt_spec == 'B') { -            // binary -            size_t bits = 0; -            switch (length_modifier) { -            case '\0': -            case 'h': for (bits = sizeof(unsigned) * 8; bits > 0; bits--) { -                        if ((uint_arg >> (bits - 1)) & 0x1) { break; } } - -                      while (bits > 0) { -                        tmp[str_arg_l++] = -                          ((uint_arg >> --bits) & 0x1) ? '1' : '0'; } -                      break; -            case 'l': for (bits = sizeof(unsigned long) * 8; bits > 0; bits--) { -                        if ((ulong_arg >> (bits - 1)) & 0x1) { break; } } - -                      while (bits > 0) { -                        tmp[str_arg_l++] = -                          ((ulong_arg >> --bits) & 0x1) ? '1' : '0'; } -                      break; -            case '2': for (bits = sizeof(unsigned long long) * 8; // NOLINT (runtime/int) -                           bits > 0; bits--) { -                        if ((ulong_long_arg >> (bits - 1)) & 0x1) { break; } } - -                      while (bits > 0) { -                        tmp[str_arg_l++] = -                          ((ulong_long_arg >> --bits) & 0x1) ? '1' : '0'; } -                      break; -            case 'z': for (bits = sizeof(size_t) * 8; bits > 0; bits--) { -                        if ((size_t_arg >> (bits - 1)) & 0x1) { break; } } - -                      while (bits > 0) { -                        tmp[str_arg_l++] = -                          ((size_t_arg >> --bits) & 0x1) ? '1' : '0'; } -                      break; -            } -          } else { -            // unsigned -            switch (length_modifier) { -            case '\0': -            case 'h': str_arg_l += sprintf(tmp + str_arg_l, f, uint_arg); -                      break; -            case 'l': str_arg_l += sprintf(tmp + str_arg_l, f, ulong_arg); -                      break; -            case '2': str_arg_l += sprintf(tmp + str_arg_l, f, ulong_long_arg); -                      break; -            case 'z': str_arg_l += sprintf(tmp + str_arg_l, f, size_t_arg); -                      break; -            } -          } - -          // include the optional minus sign and possible "0x" in the region -          // before the zero padding insertion point -          if (zero_padding_insertion_ind < str_arg_l -              && tmp[zero_padding_insertion_ind] == '-') -            zero_padding_insertion_ind++; -          if (zero_padding_insertion_ind + 1 < str_arg_l -              && tmp[zero_padding_insertion_ind]   == '0' -              && (tmp[zero_padding_insertion_ind + 1] == 'x' -                  || tmp[zero_padding_insertion_ind + 1] == 'X' -                  || tmp[zero_padding_insertion_ind + 1] == 'b' -                  || tmp[zero_padding_insertion_ind + 1] == 'B')) -            zero_padding_insertion_ind += 2; -        } - -        { -          size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; - -          if (alternate_form && fmt_spec == 'o' -              // unless zero is already the first character -              && !(zero_padding_insertion_ind < str_arg_l -                   && tmp[zero_padding_insertion_ind] == '0')) { -            // assure leading zero for alternate-form octal numbers -            if (!precision_specified -                || precision < num_of_digits + 1) { -              // precision is increased to force the first character to be zero, -              // except if a zero value is formatted with an explicit precision -              // of zero -              precision = num_of_digits + 1; -            } -          } -          // zero padding to specified precision? -          if (num_of_digits < precision) -            number_of_zeros_to_pad = precision - num_of_digits; -        } -        // zero padding to specified minimal field width? -        if (!justify_left && zero_padding) { -          int n = (int)(min_field_width - (str_arg_l -                                           + number_of_zeros_to_pad)); -          if (n > 0) -            number_of_zeros_to_pad += n; -        } -        break; -      } - -      case 'f': -      case 'e': -      case 'E': -      case 'g': -      case 'G': -      { -        // floating point -        char format[40]; -        int l; -        int remove_trailing_zeroes = false; - -        double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double); -        double abs_f = f < 0 ? -f : f; - -        if (fmt_spec == 'g' || fmt_spec == 'G') { -          // can't use %g directly, cause it prints "1.0" as "1" -          if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) -            fmt_spec = 'f'; -          else -            fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; -          remove_trailing_zeroes = true; -        } - -        if (fmt_spec == 'f' && abs_f > 1.0e307) { -          // avoid a buffer overflow -          strcpy(tmp, "inf"); -          str_arg_l = 3; -        } else { -          format[0] = '%'; -          l = 1; -          if (precision_specified) { -            size_t max_prec = TMP_LEN - 10; - -            // make sure we don't get more digits than we have room for -            if (fmt_spec == 'f' && abs_f > 1.0) -              max_prec -= (size_t)log10(abs_f); -            if (precision > max_prec) -              precision = max_prec; -            l += sprintf(format + 1, ".%d", (int)precision); -          } -          format[l] = fmt_spec; -          format[l + 1] = NUL; -          str_arg_l = sprintf(tmp, format, f); - -          if (remove_trailing_zeroes) { -            int i; -            char *tp; - -            // using %g or %G: remove superfluous zeroes -            if (fmt_spec == 'f') -              tp = tmp + str_arg_l - 1; -            else { -              tp = (char *)vim_strchr((char_u *)tmp, -                                      fmt_spec == 'e' ? 'e' : 'E'); -              if (tp) { -                // remove superfluous '+' and leading zeroes from exponent -                if (tp[1] == '+') { -                  // change "1.0e+07" to "1.0e07" -                  STRMOVE(tp + 1, tp + 2); -                  --str_arg_l; -                } -                i = (tp[1] == '-') ? 2 : 1; -                while (tp[i] == '0') { -                  // change "1.0e07" to "1.0e7" -                  STRMOVE(tp + i, tp + i + 1); -                  --str_arg_l; -                } -                --tp; -              } -            } - -            if (tp != NULL && !precision_specified) -              // remove trailing zeroes, but keep the one just after a dot -              while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') { -                STRMOVE(tp, tp + 1); -                --tp; -                --str_arg_l; -              } -          } else { -            // be consistent: some printf("%e") use 1.0e+12 and some 1.0e+012; -            // remove one zero in the last case -            char *tp = (char *)vim_strchr((char_u *)tmp, -                                          fmt_spec == 'e' ? 'e' : 'E'); -            if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0' -                && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) { -              STRMOVE(tp + 2, tp + 3); -              --str_arg_l; -            } -          } -        } -        str_arg = tmp; -        break; -      } - -      default: -        // unrecognized conversion specifier, keep format string as-is -        zero_padding = 0;  // turn zero padding off for non-numeric conversion -        justify_left = 1; -        min_field_width = 0;  // reset flags - -        // discard the unrecognized conversion, just keep -        // the unrecognized conversion character -        str_arg = p; -        str_arg_l = 0; -        if (*p) -          str_arg_l++;  // include invalid conversion specifier -                        // unchanged if not at end-of-string -        break; -      } - -      if (*p) -        p++;  // step over the just processed conversion specifier - -      // insert padding to the left as requested by min_field_width; -      // this does not include the zero padding in case of numerical conversions -      if (!justify_left) { -        assert(str_arg_l <= SIZE_MAX - number_of_zeros_to_pad); -        if (min_field_width > str_arg_l + number_of_zeros_to_pad) { -          // left padding with blank or zero -          size_t pn = min_field_width - (str_arg_l + number_of_zeros_to_pad); -          if (str_avail) { -            size_t avail = str_m - str_l; -            memset(str + str_l, zero_padding ? '0' : ' ', MIN(pn, avail)); -            str_avail = pn < avail; -          } -          assert(pn <= SIZE_MAX - str_l); -          str_l += pn; -        } -      } - -      // zero padding as requested by the precision or by the minimal -      // field width for numeric conversions required? -      if (number_of_zeros_to_pad == 0) { -        // will not copy first part of numeric right now, -        // force it to be copied later in its entirety -        zero_padding_insertion_ind = 0; -      } else { -        // insert first part of numerics (sign or '0x') before zero padding -        if (zero_padding_insertion_ind > 0) { -          size_t zn = zero_padding_insertion_ind; -          if (str_avail) { -            size_t avail = str_m - str_l; -            memmove(str + str_l, str_arg, MIN(zn, avail)); -            str_avail = zn < avail; -          } -          assert(zn <= SIZE_MAX - str_l); -          str_l += zn; -        } - -        // insert zero padding as requested by precision or min field width -        if (number_of_zeros_to_pad > 0) { -          size_t zn = number_of_zeros_to_pad; -          if (str_avail) { -            size_t avail = str_m - str_l; -            memset(str + str_l, '0', MIN(zn, avail)); -            str_avail = zn < avail; -          } -          assert(zn <= SIZE_MAX - str_l); -          str_l += zn; -        } -      } - -      // insert formatted string -      // (or as-is conversion specifier for unknown conversions) -      if (str_arg_l > zero_padding_insertion_ind) { -        size_t sn = str_arg_l - zero_padding_insertion_ind; -        if (str_avail) { -          size_t avail = str_m - str_l; -          memmove(str + str_l, -                  str_arg + zero_padding_insertion_ind, -                  MIN(sn, avail)); -          str_avail = sn < avail; -        } -        assert(sn <= SIZE_MAX - str_l); -        str_l += sn; -      } - -      // insert right padding -      if (justify_left) { -        assert(str_arg_l <= SIZE_MAX - number_of_zeros_to_pad); -        if (min_field_width > str_arg_l + number_of_zeros_to_pad) { -          // right blank padding to the field width -          size_t pn = min_field_width - (str_arg_l + number_of_zeros_to_pad); -          if (str_avail) { -            size_t avail = str_m - str_l; -            memset(str + str_l, ' ', MIN(pn, avail)); -            str_avail = pn < avail; -          } -          assert(pn <= SIZE_MAX - str_l); -          str_l += pn; -        } -      } -    } -  } - -  if (str_m > 0) { -    // make sure the string is nul-terminated even at the expense of -    // overwriting the last character (shouldn't happen, but just in case) -    str[str_l <= str_m - 1 ? str_l : str_m - 1] = '\0'; -  } - -  if (tvs && tvs[arg_idx - 1].v_type != VAR_UNKNOWN) -    EMSG(_("E767: Too many arguments to printf()")); - -  // return the number of characters formatted (excluding trailing nul -  // character); that is, the number of characters that would have been -  // written to the buffer if it were large enough. -  return (int)str_l; -} | 
