To: vim_dev@googlegroups.com Subject: Patch 7.4.1730 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1730 Problem: It is not easy to get a character out of a string. Solution: Add strgetchar() and strcharpart(). Files: src/eval.c, src/testdir/test_expr.vim *** ../vim-7.4.1729/src/eval.c 2016-04-14 12:46:33.616678646 +0200 --- src/eval.c 2016-04-14 15:00:41.064037067 +0200 *************** *** 779,787 **** --- 779,789 ---- #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,8645 **** --- 8637,8649 ---- {"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,19556 **** --- 19555,19600 ---- #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,19683 **** --- 19722,19792 ---- } /* + * "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 *** ../vim-7.4.1729/src/testdir/test_expr.vim 2016-04-03 22:44:32.403625720 +0200 --- src/testdir/test_expr.vim 2016-04-14 15:06:58.352114798 +0200 *************** *** 50,52 **** --- 50,99 ---- 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 *** ../vim-7.4.1729/src/version.c 2016-04-14 14:09:21.712015920 +0200 --- src/version.c 2016-04-14 14:56:19.538712323 +0200 *************** *** 750,751 **** --- 750,753 ---- { /* Add new patch number below this line */ + /**/ + 1730, /**/ -- ARTHUR: Right! Knights! Forward! ARTHUR leads a charge toward the castle. Various shots of them battling on, despite being hit by a variety of farm animals. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///