summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-04-14 15:13:46 +0200
committerBram Moolenaar <Bram@vim.org>2016-04-14 15:13:46 +0200
commit58de0e2dcc1f2d251b74892a06d71a14973f3187 (patch)
tree73357af1942325ac46de5990a06d872d1e626118 /src
parent6244a0fc29163ba1c734f92b55a89e01e6cf2a67 (diff)
patch 7.4.1730v7.4.1730
Problem: It is not easy to get a character out of a string. Solution: Add strgetchar() and strcharpart().
Diffstat (limited to 'src')
-rw-r--r--src/eval.c109
-rw-r--r--src/testdir/test_expr.vim47
-rw-r--r--src/version.c2
3 files changed, 158 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c
index 86580450fc..9dd4d84d39 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -779,9 +779,11 @@ static void f_strchars(typval_T *argvars, typval_T *rettv);
#ifdef HAVE_STRFTIME
static void f_strftime(typval_T *argvars, typval_T *rettv);
#endif
+static void f_strgetchar(typval_T *argvars, typval_T *rettv);
static void f_stridx(typval_T *argvars, typval_T *rettv);
static void f_string(typval_T *argvars, typval_T *rettv);
static void f_strlen(typval_T *argvars, typval_T *rettv);
+static void f_strcharpart(typval_T *argvars, typval_T *rettv);
static void f_strpart(typval_T *argvars, typval_T *rettv);
static void f_strridx(typval_T *argvars, typval_T *rettv);
static void f_strtrans(typval_T *argvars, typval_T *rettv);
@@ -8635,11 +8637,13 @@ static struct fst
{"str2float", 1, 1, f_str2float},
#endif
{"str2nr", 1, 2, f_str2nr},
+ {"strcharpart", 2, 3, f_strcharpart},
{"strchars", 1, 2, f_strchars},
{"strdisplaywidth", 1, 2, f_strdisplaywidth},
#ifdef HAVE_STRFTIME
{"strftime", 1, 2, f_strftime},
#endif
+ {"strgetchar", 2, 2, f_strgetchar},
{"stridx", 2, 3, f_stridx},
{"string", 1, 1, f_string},
{"strlen", 1, 1, f_strlen},
@@ -19551,6 +19555,46 @@ f_strftime(typval_T *argvars, typval_T *rettv)
#endif
/*
+ * "strgetchar()" function
+ */
+ static void
+f_strgetchar(typval_T *argvars, typval_T *rettv)
+{
+ char_u *str;
+ int len;
+ int error = FALSE;
+ int charidx;
+
+ rettv->vval.v_number = -1;
+ str = get_tv_string_chk(&argvars[0]);
+ if (str == NULL)
+ return;
+ len = (int)STRLEN(str);
+ charidx = get_tv_number_chk(&argvars[1], &error);
+ if (error)
+ return;
+#ifdef FEAT_MBYTE
+ {
+ int byteidx = 0;
+
+ while (charidx >= 0 && byteidx < len)
+ {
+ if (charidx == 0)
+ {
+ rettv->vval.v_number = mb_ptr2char(str + byteidx);
+ break;
+ }
+ --charidx;
+ byteidx += mb_char2len(str[byteidx]);
+ }
+ }
+#else
+ if (charidx < len)
+ rettv->vval.v_number = str[charidx];
+#endif
+}
+
+/*
* "stridx()" function
*/
static void
@@ -19678,6 +19722,71 @@ f_strwidth(typval_T *argvars, typval_T *rettv)
}
/*
+ * "strcharpart()" function
+ */
+ static void
+f_strcharpart(typval_T *argvars, typval_T *rettv)
+{
+#ifdef FEAT_MBYTE
+ char_u *p;
+ int nchar;
+ int nbyte = 0;
+ int charlen;
+ int len = 0;
+ int slen;
+ int error = FALSE;
+
+ p = get_tv_string(&argvars[0]);
+ slen = (int)STRLEN(p);
+
+ nchar = get_tv_number_chk(&argvars[1], &error);
+ if (!error)
+ {
+ if (nchar > 0)
+ while (nchar > 0 && nbyte < slen)
+ {
+ nbyte += mb_char2len(p[nbyte]);
+ --nchar;
+ }
+ else
+ nbyte = nchar;
+ if (argvars[2].v_type != VAR_UNKNOWN)
+ {
+ charlen = get_tv_number(&argvars[2]);
+ while (charlen > 0 && nbyte + len < slen)
+ {
+ len += mb_char2len(p[nbyte + len]);
+ --charlen;
+ }
+ }
+ else
+ len = slen - nbyte; /* default: all bytes that are available. */
+ }
+
+ /*
+ * Only return the overlap between the specified part and the actual
+ * string.
+ */
+ if (nbyte < 0)
+ {
+ len += nbyte;
+ nbyte = 0;
+ }
+ else if (nbyte > slen)
+ nbyte = slen;
+ if (len < 0)
+ len = 0;
+ else if (nbyte + len > slen)
+ len = slen - nbyte;
+
+ rettv->v_type = VAR_STRING;
+ rettv->vval.v_string = vim_strnsave(p + nbyte, len);
+#else
+ f_strpart(argvars, rettv);
+#endif
+}
+
+/*
* "strpart()" function
*/
static void
diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim
index 33115c7f1f..cdaf45ee73 100644
--- a/src/testdir/test_expr.vim
+++ b/src/testdir/test_expr.vim
@@ -50,3 +50,50 @@ func Test_dict()
call assert_equal('none', d[''])
call assert_equal('aaa', d['a'])
endfunc
+
+func Test_strgetchar()
+ call assert_equal(char2nr('a'), strgetchar('axb', 0))
+ call assert_equal(char2nr('x'), strgetchar('axb', 1))
+ call assert_equal(char2nr('b'), strgetchar('axb', 2))
+
+ call assert_equal(-1, strgetchar('axb', -1))
+ call assert_equal(-1, strgetchar('axb', 3))
+ call assert_equal(-1, strgetchar('', 0))
+
+ if !has('multi_byte')
+ return
+ endif
+
+ call assert_equal(char2nr('á'), strgetchar('áxb', 0))
+ call assert_equal(char2nr('x'), strgetchar('áxb', 1))
+
+ call assert_equal(char2nr('a'), strgetchar('àxb', 0))
+ call assert_equal(char2nr('̀'), strgetchar('àxb', 1))
+ call assert_equal(char2nr('x'), strgetchar('àxb', 2))
+endfunc
+
+func Test_strcharpart()
+ call assert_equal('a', strcharpart('axb', 0, 1))
+ call assert_equal('x', strcharpart('axb', 1, 1))
+ call assert_equal('b', strcharpart('axb', 2, 1))
+ call assert_equal('xb', strcharpart('axb', 1))
+
+ call assert_equal('', strcharpart('axb', 1, 0))
+ call assert_equal('', strcharpart('axb', 1, -1))
+ call assert_equal('', strcharpart('axb', -1, 1))
+ call assert_equal('', strcharpart('axb', -2, 2))
+
+ call assert_equal('a', strcharpart('axb', -1, 2))
+
+ if !has('multi_byte')
+ return
+ endif
+
+ call assert_equal('áxb', strcharpart('áxb', 0))
+ call assert_equal('á', strcharpart('áxb', 0, 1))
+ call assert_equal('x', strcharpart('áxb', 1, 1))
+
+ call assert_equal('a', strcharpart('àxb', 0, 1))
+ call assert_equal('̀', strcharpart('àxb', 1, 1))
+ call assert_equal('x', strcharpart('àxb', 2, 1))
+endfunc
diff --git a/src/version.c b/src/version.c
index 26831238bf..7132e0b072 100644
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1730,
+/**/
1729,
/**/
1728,