Added strwidth() and strchars() functions.
diff --git a/src/eval.c b/src/eval.c
index 295512e..a344cd2 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -700,6 +700,7 @@
 static void f_str2float __ARGS((typval_T *argvars, typval_T *rettv));
 #endif
 static void f_str2nr __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_strchars __ARGS((typval_T *argvars, typval_T *rettv));
 #ifdef HAVE_STRFTIME
 static void f_strftime __ARGS((typval_T *argvars, typval_T *rettv));
 #endif
@@ -709,6 +710,7 @@
 static void f_strpart __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_strridx __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_strtrans __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_strwidth __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_submatch __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_substitute __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_synID __ARGS((typval_T *argvars, typval_T *rettv));
@@ -7856,6 +7858,7 @@
     {"str2float",	1, 1, f_str2float},
 #endif
     {"str2nr",		1, 2, f_str2nr},
+    {"strchars",	1, 1, f_strchars},
 #ifdef HAVE_STRFTIME
     {"strftime",	1, 2, f_strftime},
 #endif
@@ -7865,6 +7868,7 @@
     {"strpart",		2, 3, f_strpart},
     {"strridx",		2, 3, f_strridx},
     {"strtrans",	1, 1, f_strtrans},
+    {"strwidth",	1, 1, f_strwidth},
     {"submatch",	1, 1, f_submatch},
     {"substitute",	4, 4, f_substitute},
     {"synID",		3, 3, f_synID},
@@ -16778,6 +16782,48 @@
 }
 
 /*
+ * "strchars()" function
+ */
+    static void
+f_strchars(argvars, rettv)
+    typval_T	*argvars;
+    typval_T	*rettv;
+{
+    char_u		*s = get_tv_string(&argvars[0]);
+#ifdef FEAT_MBYTE
+    varnumber_T		len = 0;
+
+    while (*s != NUL)
+    {
+	mb_cptr2char_adv(&s);
+	++len;
+    }
+    rettv->vval.v_number = len;
+#else
+    rettv->vval.v_number = (varnumber_T)(STRLEN(s));
+#endif
+}
+
+/*
+ * "strwidth()" function
+ */
+    static void
+f_strwidth(argvars, rettv)
+    typval_T	*argvars;
+    typval_T	*rettv;
+{
+    char_u	*s = get_tv_string(&argvars[0]);
+
+    rettv->vval.v_number = (varnumber_T)(
+#ifdef FEAT_MBYTE
+	    mb_string2cells(s, -1)
+#else
+	    STRLEN(s)
+#endif
+	    );
+}
+
+/*
  * "strpart()" function
  */
     static void
diff --git a/src/gui.c b/src/gui.c
index 4075997..6899992 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -2329,14 +2329,9 @@
 # ifdef FEAT_MBYTE
 	if (enc_dbcs == DBCS_JPNU)
 	{
-	    int		clen = 0;
-	    int		i;
-
 	    /* Get the length in display cells, this can be different from the
 	     * number of bytes for "euc-jp". */
-	    for (i = 0; i < len; i += (*mb_ptr2len)(s + i))
-		clen += (*mb_ptr2cells)(s + i);
-	    len = clen;
+	    len = mb_string2cells(s, len);
 	}
 # endif
     }
diff --git a/src/gui_mac.c b/src/gui_mac.c
index f6aa22b..2f0f7f8 100644
--- a/src/gui_mac.c
+++ b/src/gui_mac.c
@@ -3983,13 +3983,8 @@
 	/* Multibyte computation taken from gui_w32.c */
 	if (has_mbyte)
 	{
-	    int cell_len = 0;
-	    int n;
-
 	    /* Compute the length in display cells. */
-	    for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
-		cell_len += (*mb_ptr2cells)(s + n);
-	    rc.right = FILL_X(col + cell_len);
+	    rc.right = FILL_X(col + mb_string2cells(s, len));
 	}
 	else
 #endif
@@ -4087,13 +4082,8 @@
 	/* Multibyte computation taken from gui_w32.c */
 	if (has_mbyte)
 	{
-	    int cell_len = 0;
-	    int n;
-
 	    /* Compute the length in display cells. */
-	    for (n = 0; n < len; n += MB_BYTE2LEN(s[n]))
-		cell_len += (*mb_ptr2cells)(s + n);
-	    rc.right = FILL_X(col + cell_len);
+	    rc.right = FILL_X(col + mb_string2cells(s, len));
 	}
 	else
 	    rc.right = FILL_X(col + len) + (col + len == Columns);
diff --git a/src/gui_w16.c b/src/gui_w16.c
index f7e6d59..6866784 100644
--- a/src/gui_w16.c
+++ b/src/gui_w16.c
@@ -664,12 +664,8 @@
 #ifdef FEAT_MBYTE
 	if (has_mbyte)
 	{
-	    int cell_len = 0;
-
 	    /* Compute the length in display cells. */
-	    for (n = 0; n < len; n += MB_BYTE2LEN(text[n]))
-		cell_len += (*mb_ptr2cells)(text + n);
-	    rc.right = FILL_X(col + cell_len);
+	    rc.right = FILL_X(col + mb_string2cells(text, len));
 	}
 	else
 #endif
diff --git a/src/gui_w32.c b/src/gui_w32.c
index cfd4b78..1fdc993 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -2261,12 +2261,8 @@
 #ifdef FEAT_MBYTE
 	if (has_mbyte)
 	{
-	    int cell_len = 0;
-
 	    /* Compute the length in display cells. */
-	    for (n = 0; n < len; n += MB_BYTE2LEN(text[n]))
-		cell_len += (*mb_ptr2cells)(text + n);
-	    rc.right = FILL_X(col + cell_len);
+	    rc.right = FILL_X(col + mb_string2cells(text, len));
 	}
 	else
 #endif
diff --git a/src/mbyte.c b/src/mbyte.c
index 3a83eb4..3719b85 100644
--- a/src/mbyte.c
+++ b/src/mbyte.c
@@ -1579,6 +1579,23 @@
 }
 
 /*
+ * Return the number of cells occupied by string "p".
+ * Stop at a NUL character.  When "len" >= 0 stop at character "p[len]".
+ */
+    int
+mb_string2cells(p, len)
+    char_u  *p;
+    int	    len;
+{
+    int i;
+    int clen = 0;
+
+    for (i = 0; (len < 0 || i < len) && p[i] != NUL; i += (*mb_ptr2len)(p + i))
+	clen += (*mb_ptr2cells)(p + i);
+    return clen;
+}
+
+/*
  * mb_off2cells() function pointer.
  * Return number of display cells for char at ScreenLines[off].
  * We make sure that the offset used is less than "max_off".
@@ -4364,12 +4381,12 @@
 	     const gchar *str,
 	     gpointer data UNUSED)
 {
-    int	slen = (int)STRLEN(str);
-    int	add_to_input = TRUE;
-    int	clen;
-    int	len = slen;
-    int	commit_with_preedit = TRUE;
-    char_u	*im_str, *p;
+    int		slen = (int)STRLEN(str);
+    int		add_to_input = TRUE;
+    int		clen;
+    int		len = slen;
+    int		commit_with_preedit = TRUE;
+    char_u	*im_str;
 
 #ifdef XIM_DEBUG
     xim_log("im_commit_cb(): %s\n", str);
@@ -4402,9 +4419,9 @@
     }
     else
 	im_str = (char_u *)str;
-    clen = 0;
-    for (p = im_str; p < im_str + len; p += (*mb_ptr2len)(p))
-	clen += (*mb_ptr2cells)(p);
+
+    clen = mb_string2cells(im_str, len);
+
     if (input_conv.vc_type != CONV_NONE)
 	vim_free(im_str);
     preedit_start_col += clen;
diff --git a/src/proto/mbyte.pro b/src/proto/mbyte.pro
index e805cb4..9519a19 100644
--- a/src/proto/mbyte.pro
+++ b/src/proto/mbyte.pro
@@ -14,6 +14,7 @@
 int dbcs_ptr2cells __ARGS((char_u *p));
 int latin_ptr2cells_len __ARGS((char_u *p, int size));
 int latin_char2cells __ARGS((int c));
+int mb_string2cells __ARGS((char_u *p, int len));
 int latin_off2cells __ARGS((unsigned off, unsigned max_off));
 int dbcs_off2cells __ARGS((unsigned off, unsigned max_off));
 int utf_off2cells __ARGS((unsigned off, unsigned max_off));
diff --git a/src/screen.c b/src/screen.c
index 5b9a073..74898f8 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -6168,8 +6168,8 @@
 		int	clen = 0, i;
 
 		/* Count total number of display cells. */
-		for (i = 0; p[i] != NUL; i += (*mb_ptr2len)(p + i))
-		    clen += (*mb_ptr2cells)(p + i);
+		clen = mb_string2cells(p, -1);
+
 		/* Find first character that will fit.
 		 * Going from start to end is much faster for DBCS. */
 		for (i = 0; p[i] != NUL && clen >= this_ru_col - 1;