diff options
| author | ZyX <kp-pav@yandex.ru> | 2017-12-03 16:49:30 +0300 | 
|---|---|---|
| committer | ZyX <kp-pav@yandex.ru> | 2017-12-03 16:49:30 +0300 | 
| commit | c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57 (patch) | |
| tree | b7e59c416d1435725c65f8952b6e55c70544d97e /src/nvim/strings.c | |
| parent | 62108c3b0be46936c83f6d4c98b44ceb5e6f77fd (diff) | |
| parent | 27a577586eace687c47e7398845178208cae524a (diff) | |
| download | rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.gz rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.tar.bz2 rneovim-c49e22d3964d6c7ae1c24e8ad01b5fec4ca40b57.zip  | |
Merge branch 'master' into s-dash-stdin
Diffstat (limited to 'src/nvim/strings.c')
| -rw-r--r-- | src/nvim/strings.c | 266 | 
1 files changed, 146 insertions, 120 deletions
diff --git a/src/nvim/strings.c b/src/nvim/strings.c index d03970108b..687f734742 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1,3 +1,6 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +  #include <inttypes.h>  #include <stdarg.h>  #include <stdbool.h> @@ -198,8 +201,16 @@ char_u *vim_strsave_shellescape(const char_u *string,    /* First count the number of extra bytes required. */    size_t length = STRLEN(string) + 3;       // two quotes and a trailing NUL    for (const char_u *p = string; *p != NUL; mb_ptr_adv(p)) { -    if (*p == '\'') -      length += 3;                      /* ' => '\'' */ +#ifdef WIN32 +    if (!p_ssl) { +      if (*p == '"') { +        length++;                       // " -> "" +      } +    } else +#endif +    if (*p == '\'') { +      length += 3;                      // ' => '\'' +    }      if ((*p == '\n' && (csh_like || do_newline))          || (*p == '!' && (csh_like || do_special))) {        ++length;                         /* insert backslash */ @@ -216,10 +227,25 @@ char_u *vim_strsave_shellescape(const char_u *string,    escaped_string = xmalloc(length);    d = escaped_string; -  /* add opening quote */ +  // add opening quote +#ifdef WIN32 +  if (!p_ssl) { +    *d++ = '"'; +  } else +#endif    *d++ = '\'';    for (const char_u *p = string; *p != NUL; ) { +#ifdef WIN32 +    if (!p_ssl) { +      if (*p == '"') { +        *d++ = '"'; +        *d++ = '"'; +        p++; +        continue; +      } +    } else +#endif      if (*p == '\'') {        *d++ = '\'';        *d++ = '\\'; @@ -246,7 +272,12 @@ char_u *vim_strsave_shellescape(const char_u *string,      MB_COPY_CHAR(p, d);    } -  /* add terminating quote and finish with a NUL */ +  // add terminating quote and finish with a NUL +# ifdef WIN32 +  if (!p_ssl) { +    *d++ = '"'; +  } else +# endif    *d++ = '\'';    *d = NUL; @@ -291,45 +322,42 @@ void vim_strup(char_u *p)    }  } -/* - * Make string "s" all upper-case and return it in allocated memory. - * Handles multi-byte characters as well as possible. - */ -char_u *strup_save(const char_u *orig) +/// Make given string all upper-case or all lower-case +/// +/// Handles multi-byte characters as good as possible. +/// +/// @param[in]  orig  Input string. +/// @param[in]  upper If true make uppercase, otherwise lowercase +/// +/// @return [allocated] upper-cased string. +char *strcase_save(const char *const orig, bool upper)    FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL  { -  char_u *res = vim_strsave(orig); +  char *res = xstrdup(orig); -  char_u *p = res; +  char *p = res;    while (*p != NUL) {      int l; -    if (enc_utf8) { -      int c = utf_ptr2char(p); -      int uc = utf_toupper(c); - -      /* Reallocate string when byte count changes.  This is rare, -       * thus it's OK to do another malloc()/free(). */ -      l = utf_ptr2len(p); -      int newl = utf_char2len(uc); -      if (newl != l) { -        // TODO(philix): use xrealloc() in strup_save() -        char_u *s = xmalloc(STRLEN(res) + (size_t)(1 + newl - l)); -        memcpy(s, res, (size_t)(p - res)); -        STRCPY(s + (p - res) + newl, p + l); -        p = s + (p - res); -        xfree(res); -        res = s; -      } - -      utf_char2bytes(uc, p); -      p += newl; -    } else if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) -      p += l;                 /* skip multi-byte character */ -    else { -      *p = (char_u) TOUPPER_LOC(*p);  // note that toupper() can be a macro -      p++; +    int c = utf_ptr2char((const char_u *)p); +    int uc = upper ? mb_toupper(c) : mb_tolower(c); + +    // Reallocate string when byte count changes.  This is rare, +    // thus it's OK to do another malloc()/free(). +    l = utf_ptr2len((const char_u *)p); +    int newl = utf_char2len(uc); +    if (newl != l) { +      // TODO(philix): use xrealloc() in strup_save() +      char *s = xmalloc(STRLEN(res) + (size_t)(1 + newl - l)); +      memcpy(s, res, (size_t)(p - res)); +      STRCPY(s + (p - res) + newl, p + l); +      p = s + (p - res); +      xfree(res); +      res = s;      } + +    utf_char2bytes(uc, (char_u *)p); +    p += newl;    }    return res; @@ -397,72 +425,27 @@ int vim_strnicmp(const char *s1, const char *s2, size_t len)  }  #endif -/* - * Version of strchr() and strrchr() that handle unsigned char strings - * with characters from 128 to 255 correctly.  It also doesn't return a - * pointer to the NUL at the end of the string. - */ -char_u *vim_strchr(const char_u *string, int c) -  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE +/// strchr() version which handles multibyte strings +/// +/// @param[in]  string  String to search in. +/// @param[in]  c  Character to search for. +/// +/// @return Pointer to the first byte of the found character in string or NULL +///         if it was not found or character is invalid. NUL character is never +///         found, use `strlen()` instead. +char_u *vim_strchr(const char_u *const string, const int c) +  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT  { -  int b; - -  const char_u *p = string; -  if (enc_utf8 && c >= 0x80) { -    while (*p != NUL) { -      int l = (*mb_ptr2len)(p); - -      // Avoid matching an illegal byte here. -      if (l > 1 && utf_ptr2char(p) == c) { -        return (char_u *) p; -      } -      p += l; -    } +  if (c <= 0) {      return NULL; +  } else if (c < 0x80) { +    return (char_u *)strchr((const char *)string, c); +  } else { +    char u8char[MB_MAXBYTES + 1]; +    const int len = utf_char2bytes(c, (char_u *)u8char); +    u8char[len] = NUL; +    return (char_u *)strstr((const char *)string, u8char);    } -  if (enc_dbcs != 0 && c > 255) { -    int n2 = c & 0xff; - -    c = ((unsigned)c >> 8) & 0xff; -    while ((b = *p) != NUL) { -      if (b == c && p[1] == n2) -        return (char_u *) p; -      p += (*mb_ptr2len)(p); -    } -    return NULL; -  } -  if (has_mbyte) { -    while ((b = *p) != NUL) { -      if (b == c) -        return (char_u *) p; -      p += (*mb_ptr2len)(p); -    } -    return NULL; -  } -  while ((b = *p) != NUL) { -    if (b == c) -      return (char_u *) p; -    ++p; -  } -  return NULL; -} - -/* - * Version of strchr() that only works for bytes and handles unsigned char - * strings with characters above 128 correctly. It also doesn't return a - * pointer to the NUL at the end of the string. - */ -char_u *vim_strbyte(const char_u *string, int c) -  FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE -{ -  const char_u *p = string; - -  while (*p != NUL) { -    if (*p == c) -      return (char_u *) p; -    ++p; -  } -  return NULL;  }  /* @@ -571,8 +554,8 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp)      EMSG(_(e_printf));    } else {      (*idxp)++; -    int err = false; -    n = (varnumber_T)get_tv_number_chk(&tvs[idx], &err); +    bool err = false; +    n = tv_get_number_chk(&tvs[idx], &err);      if (err) {        n = 0;      } @@ -594,22 +577,21 @@ static varnumber_T tv_nr(typval_T *tvs, int *idxp)  ///                      free "*tofree".  ///  /// @return String value or NULL in case of error. -static char *tv_str(typval_T *tvs, int *idxp, char ** const tofree) +static const char *tv_str(typval_T *tvs, int *idxp, char **const tofree)    FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT  {    int idx = *idxp - 1; -  char *s = NULL; +  const char *s = NULL;    if (tvs[idx].v_type == VAR_UNKNOWN) {      EMSG(_(e_printf));    } else {      (*idxp)++;      if (tvs[idx].v_type == VAR_STRING || tvs[idx].v_type == VAR_NUMBER) { -      s = (char *)get_tv_string_chk(&tvs[idx]); +      s = tv_get_string_chk(&tvs[idx]);        *tofree = NULL;      } else { -      s = encode_tv2echo(&tvs[idx], NULL); -      *tofree = s; +      s = *tofree = encode_tv2echo(&tvs[idx], NULL);      }    }    return s; @@ -671,7 +653,7 @@ static float_T tv_float(typval_T *const tvs, int *const 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; +      f = (float_T)tvs[idx].vval.v_number;      } else {        EMSG(_("E807: Expected Float argument for printf()"));      } @@ -753,6 +735,22 @@ int vim_snprintf(char *str, size_t str_m, const char *fmt, ...)    return str_l;  } +// Return the representation of infinity for printf() function: +// "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF". +static const char *infinity_str(bool positive, char fmt_spec, +                                int force_sign, int space_for_positive) +{ +  static const char *table[] = { +    "-inf", "inf", "+inf", " inf", +    "-INF", "INF", "+INF", " INF" +  }; +  int idx = positive * (1 + force_sign + force_sign * space_for_positive); +  if (ASCII_ISUPPER(fmt_spec)) { +    idx += 4; +  } +  return table[idx]; +} +  /// Write formatted value to the string  /// @@ -909,10 +907,16 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,          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;        } +      switch (fmt_spec) { +        case 'd': case 'u': case 'o': case 'x': case 'X': +          if (tvs && length_modifier == '\0') { +            length_modifier = '2'; +          } +      } +        // get parameter value, do initial processing        switch (fmt_spec) {          // '%' and 'c' behave similar to 's' regarding flags and field widths @@ -934,7 +938,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,              case 's':              case 'S':                str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree) -                            : va_arg(ap, char *); +                            : va_arg(ap, const char *);                if (!str_arg) {                  str_arg = "[NULL]";                  str_arg_l = 6; @@ -1186,6 +1190,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,          }          case 'f': +        case 'F':          case 'e':          case 'E':          case 'g': @@ -1201,36 +1206,51 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,              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'; +                fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : '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 -              memmove(tmp, "inf", sizeof("inf")); -              str_arg_l = sizeof("inf") - 1; +            if (isinf(f) +                || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) { +              xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec, +                                         force_sign, space_for_positive), +                       sizeof(tmp)); +              str_arg_l = strlen(tmp); +              zero_padding = 0; +            } else if (isnan(f)) { +              // Not a number: nan or NAN +              memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4); +              str_arg_l = 3; +              zero_padding = 0;              } else {                format[0] = '%'; -              int l = 1; +              size_t l = 1; +              if (force_sign) { +                format[l++] = space_for_positive ? ' ' : '+'; +              }                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) { +                if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) {                    max_prec -= (size_t)log10(abs_f);                  }                  if (precision > max_prec) {                    precision = max_prec;                  } -                l += snprintf(format + 1, sizeof(format) - 1, ".%d", -                              (int)precision); +                l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d", +                                      (int)precision);                } + +              // Cast to char to avoid a conversion warning on Ubuntu 12.04.                format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec);                format[l + 1] = NUL; -              assert(l + 1 < (int)sizeof(format)); + +              // Regular float number +              assert(l + 1 < sizeof(format));                str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f);                assert(str_arg_l < sizeof(tmp)); @@ -1239,7 +1259,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,                  char *tp;                  // using %g or %G: remove superfluous zeroes -                if (fmt_spec == 'f') { +                if (fmt_spec == 'f' || fmt_spec == 'F') {                    tp = tmp + str_arg_l - 1;                  } else {                    tp = (char *)vim_strchr((char_u *)tmp, @@ -1281,6 +1301,12 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap,                  }                }              } +            if (zero_padding && min_field_width > str_arg_l +                && (tmp[0] == '-' || force_sign)) { +              // Padding 0's should be inserted after the sign. +              number_of_zeros_to_pad = min_field_width - str_arg_l; +              zero_padding_insertion_ind = 1; +            }              str_arg = tmp;              break;            }  | 
