changeset 34540:9e093c96dff6 v9.1.0172

patch 9.1.0172: More code can use ml_get_buf_len() instead of STRLEN() Commit: https://github.com/vim/vim/commit/94b7c3233ef534acc669b3083ed1fe59cf3a090b Author: zeertzjq <zeertzjq@outlook.com> Date: Tue Mar 12 21:50:32 2024 +0100 patch 9.1.0172: More code can use ml_get_buf_len() instead of STRLEN() Problem: More code can use ml_get_buf_len() instead of STRLEN(). Solution: Change more STRLEN() calls to ml_get_buf_len(). Also do not set ml_line_textlen in ml_replace_len() if "has_props" is set, because "len_arg" also includes the size of text properties in that case. (zeertzjq) closes: #14183 Signed-off-by: zeertzjq <zeertzjq@outlook.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Tue, 12 Mar 2024 22:00:04 +0100
parents 0dbb6f014f5e
children a4b8338f9e76
files src/buffer.c src/channel.c src/charset.c src/diff.c src/drawline.c src/drawscreen.c src/edit.c src/ex_cmds.c src/fileio.c src/fold.c src/help.c src/indent.c src/insexpand.c src/mbyte.c src/memline.c src/misc2.c src/netbeans.c src/ops.c src/proto/memline.pro src/quickfix.c src/register.c src/search.c src/spell.c src/spellfile.c src/spellsuggest.c src/syntax.c src/textformat.c src/textobject.c src/textprop.c src/version.c
diffstat 30 files changed, 137 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4221,7 +4221,7 @@ build_stl_str_hl(
     stl_hlrec_T **tabtab)	// return: tab page nrs (can be NULL)
 {
     linenr_T	lnum;
-    size_t	len;
+    colnr_T	len;
     char_u	*p;
     char_u	*s;
     char_u	*t;
@@ -4328,12 +4328,12 @@ build_stl_str_hl(
 
     // Get the byte value now, in case we need it below. This is more efficient
     // than making a copy of the line.
-    len = STRLEN(p);
-    if (wp->w_cursor.col > (colnr_T)len)
+    len = ml_get_buf_len(wp->w_buffer, lnum);
+    if (wp->w_cursor.col > len)
     {
 	// Line may have changed since checking the cursor column, or the lnum
 	// was adjusted above.
-	wp->w_cursor.col = (colnr_T)len;
+	wp->w_cursor.col = len;
 	wp->w_cursor.coladd = 0;
 	byteval = 0;
     }
--- a/src/channel.c
+++ b/src/channel.c
@@ -1493,7 +1493,7 @@ channel_set_req_callback(
 write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
 {
     char_u  *line = ml_get_buf(buf, lnum, FALSE);
-    int	    len = (int)STRLEN(line);
+    int	    len = ml_get_buf_len(buf, lnum);
     char_u  *p;
     int	    i;
 
--- a/src/charset.c
+++ b/src/charset.c
@@ -1690,7 +1690,7 @@ getvvcol(
 	endadd = 0;
 	// Cannot put the cursor on part of a wide character.
 	ptr = ml_get_buf(wp->w_buffer, pos->lnum, FALSE);
-	if (pos->col < (colnr_T)STRLEN(ptr))
+	if (pos->col < ml_get_buf_len(wp->w_buffer, pos->lnum))
 	{
 	    int c = (*mb_ptr2char)(ptr + pos->col);
 
--- a/src/diff.c
+++ b/src/diff.c
@@ -762,7 +762,7 @@ diff_write_buffer(buf_T *buf, diffin_T *
 
     // xdiff requires one big block of memory with all the text.
     for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
-	len += (long)STRLEN(ml_get_buf(buf, lnum, FALSE)) + 1;
+	len += ml_get_buf_len(buf, lnum) + 1;
     ptr = alloc(len);
     if (ptr == NULL)
     {
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -1533,7 +1533,7 @@ win_line(
 	}
 	else
 	{
-	    v = (long)STRLEN(line);
+	    v = ml_get_buf_len(wp->w_buffer, lnum);
 	    if (v < SPWORDLEN)
 	    {
 		// Short line, use it completely and append the start of the
@@ -1570,7 +1570,7 @@ win_line(
 	// find start of trailing whitespace
 	if (wp->w_lcs_chars.trail)
 	{
-	    trailcol = (colnr_T)STRLEN(ptr);
+	    trailcol = ml_get_buf_len(wp->w_buffer, lnum);
 	    while (trailcol > (colnr_T)0 && VIM_ISWHITE(ptr[trailcol - 1]))
 		--trailcol;
 	    trailcol += (colnr_T)(ptr - line);
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -1300,7 +1300,7 @@ fold_line(
 			&& (lnume < bot->lnum
 			    || (lnume == bot->lnum
 				&& (bot->col - (*p_sel == 'e'))
-		>= (colnr_T)STRLEN(ml_get_buf(wp->w_buffer, lnume, FALSE)))))))
+				    >= ml_get_buf_len(wp->w_buffer, lnume))))))
 	{
 	    if (VIsual_mode == Ctrl_V)
 	    {
--- a/src/edit.c
+++ b/src/edit.c
@@ -3222,7 +3222,7 @@ replace_do_bs(int limit_col)
 	{
 	    // Do not adjust text properties for individual delete and insert
 	    // operations, do it afterwards on the resulting text.
-	    len_before = STRLEN(ml_get_curline());
+	    len_before = ml_get_curline_len();
 	    ++text_prop_frozen;
 	}
 #endif
@@ -3237,14 +3237,14 @@ replace_do_bs(int limit_col)
 	{
 	    (void)del_char_after_col(limit_col);
 	    if (State & VREPLACE_FLAG)
-		orig_len = (int)STRLEN(ml_get_cursor());
+		orig_len = ml_get_cursor_len();
 	    replace_push(cc);
 	}
 	else
 	{
 	    pchar_cursor(cc);
 	    if (State & VREPLACE_FLAG)
-		orig_len = (int)STRLEN(ml_get_cursor()) - 1;
+		orig_len = ml_get_cursor_len() - 1;
 	}
 	replace_pop_ins();
 
@@ -3252,7 +3252,7 @@ replace_do_bs(int limit_col)
 	{
 	    // Get the number of screen cells used by the inserted characters
 	    p = ml_get_cursor();
-	    ins_len = (int)STRLEN(p) - orig_len;
+	    ins_len = ml_get_cursor_len() - orig_len;
 	    vcol = start_vcol;
 	    for (i = 0; i < ins_len; ++i)
 	    {
@@ -3278,7 +3278,7 @@ replace_do_bs(int limit_col)
 #ifdef FEAT_PROP_POPUP
 	if (curbuf->b_has_textprop)
 	{
-	    size_t len_now = STRLEN(ml_get_curline());
+	    size_t len_now = ml_get_curline_len();
 
 	    --text_prop_frozen;
 	    adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col,
@@ -4068,7 +4068,7 @@ ins_bs(
 			       (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
 		return FALSE;
 	    --Insstart.lnum;
-	    Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum));
+	    Insstart.col = ml_get_len(Insstart.lnum);
 	}
 	/*
 	 * In replace mode:
@@ -5174,7 +5174,7 @@ ins_eol(int c)
     // NL in reverse insert will always start in the end of
     // current line.
     if (revins_on)
-	curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
+	curwin->w_cursor.col += ml_get_cursor_len();
 #endif
 
     AppendToRedobuff(NL_STR);
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -489,7 +489,7 @@ ex_sort(exarg_T *eap)
     for (lnum = eap->line1; lnum <= eap->line2; ++lnum)
     {
 	s = ml_get(lnum);
-	len = (int)STRLEN(s);
+	len = ml_get_len(lnum);
 	if (maxlen < len)
 	    maxlen = len;
 
@@ -691,7 +691,7 @@ do_move(linenr_T line1, linenr_T line2, 
 	return FAIL;
     for (extra = 0, l = line1; l <= line2; l++)
     {
-	str = vim_strsave(ml_get(l + extra));
+	str = vim_strnsave(ml_get(l + extra), ml_get_len(l + extra));
 	if (str != NULL)
 	{
 	    ml_append(dest + l - line1, str, (colnr_T)0, FALSE);
@@ -824,9 +824,9 @@ ex_copy(linenr_T line1, linenr_T line2, 
     curwin->w_cursor.lnum = n;
     while (line1 <= line2)
     {
-	// need to use vim_strsave() because the line will be unlocked within
+	// need to make a copy because the line will be unlocked within
 	// ml_append()
-	p = vim_strsave(ml_get(line1));
+	p = vim_strnsave(ml_get(line1), ml_get_len(line1));
 	if (p != NULL)
 	{
 	    ml_append(curwin->w_cursor.lnum, p, (colnr_T)0, FALSE);
@@ -4225,7 +4225,8 @@ ex_substitute(exarg_T *eap)
 
 		if (sub_firstline == NULL)
 		{
-		    sub_firstline = vim_strsave(ml_get(sub_firstlnum));
+		    sub_firstline = vim_strnsave(ml_get(sub_firstlnum),
+						    ml_get_len(sub_firstlnum));
 		    if (sub_firstline == NULL)
 		    {
 			vim_free(new_start);
@@ -4379,7 +4380,8 @@ ex_substitute(exarg_T *eap)
 				// really update the line, it would change
 				// what matches.  Temporarily replace the line
 				// and change it back afterwards.
-				orig_line = vim_strsave(ml_get(lnum));
+				orig_line = vim_strnsave(ml_get(lnum),
+							     ml_get_len(lnum));
 				if (orig_line != NULL)
 				{
 				    char_u *new_line = concat_str(new_start,
@@ -4725,7 +4727,8 @@ ex_substitute(exarg_T *eap)
 		{
 		    sub_firstlnum += nmatch - 1;
 		    vim_free(sub_firstline);
-		    sub_firstline = vim_strsave(ml_get(sub_firstlnum));
+		    sub_firstline = vim_strnsave(ml_get(sub_firstlnum),
+						    ml_get_len(sub_firstlnum));
 		    // When going beyond the last line, stop substituting.
 		    if (sub_firstlnum <= line2)
 			do_again = TRUE;
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1246,7 +1246,7 @@ retry:
 			for (;;)
 			{
 			    p = ml_get(read_buf_lnum) + read_buf_col;
-			    n = (int)STRLEN(p);
+			    n = ml_get_len(read_buf_lnum) - read_buf_col;
 			    if ((int)tlen + n + 1 > size)
 			    {
 				// Filled up to "size", append partial line.
--- a/src/fold.c
+++ b/src/fold.c
@@ -1061,7 +1061,6 @@ find_wl_entry(win_T *win, linenr_T lnum)
 foldAdjustVisual(void)
 {
     pos_T	*start, *end;
-    char_u	*ptr;
 
     if (!VIsual_active || !hasAnyFolding(curwin))
 	return;
@@ -1082,8 +1081,7 @@ foldAdjustVisual(void)
     if (!hasFolding(end->lnum, NULL, &end->lnum))
 	return;
 
-    ptr = ml_get(end->lnum);
-    end->col = (colnr_T)STRLEN(ptr);
+    end->col = ml_get_len(end->lnum);
     if (end->col > 0 && *p_sel == 'o')
 	--end->col;
     // prevent cursor from moving on the trail byte
@@ -1799,7 +1797,7 @@ foldAddMarker(linenr_T lnum, char_u *mar
 
     // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end
     line = ml_get(lnum);
-    line_len = (int)STRLEN(line);
+    line_len = ml_get_len(lnum);
 
     if (u_save(lnum - 1, lnum + 1) != OK)
 	return;
@@ -1887,7 +1885,7 @@ foldDelMarker(linenr_T lnum, char_u *mar
 	    if (u_save(lnum - 1, lnum + 1) == OK)
 	    {
 		// Make new line: text-before-marker + text-after-marker
-		newline = alloc(STRLEN(line) - len + 1);
+		newline = alloc(ml_get_len(lnum) - len + 1);
 		if (newline != NULL)
 		{
 		    STRNCPY(newline, line, p - line);
--- a/src/help.c
+++ b/src/help.c
@@ -720,7 +720,7 @@ fix_help_buffer(void)
 	for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
 	{
 	    line = ml_get_buf(curbuf, lnum, FALSE);
-	    len = (int)STRLEN(line);
+	    len = ml_get_buf_len(curbuf, lnum);
 	    if (in_example && len > 0 && !VIM_ISWHITE(line[0]))
 	    {
 		// End of example: non-white or '<' in first column.
--- a/src/indent.c
+++ b/src/indent.c
@@ -1609,7 +1609,7 @@ copy_indent(int size, char_u *src)
 	{
 	    // Allocate memory for the result: the copied indent, new indent
 	    // and the rest of the line.
-	    line_len = (int)STRLEN(ml_get_curline()) + 1;
+	    line_len = ml_get_curline_len() + 1;
 	    line = alloc(ind_len + line_len);
 	    if (line == NULL)
 		return FALSE;
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -3297,8 +3297,7 @@ process_next_cpt_value(
 	    // buffer, so that word at start of buffer is found
 	    // correctly.
 	    st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count;
-	    st->first_match_pos.col =
-		(colnr_T)STRLEN(ml_get(st->first_match_pos.lnum));
+	    st->first_match_pos.col = ml_get_len(st->first_match_pos.lnum);
 	}
 	st->last_match_pos = st->first_match_pos;
 	compl_type = 0;
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -4378,7 +4378,7 @@ mb_adjustpos(buf_T *buf, pos_T *lp)
     if (lp->col > 0 || lp->coladd > 1)
     {
 	p = ml_get_buf(buf, lp->lnum, FALSE);
-	if (*p == NUL || (int)STRLEN(p) < lp->col)
+	if (*p == NUL || ml_get_buf_len(buf, lp->lnum) < lp->col)
 	    lp->col = 0;
 	else
 	    lp->col -= (*mb_head_off)(p, p + lp->col);
--- a/src/memline.c
+++ b/src/memline.c
@@ -2682,6 +2682,13 @@ ml_get_len(linenr_T lnum)
     return ml_get_buf_len(curbuf, lnum);
 }
 
+// return length (excluding the NUL) of the text after position "pos"
+    colnr_T
+ml_get_pos_len(pos_T *pos)
+{
+    return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - pos->col;
+}
+
 // return length (excluding the NUL) of the cursor line
     colnr_T
 ml_get_curline_len(void)
@@ -3661,7 +3668,7 @@ ml_replace_len(
 
     curbuf->b_ml.ml_line_ptr = line;
     curbuf->b_ml.ml_line_len = len;
-    curbuf->b_ml.ml_line_textlen = len_arg + !has_props;
+    curbuf->b_ml.ml_line_textlen = !has_props ? len_arg + 1 : 0;
     curbuf->b_ml.ml_line_lnum = lnum;
     curbuf->b_ml.ml_flags = (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY;
 
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -130,6 +130,7 @@ coladvance2(
     colnr_T	wcol = wcol_arg;
     int		idx;
     char_u	*line;
+    int		linelen;
     colnr_T	col = 0;
     int		csize = 0;
     int		one_more;
@@ -142,10 +143,11 @@ coladvance2(
 		    || (VIsual_active && *p_sel != 'o')
 		    || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL);
     line = ml_get_buf(curbuf, pos->lnum, FALSE);
+    linelen = ml_get_buf_len(curbuf, pos->lnum);
 
     if (wcol >= MAXCOL)
     {
-	    idx = (int)STRLEN(line) - 1 + one_more;
+	    idx = linelen - 1 + one_more;
 	    col = wcol;
 
 	    if ((addspaces || finetune) && !VIsual_active)
@@ -255,7 +257,6 @@ coladvance2(
 	    else
 	    {
 		// Break a tab
-		int	linelen = (int)STRLEN(line);
 		int	correct = wcol - col - csize + 1; // negative!!
 		char_u	*newline;
 		int	t, s = 0;
@@ -412,7 +413,7 @@ dec(pos_T *lp)
     {
 	// past end of line
 	p = ml_get(lp->lnum);
-	lp->col = (colnr_T)STRLEN(p);
+	lp->col = ml_get_len(lp->lnum);
 	if (has_mbyte)
 	    lp->col -= (*mb_head_off)(p, p + lp->col);
 	return 0;
@@ -435,7 +436,7 @@ dec(pos_T *lp)
 	// there is a prior line
 	lp->lnum--;
 	p = ml_get(lp->lnum);
-	lp->col = (colnr_T)STRLEN(p);
+	lp->col = ml_get_len(lp->lnum);
 	if (has_mbyte)
 	    lp->col -= (*mb_head_off)(p, p + lp->col);
 	return 1;
@@ -515,7 +516,6 @@ get_cursor_rel_lnum(
     void
 check_pos(buf_T *buf, pos_T *pos)
 {
-    char_u *line;
     colnr_T len;
 
     if (pos->lnum > buf->b_ml.ml_line_count)
@@ -523,8 +523,7 @@ check_pos(buf_T *buf, pos_T *pos)
 
     if (pos->col > 0)
     {
-	line = ml_get_buf(buf, pos->lnum, FALSE);
-	len = (colnr_T)STRLEN(line);
+	len = ml_get_buf_len(buf, pos->lnum);
 	if (pos->col > len)
 	    pos->col = len;
     }
@@ -570,7 +569,7 @@ check_cursor_col_win(win_T *win)
     colnr_T      oldcoladd = win->w_cursor.col + win->w_cursor.coladd;
     unsigned int cur_ve_flags = get_ve_flags();
 
-    len = (colnr_T)STRLEN(ml_get_buf(win->w_buffer, win->w_cursor.lnum, FALSE));
+    len = ml_get_buf_len(win->w_buffer, win->w_cursor.lnum);
     if (len == 0)
 	win->w_cursor.col = 0;
     else if (win->w_cursor.col >= len)
@@ -649,7 +648,7 @@ check_visual_pos(void)
     }
     else
     {
-	int len = (int)STRLEN(ml_get(VIsual.lnum));
+	int len = ml_get_len(VIsual.lnum);
 
 	if (VIsual.col > len)
 	{
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -932,7 +932,7 @@ nb_partialremove(linenr_T lnum, colnr_T 
     int lastbyte = last;
 
     oldtext = ml_get(lnum);
-    oldlen = (int)STRLEN(oldtext);
+    oldlen = ml_get_len(lnum);
     if (first >= (colnr_T)oldlen || oldlen == 0)  // just in case
 	return;
     if (lastbyte >= oldlen)
@@ -957,8 +957,8 @@ nb_joinlines(linenr_T first, linenr_T ot
     int len_first, len_other;
     char_u *p;
 
-    len_first = (int)STRLEN(ml_get(first));
-    len_other = (int)STRLEN(ml_get(other));
+    len_first = ml_get_len(first);
+    len_other = ml_get_len(other);
     p = alloc(len_first + len_other + 1);
     if (p == NULL)
 	return;
@@ -1402,7 +1402,7 @@ nb_do_cmd(
 			int	col = pos == NULL ? 0 : pos->col;
 
 			// Insert halfway a line.
-			newline = alloc(STRLEN(oldline) + len + 1);
+			newline = alloc(ml_get_len(lnum) + len + 1);
 			if (newline != NULL)
 			{
 			    mch_memmove(newline, oldline, (size_t)col);
@@ -3314,8 +3314,7 @@ get_buf_size(buf_T *bufp)
 	eol_size = 1;
     for (lnum = 1; lnum <= bufp->b_ml.ml_line_count; ++lnum)
     {
-	char_count += (long)STRLEN(ml_get_buf(bufp, lnum, FALSE))
-	    + eol_size;
+	char_count += ml_get_buf_len(bufp, lnum) + eol_size;
 	// Check for a CTRL-C every 100000 characters
 	if (char_count > last_check)
 	{
--- a/src/ops.c
+++ b/src/ops.c
@@ -212,7 +212,7 @@ op_shift(oparg_T *oap, int curs_top, int
 	// Set "'[" and "']" marks.
 	curbuf->b_op_start = oap->start;
 	curbuf->b_op_end.lnum = oap->end.lnum;
-	curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+	curbuf->b_op_end.col = ml_get_len(oap->end.lnum);
 	if (curbuf->b_op_end.col > 0)
 	    --curbuf->b_op_end.col;
     }
@@ -476,7 +476,7 @@ shift_block(oparg_T *oap, int amount)
 	STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
     }
     // replace the line
-    added = new_line_len - (int)STRLEN(oldp);
+    added = new_line_len - ml_get_curline_len();
     ml_replace(curwin->w_cursor.lnum, newp, FALSE);
     inserted_bytes(curwin->w_cursor.lnum, bd.textcol, added);
     State = oldstate;
@@ -554,7 +554,7 @@ block_insert(
 	    spaces = 0;
 
 	// Make sure the allocated size matches what is actually copied below.
-	newp = alloc(STRLEN(oldp) + spaces + s_len
+	newp = alloc(ml_get_len(lnum) + spaces + s_len
 		    + (spaces > 0 && !bdp->is_short ? ts_val - spaces : 0)
 								  + count + 1);
 	if (newp == NULL)
@@ -800,7 +800,7 @@ op_delete(oparg_T *oap)
 	    // Thus the number of characters may increase!
 	    n = bd.textlen - bd.startspaces - bd.endspaces;
 	    oldp = ml_get(lnum);
-	    newp = alloc(STRLEN(oldp) + 1 - n);
+	    newp = alloc(ml_get_len(lnum) + 1 - n);
 	    if (newp == NULL)
 		continue;
 	    // copy up to deleted part
@@ -920,8 +920,7 @@ op_delete(oparg_T *oap)
 	    {
 		// fix up things for virtualedit-delete:
 		// break the tabs which are going to get in our way
-		char_u		*curline = ml_get_curline();
-		int		len = (int)STRLEN(curline);
+		int		len = ml_get_curline_len();
 
 		if (oap->end.coladd != 0
 			&& (int)oap->end.col >= len - 1
@@ -1116,7 +1115,7 @@ op_replace(oparg_T *oap, int c)
 	    n += numc - bd.textlen;
 
 	    oldp = ml_get_curline();
-	    oldlen = STRLEN(oldp);
+	    oldlen = ml_get_curline_len();
 	    newp = alloc(oldlen + 1 + n);
 	    if (newp == NULL)
 		continue;
@@ -1174,7 +1173,7 @@ op_replace(oparg_T *oap, int c)
 	{
 	    oap->start.col = 0;
 	    curwin->w_cursor.col = 0;
-	    oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+	    oap->end.col = ml_get_len(oap->end.lnum);
 	    if (oap->end.col)
 		--oap->end.col;
 	}
@@ -1320,7 +1319,7 @@ op_tilde(oparg_T *oap)
 	{
 	    oap->start.col = 0;
 	    pos.col = 0;
-	    oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+	    oap->end.col = ml_get_len(oap->end.lnum);
 	    if (oap->end.col)
 		--oap->end.col;
 	}
@@ -1334,8 +1333,8 @@ op_tilde(oparg_T *oap)
 	    for (;;)
 	    {
 		did_change |= swapchars(oap->op_type, &pos,
-				pos.lnum == oap->end.lnum ? oap->end.col + 1:
-					   (int)STRLEN(ml_get_pos(&pos)));
+			pos.lnum == oap->end.lnum ? oap->end.col + 1
+						  : ml_get_pos_len(&pos));
 		if (LTOREQ_POS(oap->end, pos) || inc(&pos) == -1)
 		    break;
 	    }
@@ -1353,7 +1352,7 @@ op_tilde(oparg_T *oap)
 		while (pos.lnum < oap->end.lnum)
 		{
 		    ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
-		    count = (int)STRLEN(ptr) - pos.col;
+		    count = ml_get_buf_len(curbuf, pos.lnum) - pos.col;
 		    netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
 		    // get the line again, it may have been flushed
 		    ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
@@ -1542,10 +1541,13 @@ op_insert(oparg_T *oap, long count1)
 	ind_pre_col = (colnr_T)getwhitecols_curline();
 	ind_pre_vcol = get_indent();
 	firstline = ml_get(oap->start.lnum) + bd.textcol;
+	pre_textlen = ml_get_len(oap->start.lnum) - bd.textcol;
 
 	if (oap->op_type == OP_APPEND)
+	{
 	    firstline += bd.textlen;
-	pre_textlen = (long)STRLEN(firstline);
+	    pre_textlen -= bd.textlen;
+	}
     }
 
     if (oap->op_type == OP_APPEND)
@@ -1686,7 +1688,7 @@ op_insert(oparg_T *oap, long count1)
 	 * copy of the required string.
 	 */
 	firstline = ml_get(oap->start.lnum);
-	len = STRLEN(firstline);
+	len = ml_get_len(oap->start.lnum);
 	add = bd.textcol;
 	if (oap->op_type == OP_APPEND)
 	{
@@ -1706,11 +1708,10 @@ op_insert(oparg_T *oap, long count1)
 	    }
 	}
 	if ((size_t)add > len)
-	    firstline += len;  // short line, point to the NUL
-	else
-	    firstline += add;
-	if (pre_textlen >= 0 && (ins_len =
-			   (long)STRLEN(firstline) - pre_textlen - offset) > 0)
+	    add = len;  // short line, point to the NUL
+	firstline += add;
+	len -= add;
+	if (pre_textlen >= 0 && (ins_len = len - pre_textlen - offset) > 0)
 	{
 	    ins_text = vim_strnsave(firstline, ins_len);
 	    if (ins_text != NULL)
@@ -1778,7 +1779,7 @@ op_change(oparg_T *oap)
 						    || gchar_cursor() == NUL))
 	    coladvance_force(getviscol());
 	firstline = ml_get(oap->start.lnum);
-	pre_textlen = (long)STRLEN(firstline);
+	pre_textlen = ml_get_len(oap->start.lnum);
 	pre_indent = (long)getwhitecols(firstline);
 	bd.textcol = curwin->w_cursor.col;
     }
@@ -1812,7 +1813,7 @@ op_change(oparg_T *oap)
 	    bd.textcol += new_indent - pre_indent;
 	}
 
-	ins_len = (long)STRLEN(firstline) - pre_textlen;
+	ins_len = ml_get_len(oap->start.lnum) - pre_textlen;
 	if (ins_len > 0)
 	{
 	    // Subsequent calls to ml_get() flush the firstline data - take a
@@ -1838,7 +1839,8 @@ op_change(oparg_T *oap)
 			else
 			    vpos.coladd = 0;
 			oldp = ml_get(linenr);
-			newp = alloc(STRLEN(oldp) + vpos.coladd + ins_len + 1);
+			newp = alloc(ml_get_len(linenr)
+						  + vpos.coladd + ins_len + 1);
 			if (newp == NULL)
 			    continue;
 			// copy up to block start
@@ -2491,7 +2493,7 @@ charwise_block_prep(
 	}
     }
     if (endcol == MAXCOL)
-	endcol = (colnr_T)STRLEN(p);
+	endcol = ml_get_len(lnum);
     if (startcol > endcol || is_oneChar)
 	bdp->textlen = 0;
     else
@@ -2565,13 +2567,13 @@ op_addsub(
 	    {
 		curwin->w_cursor.col = 0;
 		pos.col = 0;
-		length = (colnr_T)STRLEN(ml_get(pos.lnum));
+		length = ml_get_len(pos.lnum);
 	    }
 	    else // oap->motion_type == MCHAR
 	    {
 		if (pos.lnum == oap->start.lnum && !oap->inclusive)
 		    dec(&(oap->end));
-		length = (colnr_T)STRLEN(ml_get(pos.lnum));
+		length = ml_get_len(pos.lnum);
 		pos.col = 0;
 		if (pos.lnum == oap->start.lnum)
 		{
@@ -2580,7 +2582,7 @@ op_addsub(
 		}
 		if (pos.lnum == oap->end.lnum)
 		{
-		    length = (int)STRLEN(ml_get(oap->end.lnum));
+		    length = ml_get_len(oap->end.lnum);
 		    if (oap->end.col >= length)
 			oap->end.col = length - 1;
 		    length = oap->end.col - pos.col + 1;
@@ -3048,14 +3050,12 @@ do_addsub(
 	// del_char() will also mark line needing displaying
 	if (todel > 0)
 	{
-	    int bytes_after = (int)STRLEN(ml_get_curline())
-							- curwin->w_cursor.col;
+	    int bytes_after = ml_get_curline_len() - curwin->w_cursor.col;
 
 	    // Delete the one character before the insert.
 	    curwin->w_cursor = save_pos;
 	    (void)del_char(FALSE);
-	    curwin->w_cursor.col = (colnr_T)(STRLEN(ml_get_curline())
-								- bytes_after);
+	    curwin->w_cursor.col = ml_get_curline_len() - bytes_after;
 	    --todel;
 	}
 	while (todel-- > 0)
@@ -3361,7 +3361,7 @@ cursor_pos_info(dict_T *dict)
 		validate_virtcol();
 		col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1,
 			(int)curwin->w_virtcol + 1);
-		col_print(buf2, sizeof(buf2), (int)STRLEN(p),
+		col_print(buf2, sizeof(buf2), ml_get_curline_len(),
 							   linetabsize_str(p));
 
 		if (char_count_cursor == byte_count_cursor
@@ -3858,13 +3858,12 @@ do_pending_operator(cmdarg_T *cap, int o
 		if (LT_POS(VIsual, curwin->w_cursor))
 		{
 		    VIsual.col = 0;
-		    curwin->w_cursor.col =
-			       (colnr_T)STRLEN(ml_get(curwin->w_cursor.lnum));
+		    curwin->w_cursor.col = ml_get_len(curwin->w_cursor.lnum);
 		}
 		else
 		{
 		    curwin->w_cursor.col = 0;
-		    VIsual.col = (colnr_T)STRLEN(ml_get(VIsual.lnum));
+		    VIsual.col = ml_get_len(VIsual.lnum);
 		}
 		VIsual_mode = 'v';
 	    }
@@ -3895,7 +3894,7 @@ do_pending_operator(cmdarg_T *cap, int o
 						  || oap->motion_type == MLINE)
 			&& hasFolding(curwin->w_cursor.lnum, NULL,
 						      &curwin->w_cursor.lnum))
-		    curwin->w_cursor.col = (colnr_T)STRLEN(ml_get_curline());
+		    curwin->w_cursor.col = ml_get_curline_len();
 	    }
 #endif
 	    oap->end = curwin->w_cursor;
@@ -3916,7 +3915,7 @@ do_pending_operator(cmdarg_T *cap, int o
 									NULL))
 		    curwin->w_cursor.col = 0;
 		if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum))
-		    oap->start.col = (colnr_T)STRLEN(ml_get(oap->start.lnum));
+		    oap->start.col = ml_get_len(oap->start.lnum);
 	    }
 #endif
 	    oap->end = oap->start;
@@ -4126,7 +4125,7 @@ do_pending_operator(cmdarg_T *cap, int o
 		oap->motion_type = MLINE;
 	    else
 	    {
-		oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
+		oap->end.col = ml_get_len(oap->end.lnum);
 		if (oap->end.col)
 		{
 		    --oap->end.col;
--- a/src/proto/memline.pro
+++ b/src/proto/memline.pro
@@ -20,6 +20,7 @@ char_u *ml_get_pos(pos_T *pos);
 char_u *ml_get_curline(void);
 char_u *ml_get_cursor(void);
 colnr_T ml_get_len(linenr_T lnum);
+colnr_T ml_get_pos_len(pos_T *pos);
 colnr_T ml_get_curline_len(void);
 colnr_T ml_get_cursor_len(void);
 colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum);
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -780,9 +780,9 @@ qf_get_next_buf_line(qfstate_T *state)
 	return QF_END_OF_INPUT;
 
     p_buf = ml_get_buf(state->buf, state->buflnum, FALSE);
+    len = ml_get_buf_len(state->buf, state->buflnum);
     state->buflnum += 1;
 
-    len = (int)STRLEN(p_buf);
     if (len > IOSIZE - 2)
     {
 	state->linebuf = qf_grow_linebuf(state, len);
@@ -6196,13 +6196,14 @@ vgr_match_buflines(
 		    break;
 		col = regmatch->endpos[0].col
 		    + (col == regmatch->endpos[0].col);
-		if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
+		if (col > ml_get_buf_len(buf, lnum))
 		    break;
 	    }
 	}
 	else
 	{
 	    char_u  *str = ml_get_buf(buf, lnum, FALSE);
+	    int	    line_len = ml_get_buf_len(buf, lnum);
 	    int	    score;
 	    int_u   matches[MAX_FUZZY_MATCHES];
 	    int_u   sz = ARRAY_LENGTH(matches);
@@ -6241,7 +6242,7 @@ vgr_match_buflines(
 		if ((flags & VGR_GLOBAL) == 0)
 		    break;
 		col = matches[pat_len - 1] + col + 1;
-		if (col > (colnr_T)STRLEN(str))
+		if (col > line_len)
 		    break;
 	    }
 	}
--- a/src/register.c
+++ b/src/register.c
@@ -1793,7 +1793,7 @@ do_put(
 	    }
 	    // get the old line and advance to the position to insert at
 	    oldp = ml_get_curline();
-	    oldlen = (int)STRLEN(oldp);
+	    oldlen = ml_get_curline_len();
 	    init_chartabsize_arg(&cts, curwin, curwin->w_cursor.lnum, 0,
 								  oldp, oldp);
 
@@ -1924,7 +1924,7 @@ do_put(
 	    curwin->w_cursor.col++;
 
 	    // in Insert mode we might be after the NUL, correct for that
-	    len = (colnr_T)STRLEN(ml_get_curline());
+	    len = ml_get_curline_len();
 	    if (curwin->w_cursor.col > len)
 		curwin->w_cursor.col = len;
 	}
@@ -2008,7 +2008,7 @@ do_put(
 		totlen = count * yanklen;
 		do {
 		    oldp = ml_get(lnum);
-		    oldlen = (int)STRLEN(oldp);
+		    oldlen = ml_get_len(lnum);
 		    if (lnum > start_lnum)
 		    {
 			pos_T   pos;
@@ -2088,7 +2088,7 @@ do_put(
 		    lnum = new_cursor.lnum;
 		    ptr = ml_get(lnum) + col;
 		    totlen = (int)STRLEN(y_array[y_size - 1]);
-		    newp = alloc(STRLEN(ptr) + totlen + 1);
+		    newp = alloc(ml_get_len(lnum) - col + totlen + 1);
 		    if (newp == NULL)
 			goto error;
 		    STRCPY(newp, y_array[y_size - 1]);
@@ -2129,7 +2129,7 @@ do_put(
 			curwin->w_cursor.lnum = lnum;
 			ptr = ml_get(lnum);
 			if (cnt == count && i == y_size - 1)
-			    lendiff = (int)STRLEN(ptr);
+			    lendiff = ml_get_len(lnum);
 			if (*ptr == '#' && preprocs_left())
 			    indent = 0;     // Leave # lines at start
 			else
@@ -2147,7 +2147,7 @@ do_put(
 			curwin->w_cursor = old_pos;
 			// remember how many chars were removed
 			if (cnt == count && i == y_size - 1)
-			    lendiff -= (int)STRLEN(ml_get(lnum));
+			    lendiff -= ml_get_len(lnum);
 		    }
 		}
 		if (cnt == 1)
@@ -2239,7 +2239,7 @@ error:
     curwin->w_set_curswant = TRUE;
 
     // Make sure the cursor is not after the NUL.
-    int len = (int)STRLEN(ml_get_curline());
+    int len = ml_get_curline_len();
     if (curwin->w_cursor.col > len)
     {
 	if (cur_ve_flags == VE_ALL)
--- a/src/search.c
+++ b/src/search.c
@@ -660,7 +660,7 @@ searchit(
 						    && pos->col < MAXCOL - 2)
 	{
 	    ptr = ml_get_buf(buf, pos->lnum, FALSE);
-	    if ((int)STRLEN(ptr) <= pos->col)
+	    if (ml_get_buf_len(buf, pos->lnum) <= pos->col)
 		start_char_len = 1;
 	    else
 		start_char_len = (*mb_ptr2len)(ptr + pos->col);
@@ -966,8 +966,7 @@ searchit(
 			    if (pos->lnum > 1)  // just in case
 			    {
 				--pos->lnum;
-				pos->col = (colnr_T)STRLEN(ml_get_buf(buf,
-							   pos->lnum, FALSE));
+				pos->col = ml_get_buf_len(buf, pos->lnum);
 			    }
 			}
 			else
@@ -1102,7 +1101,7 @@ searchit(
     if (pos->lnum > buf->b_ml.ml_line_count)
     {
 	pos->lnum = buf->b_ml.ml_line_count;
-	pos->col = (int)STRLEN(ml_get_buf(buf, pos->lnum, FALSE));
+	pos->col = ml_get_buf_len(buf, pos->lnum);
 	if (pos->col > 0)
 	    --pos->col;
     }
@@ -1772,7 +1771,7 @@ searchc(cmdarg_T *cap, int t_cmd)
 
     p = ml_get_curline();
     col = curwin->w_cursor.col;
-    len = (int)STRLEN(p);
+    len = ml_get_curline_len();
 
     while (count--)
     {
@@ -2315,7 +2314,7 @@ findmatchlimit(
 		    break;
 
 		linep = ml_get(pos.lnum);
-		pos.col = (colnr_T)STRLEN(linep); // pos.col on trailing NUL
+		pos.col = ml_get_len(pos.lnum); // pos.col on trailing NUL
 		do_quotes = -1;
 		line_breakcheck();
 
@@ -2492,7 +2491,7 @@ findmatchlimit(
 		if (pos.lnum > 1)
 		{
 		    ptr = ml_get(pos.lnum - 1);
-		    if (*ptr && *(ptr + STRLEN(ptr) - 1) == '\\')
+		    if (*ptr && *(ptr + ml_get_len(pos.lnum - 1) - 1) == '\\')
 		    {
 			do_quotes = 1;
 			if (start_in_quotes == MAYBE)
@@ -2986,8 +2985,7 @@ current_search(
 		// try again from end of buffer
 		// searching backwards, so set pos to last line and col
 		pos.lnum = curwin->w_buffer->b_ml.ml_line_count;
-		pos.col  = (colnr_T)STRLEN(
-				ml_get(curwin->w_buffer->b_ml.ml_line_count));
+		pos.col  = ml_get_len(curwin->w_buffer->b_ml.ml_line_count);
 	    }
 	}
     }
--- a/src/spell.c
+++ b/src/spell.c
@@ -1384,7 +1384,7 @@ spell_move_to(
 
 	line = ml_get_buf(wp->w_buffer, lnum, FALSE);
 
-	len = (int)STRLEN(line);
+	len = ml_get_buf_len(wp->w_buffer, lnum);
 	if (buflen < len + MAXWLEN + 2)
 	{
 	    vim_free(buf);
@@ -2988,7 +2988,7 @@ ex_spellrepall(exarg_T *eap UNUSED)
 	if (addlen <= 0 || STRNCMP(line + curwin->w_cursor.col,
 						   repl_to, repl_to_len) != 0)
 	{
-	    p = alloc(STRLEN(line) + addlen + 1);
+	    p = alloc(ml_get_curline_len() + addlen + 1);
 	    if (p == NULL)
 		break;
 	    mch_memmove(p, line, curwin->w_cursor.col);
--- a/src/spellfile.c
+++ b/src/spellfile.c
@@ -5877,7 +5877,7 @@ sug_write(spellinfo_T *spin, char_u *fna
     {
 	// <sugline>: <sugnr> ... NUL
 	line = ml_get_buf(spin->si_spellbuf, lnum, FALSE);
-	len = (int)STRLEN(line) + 1;
+	len = ml_get_buf_len(spin->si_spellbuf, lnum) + 1;
 	if (fwrite(line, (size_t)len, (size_t)1, fd) == 0)
 	{
 	    emsg(_(e_error_while_writing));
--- a/src/spellsuggest.c
+++ b/src/spellsuggest.c
@@ -509,8 +509,8 @@ spell_suggest(int count)
 	end_visual_mode();
 	// make sure we don't include the NUL at the end of the line
 	line = ml_get_curline();
-	if (badlen > (int)STRLEN(line) - (int)curwin->w_cursor.col)
-	    badlen = (int)STRLEN(line) - (int)curwin->w_cursor.col;
+	if (badlen > ml_get_curline_len() - (int)curwin->w_cursor.col)
+	    badlen = ml_get_curline_len() - (int)curwin->w_cursor.col;
     }
     // Find the start of the badly spelled word.
     else if (spell_move_to(curwin, FORWARD, TRUE, TRUE, NULL) == 0
@@ -543,7 +543,7 @@ spell_suggest(int count)
 							curwin->w_cursor.col);
 
     // Make a copy of current line since autocommands may free the line.
-    line = vim_strsave(ml_get_curline());
+    line = vim_strnsave(ml_get_curline(), ml_get_curline_len());
     if (line == NULL)
 	goto skip;
 
--- a/src/syntax.c
+++ b/src/syntax.c
@@ -593,7 +593,6 @@ syn_sync(
     int		had_sync_point;
     stateitem_T	*cur_si;
     synpat_T	*spp;
-    char_u	*line;
     int		found_flags = 0;
     int		found_match_idx = 0;
     linenr_T	found_current_lnum = 0;
@@ -651,8 +650,9 @@ syn_sync(
 	 */
 	for ( ; start_lnum > 1; --start_lnum)
 	{
-	    line = ml_get(start_lnum - 1);
-	    if (*line == NUL || *(line + STRLEN(line) - 1) != '\\')
+	    char_u	*l = ml_get(start_lnum - 1);
+
+	    if (*l == NUL || *(l + ml_get_len(start_lnum - 1) - 1) != '\\')
 		break;
 	}
 	current_lnum = start_lnum;
@@ -2775,7 +2775,6 @@ find_endpos(
     regmmatch_T	regmatch;
     regmmatch_T	best_regmatch;	    // startpos/endpos of best match
     lpos_T	pos;
-    char_u	*line;
     int		had_match = FALSE;
     char_u	buf_chartab[32];  // chartab array for syn option iskyeyword
 
@@ -2899,8 +2898,7 @@ find_endpos(
 		if (pos.lnum > startpos->lnum)
 		    break;
 
-		line = ml_get_buf(syn_buf, startpos->lnum, FALSE);
-		line_len = (int)STRLEN(line);
+		line_len = ml_get_buf_len(syn_buf, startpos->lnum);
 
 		// take care of an empty match or negative offset
 		if (pos.col <= matchcol)
@@ -3101,7 +3099,7 @@ syn_add_start_off(
     {
 	// a "\n" at the end of the pattern may take us below the last line
 	result->lnum = syn_buf->b_ml.ml_line_count;
-	col = (int)STRLEN(ml_get_buf(syn_buf, result->lnum, FALSE));
+	col = ml_get_buf_len(syn_buf, result->lnum);
     }
     if (off != 0)
     {
--- a/src/textformat.c
+++ b/src/textformat.c
@@ -455,7 +455,7 @@ internal_format(
 	    // Check if cursor is not past the NUL off the line, cindent
 	    // may have added or removed indent.
 	    curwin->w_cursor.col += startcol;
-	    len = (colnr_T)STRLEN(ml_get_curline());
+	    len = ml_get_curline_len();
 	    if (curwin->w_cursor.col > len)
 		curwin->w_cursor.col = len;
 	}
@@ -531,9 +531,7 @@ ends_in_white(linenr_T lnum)
 
     if (*s == NUL)
 	return FALSE;
-    // Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro
-    // invocation may call function multiple times".
-    l = STRLEN(s) - 1;
+    l = ml_get_len(lnum) - 1;
     return VIM_ISWHITE(s[l]);
 }
 
@@ -573,7 +571,7 @@ same_leader(
 		return FALSE;
 	    if (*p == COM_START)
 	    {
-		int line_len = (int)STRLEN(ml_get(lnum));
+		int line_len = ml_get_len(lnum);
 		if (line_len <= leader1_len)
 		    return FALSE;
 		if (leader2_flags == NULL || leader2_len == 0)
@@ -684,7 +682,7 @@ auto_format(
     // in 'formatoptions' and there is a single character before the cursor.
     // Otherwise the line would be broken and when typing another non-white
     // next they are not joined back together.
-    wasatend = (pos.col == (colnr_T)STRLEN(old));
+    wasatend = (pos.col == ml_get_curline_len());
     if (*old != NUL && !trailblank && wasatend)
     {
 	dec_cursor();
@@ -740,7 +738,7 @@ auto_format(
     if (!wasatend && has_format_option(FO_WHITE_PAR))
     {
 	new = ml_get_curline();
-	len = (colnr_T)STRLEN(new);
+	len = ml_get_curline_len();
 	if (curwin->w_cursor.col == len)
 	{
 	    pnew = vim_strnsave(new, len + 2);
@@ -1217,7 +1215,7 @@ format_lines(
 		}
 		first_par_line = FALSE;
 		// If the line is getting long, format it next time
-		if (STRLEN(ml_get_curline()) > (size_t)max_len)
+		if (ml_get_curline_len() > max_len)
 		    force_format = TRUE;
 		else
 		    force_format = FALSE;
--- a/src/textobject.c
+++ b/src/textobject.c
@@ -232,7 +232,7 @@ findpar(
 
 	// Put the cursor on the last character in the last line and make the
 	// motion inclusive.
-	if ((curwin->w_cursor.col = (colnr_T)STRLEN(line)) != 0)
+	if ((curwin->w_cursor.col = ml_get_len(curr)) != 0)
 	{
 	    --curwin->w_cursor.col;
 	    curwin->w_cursor.col -=
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -637,7 +637,7 @@ get_text_props(buf_T *buf, linenr_T lnum
 
     // Fetch the line to get the ml_line_len field updated.
     text = ml_get_buf(buf, lnum, will_change);
-    textlen = STRLEN(text) + 1;
+    textlen = ml_get_buf_len(buf, lnum) + 1;
     proplen = buf->b_ml.ml_line_len - textlen;
     if (proplen == 0)
 	return 0;
@@ -864,7 +864,7 @@ set_text_props(linenr_T lnum, char_u *pr
     int	    textlen;
 
     text = ml_get(lnum);
-    textlen = (int)STRLEN(text) + 1;
+    textlen = ml_get_len(lnum) + 1;
     newtext = alloc(textlen + len);
     if (newtext == NULL)
 	return;
@@ -1091,7 +1091,7 @@ f_prop_clear(typval_T *argvars, typval_T
 	if (lnum > buf->b_ml.ml_line_count)
 	    break;
 	text = ml_get_buf(buf, lnum, FALSE);
-	len = STRLEN(text) + 1;
+	len = ml_get_buf_len(buf, lnum) + 1;
 	if ((size_t)buf->b_ml.ml_line_len > len)
 	{
 	    did_clear = TRUE;
@@ -1221,7 +1221,7 @@ f_prop_find(typval_T *argvars, typval_T 
     while (1)
     {
 	char_u	*text = ml_get_buf(buf, lnum, FALSE);
-	size_t	textlen = STRLEN(text) + 1;
+	size_t	textlen = ml_get_buf_len(buf, lnum) + 1;
 	int	count = (int)((buf->b_ml.ml_line_len - textlen)
 							 / sizeof(textprop_T));
 	int	    i;
@@ -1342,7 +1342,7 @@ get_props_in_line(
 	int		add_lnum)
 {
     char_u	*text = ml_get_buf(buf, lnum, FALSE);
-    size_t	textlen = STRLEN(text) + 1;
+    size_t	textlen = ml_get_buf_len(buf, lnum) + 1;
     int		count;
     int		i;
     textprop_T	prop;
@@ -1675,13 +1675,11 @@ f_prop_remove(typval_T *argvars, typval_
 	end = buf->b_ml.ml_line_count;
     for (lnum = start; lnum <= end; ++lnum)
     {
-	char_u *text;
 	size_t len;
 
 	if (lnum > buf->b_ml.ml_line_count)
 	    break;
-	text = ml_get_buf(buf, lnum, FALSE);
-	len = STRLEN(text) + 1;
+	len = ml_get_buf_len(buf, lnum) + 1;
 	if ((size_t)buf->b_ml.ml_line_len > len)
 	{
 	    static textprop_T	textprop;  // static because of alignment
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    172,
+/**/
     171,
 /**/
     170,