To: vim-dev@vim.org Subject: Patch 6.1.383 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit ------------ Patch 6.1.383 Problem: The filling of the status line doesn't work properly for multi-byte characters. (Nam SungHyun) There is no check for going past the end of the buffer. Solution: Properly distinguish characters and bytes. Properly check for running out of buffer space. Files: src/buffer.c, src/ex_cmds2.c, src/proto/buffer.pro, src/screen.c *** ../vim61.382/src/buffer.c Sun Mar 9 14:24:49 2003 --- src/buffer.c Sun Mar 9 17:43:51 2003 *************** *** 2705,2711 **** { #ifdef FEAT_STL_OPT if (stl_syntax & STL_IN_TITLE) ! build_stl_str_hl(curwin, t_str, p_titlestring, 0, maxlen, NULL); else #endif t_str = p_titlestring; --- 2705,2712 ---- { #ifdef FEAT_STL_OPT if (stl_syntax & STL_IN_TITLE) ! build_stl_str_hl(curwin, t_str, sizeof(buf), ! p_titlestring, 0, maxlen, NULL); else #endif t_str = p_titlestring; *************** *** 2805,2811 **** { #ifdef FEAT_STL_OPT if (stl_syntax & STL_IN_ICON) ! build_stl_str_hl(curwin, i_str, p_iconstring, 0, 0, NULL); else #endif i_str = p_iconstring; --- 2806,2813 ---- { #ifdef FEAT_STL_OPT if (stl_syntax & STL_IN_ICON) ! build_stl_str_hl(curwin, i_str, sizeof(buf), ! p_iconstring, 0, 0, NULL); else #endif i_str = p_iconstring; *************** *** 2874,2895 **** #if defined(FEAT_STL_OPT) || defined(PROTO) /* ! * Build a string from the status line items in fmt, return length of string. * * Items are drawn interspersed with the text that surrounds it * Specials: %-(xxx%) => group, %= => middle marker, %< => truncation * Item: %-. All but are optional * ! * if maxlen is not zero, the string will be filled at any middle marker ! * or truncated if too long, fillchar is used for all whitespace */ int ! build_stl_str_hl(wp, out, fmt, fillchar, maxlen, hl) win_T *wp; ! char_u *out; char_u *fmt; int fillchar; ! int maxlen; struct stl_hlrec *hl; { char_u *p; --- 2876,2899 ---- #if defined(FEAT_STL_OPT) || defined(PROTO) /* ! * Build a string from the status line items in fmt. ! * Return length of string in screen cells. * * Items are drawn interspersed with the text that surrounds it * Specials: %-(xxx%) => group, %= => middle marker, %< => truncation * Item: %-. All but are optional * ! * If maxwidth is not zero, the string will be filled at any middle marker ! * or truncated if too long, fillchar is used for all whitespace. */ int ! build_stl_str_hl(wp, out, outlen, fmt, fillchar, maxwidth, hl) win_T *wp; ! char_u *out; /* buffer to write into */ ! size_t outlen; /* length of out[] */ char_u *fmt; int fillchar; ! int maxwidth; struct stl_hlrec *hl; { char_u *p; *************** *** 2909,2914 **** --- 2913,2919 ---- int itemisflag; char_u *str; long num; + int width; int itemcnt; int curitem; int groupitem[STL_MAX_ITEM]; *************** *** 2936,2942 **** #define TMPLEN 70 char_u tmp[TMPLEN]; ! if (!fillchar) fillchar = ' '; /* * Get line & check if empty (cursorpos will show "0-1"). --- 2941,2947 ---- #define TMPLEN 70 char_u tmp[TMPLEN]; ! if (fillchar == 0) fillchar = ' '; /* * Get line & check if empty (cursorpos will show "0-1"). *************** *** 2952,2966 **** prevchar_isitem = FALSE; for (s = fmt; *s;) { ! if (*s && *s != '%') prevchar_isflag = prevchar_isitem = FALSE; ! while (*s && *s != '%') *p++ = *s++; ! if (!*s) break; s++; if (*s == '%') { *p++ = *s++; prevchar_isflag = prevchar_isitem = FALSE; continue; --- 2957,2981 ---- prevchar_isitem = FALSE; for (s = fmt; *s;) { ! if (*s != NUL && *s != '%') prevchar_isflag = prevchar_isitem = FALSE; ! ! /* ! * Handle up to the next '%' or the end. ! */ ! while (*s != NUL && *s != '%' && p + 1 < out + outlen) *p++ = *s++; ! if (*s == NUL || p + 1 >= out + outlen) break; + + /* + * Handle one '%' item. + */ s++; if (*s == '%') { + if (p + 1 >= out + outlen) + break; *p++ = *s++; prevchar_isflag = prevchar_isitem = FALSE; continue; *************** *** 2987,3038 **** if (groupdepth < 1) continue; groupdepth--; ! l = (long)(p - item[groupitem[groupdepth]].start); if (curitem > groupitem[groupdepth] + 1 && item[groupitem[groupdepth]].minwid == 0) ! { /* remove group if all items are empty */ for (n = groupitem[groupdepth] + 1; n < curitem; n++) if (item[n].type == Normal) break; if (n == curitem) ! p = item[groupitem[groupdepth]].start; } ! if (item[groupitem[groupdepth]].maxwid < l) ! { /* truncate */ ! n = item[groupitem[groupdepth]].maxwid; ! mch_memmove(item[groupitem[groupdepth]].start, ! item[groupitem[groupdepth]].start + l - n, ! (size_t)n); ! t = item[groupitem[groupdepth]].start; *t = '<'; ! l -= n; ! p -= l; ! for (n = groupitem[groupdepth] + 1; n < curitem; n++) { ! item[n].start -= l; ! if (item[n].start < t) ! item[n].start = t; } } else if (abs(item[groupitem[groupdepth]].minwid) > l) ! { /* fill */ n = item[groupitem[groupdepth]].minwid; if (n < 0) { n = 0 - n; ! while (l++ < n) *p++ = fillchar; } else { ! mch_memmove(item[groupitem[groupdepth]].start + n - l, ! item[groupitem[groupdepth]].start, ! (size_t)l); l = n - l; p += l; for (n = groupitem[groupdepth] + 1; n < curitem; n++) item[n].start += l; ! for (t = item[groupitem[groupdepth]].start; l > 0; l--) *t++ = fillchar; } } --- 3002,3081 ---- if (groupdepth < 1) continue; groupdepth--; ! ! t = item[groupitem[groupdepth]].start; ! *p = NUL; ! l = vim_strsize(t); if (curitem > groupitem[groupdepth] + 1 && item[groupitem[groupdepth]].minwid == 0) ! { ! /* remove group if all items are empty */ for (n = groupitem[groupdepth] + 1; n < curitem; n++) if (item[n].type == Normal) break; if (n == curitem) ! { ! p = t; ! l = 0; ! } } ! if (l > item[groupitem[groupdepth]].maxwid) ! { ! /* truncate, remove n bytes of text at the start */ ! #ifdef FEAT_MBYTE ! if (has_mbyte) ! { ! /* Find the first character that should be included. */ ! n = 0; ! while (l >= item[groupitem[groupdepth]].maxwid) ! { ! l -= ptr2cells(t + n); ! n += (*mb_ptr2len_check)(t + n); ! } ! } ! else ! #endif ! n = (p - t) - item[groupitem[groupdepth]].maxwid + 1; ! *t = '<'; ! mch_memmove(t + 1, t + n, p - (t + n)); ! p = p - n + 1; ! #ifdef FEAT_MBYTE ! /* Fill up space left over by half a double-wide char. */ ! while (++l < item[groupitem[groupdepth]].minwid) ! *p++ = fillchar; ! #endif ! ! /* correct the start of the items for the truncation */ ! for (l = groupitem[groupdepth] + 1; l < curitem; l++) { ! item[l].start -= n; ! if (item[l].start < t) ! item[l].start = t; } } else if (abs(item[groupitem[groupdepth]].minwid) > l) ! { ! /* fill */ n = item[groupitem[groupdepth]].minwid; if (n < 0) { + /* fill by appending characters */ n = 0 - n; ! while (l++ < n && p + 1 < out + outlen) *p++ = fillchar; } else { ! /* fill by inserting characters */ ! mch_memmove(t + n - l, t, p - t); l = n - l; + if (p + l >= out + outlen) + l = (out + outlen) - p - 1; p += l; for (n = groupitem[groupdepth] + 1; n < curitem; n++) item[n].start += l; ! for ( ; l > 0; l--) *t++ = fillchar; } } *************** *** 3124,3132 **** case STL_VIM_EXPR: /* '{' */ itemisflag = TRUE; t = p; ! while (*s != '}' && *s != NUL) *p++ = *s++; ! if (*s == NUL) /* missing '}' */ break; s++; *p = 0; --- 3167,3175 ---- case STL_VIM_EXPR: /* '{' */ itemisflag = TRUE; t = p; ! while (*s != '}' && *s != NUL && p + 1 < out + outlen) *p++ = *s++; ! if (*s != '}') /* missing '}' or out of space */ break; s++; *p = 0; *************** *** 3333,3339 **** t++; prevchar_isflag = TRUE; } ! l = (long)vim_strsize(t); if (l > 0) prevchar_isitem = TRUE; if (l > maxwid) --- 3376,3382 ---- t++; prevchar_isflag = TRUE; } ! l = vim_strsize(t); if (l > 0) prevchar_isitem = TRUE; if (l > maxwid) *************** *** 3348,3370 **** else #endif l -= byte2cells(*t++); *p++ = '<'; } if (minwid > 0) { ! for (; l < minwid; l++) *p++ = fillchar; minwid = 0; } else minwid *= -1; ! while (*t) { *p++ = *t++; if (p[-1] == ' ') p[-1] = fillchar; } ! for (; l < minwid; l++) *p++ = fillchar; } else if (num >= 0) --- 3391,3415 ---- else #endif l -= byte2cells(*t++); + if (p + 1 >= out + outlen) + break; *p++ = '<'; } if (minwid > 0) { ! for (; l < minwid && p + 1 < out + outlen; l++) *p++ = fillchar; minwid = 0; } else minwid *= -1; ! while (*t && p + 1 < out + outlen) { *p++ = *t++; if (p[-1] == ' ') p[-1] = fillchar; } ! for (; l < minwid && p + 1 < out + outlen; l++) *p++ = fillchar; } else if (num >= 0) *************** *** 3372,3377 **** --- 3417,3424 ---- int nbase = (base == 'D' ? 10 : (base == 'O' ? 8 : 16)); char_u nstr[20]; + if (p + 20 >= out + outlen) + break; /* not sufficient space */ prevchar_isitem = TRUE; t = nstr; if (opt == STL_VIRTCOL_ALT) *************** *** 3400,3409 **** *t++ = '%'; *t = t[-3]; *++t = 0; ! sprintf((char *) p, (char *) nstr, 0, num, n); } else ! sprintf((char *) p, (char *) nstr, minwid, num); p += STRLEN(p); } else --- 3447,3456 ---- *t++ = '%'; *t = t[-3]; *++t = 0; ! sprintf((char *)p, (char *)nstr, 0, num, n); } else ! sprintf((char *)p, (char *)nstr, minwid, num); p += STRLEN(p); } else *************** *** 3416,3478 **** prevchar_isflag = FALSE; /* Item not NULL, but not a flag */ curitem++; } ! *p = 0; itemcnt = curitem; - num = (long)STRLEN(out); ! if (maxlen && num > maxlen) ! { /* Apply STL_TRUNC */ ! for (l = 0; l < itemcnt; l++) ! if (item[l].type == Trunc) ! break; if (itemcnt == 0) s = out; else { ! l = l == itemcnt ? 0 : l; ! s = item[l].start; } ! if ((int) (s - out) > maxlen) ! { /* Truncation mark is beyond max length */ ! s = out + maxlen - 1; for (l = 0; l < itemcnt; l++) if (item[l].start > s) break; *s++ = '>'; *s = 0; - itemcnt = l; } else { ! int shift = num - maxlen; ! ! p = s + shift; ! mch_memmove(s, p, STRLEN(p) + 1); *s = '<'; for (; l < itemcnt; l++) { ! if (item[l].start - shift >= out) ! item[l].start -= shift; else item[l].start = out; } } ! num = maxlen; } ! else if (num < maxlen) ! { /* Apply STL_MIDDLE if any */ for (l = 0; l < itemcnt; l++) if (item[l].type == Middle) break; if (l < itemcnt) { ! p = item[l].start + maxlen - num; mch_memmove(p, item[l].start, STRLEN(item[l].start) + 1); for (s = item[l].start; s < p; s++) *s = fillchar; for (l++; l < itemcnt; l++) ! item[l].start += maxlen - num; ! num = maxlen; } } --- 3463,3571 ---- prevchar_isflag = FALSE; /* Item not NULL, but not a flag */ curitem++; } ! *p = NUL; itemcnt = curitem; ! width = vim_strsize(out); ! if (maxwidth > 0 && width > maxwidth) ! { ! /* Result is too long, must trunctate somewhere. */ ! l = 0; if (itemcnt == 0) s = out; else { ! s = item[0].start; ! for ( ; l < itemcnt; l++) ! if (item[l].type == Trunc) ! { ! /* Truncate at %< item. */ ! s = item[l].start; ! break; ! } } ! ! if (width - vim_strsize(s) > maxwidth) ! { ! /* Truncation mark is beyond max length */ ! #ifdef FEAT_MBYTE ! if (has_mbyte) ! { ! s = out; ! width = 0; ! for (;;) ! { ! width += ptr2cells(s); ! if (width >= maxwidth) ! break; ! s += (*mb_ptr2len_check)(s); ! } ! /* Fill up for half a double-wide character. */ ! while (++width < maxwidth) ! *s++ = fillchar; ! } ! #endif ! else ! s = out + maxwidth - 1; for (l = 0; l < itemcnt; l++) if (item[l].start > s) break; + itemcnt = l; *s++ = '>'; *s = 0; } else { ! #ifdef FEAT_MBYTE ! if (has_mbyte) ! { ! n = 0; ! while (width >= maxwidth) ! { ! width -= ptr2cells(s + n); ! n += (*mb_ptr2len_check)(s + n); ! } ! } ! else ! #endif ! n = width - maxwidth + 1; ! p = s + n; ! mch_memmove(s + 1, p, STRLEN(p) + 1); *s = '<'; + + /* Fill up for half a double-wide character. */ + while (++width < maxwidth) + { + s = s + STRLEN(s); + *s++ = fillchar; + *s = NUL; + } + for (; l < itemcnt; l++) { ! if (item[l].start - n >= out) ! item[l].start -= n; else item[l].start = out; } } ! width = maxwidth; } ! else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen) ! { ! /* Apply STL_MIDDLE if any */ for (l = 0; l < itemcnt; l++) if (item[l].type == Middle) break; if (l < itemcnt) { ! p = item[l].start + maxwidth - width; mch_memmove(p, item[l].start, STRLEN(item[l].start) + 1); for (s = item[l].start; s < p; s++) *s = fillchar; for (l++; l < itemcnt; l++) ! item[l].start += maxwidth - width; ! width = maxwidth; } } *************** *** 3491,3497 **** hl->userhl = 0; } ! return (int)num; } #endif /* FEAT_STL_OPT */ --- 3584,3590 ---- hl->userhl = 0; } ! return width; } #endif /* FEAT_STL_OPT */ *** ../vim61.382/src/ex_cmds2.c Sun Mar 9 15:05:10 2003 --- src/ex_cmds2.c Sat Mar 8 15:13:45 2003 *************** *** 2864,2870 **** curwin->w_botline = lnum + 63; printer_page_num = pagenum; ! build_stl_str_hl(curwin, tbuf, p_header, ' ', width, NULL); /* Reset line numbers */ curwin->w_cursor.lnum = tmp_lnum; --- 2866,2873 ---- curwin->w_botline = lnum + 63; printer_page_num = pagenum; ! build_stl_str_hl(curwin, tbuf, (size_t)(width + IOSIZE), ! p_header, ' ', width, NULL); /* Reset line numbers */ curwin->w_cursor.lnum = tmp_lnum; *** ../vim61.382/src/proto/buffer.pro Sat Mar 8 20:33:32 2003 --- src/proto/buffer.pro Sat Mar 8 15:47:27 2003 *************** *** 37,43 **** void col_print __ARGS((char_u *buf, int col, int vcol)); void maketitle __ARGS((void)); void resettitle __ARGS((void)); ! int build_stl_str_hl __ARGS((win_T *wp, char_u *out, char_u *fmt, int fillchar, int maxlen, struct stl_hlrec *hl)); void get_rel_pos __ARGS((win_T *wp, char_u *str)); int append_arg_number __ARGS((win_T *wp, char_u *buf, int add_file, int maxlen)); char_u *fix_fname __ARGS((char_u *fname)); --- 37,43 ---- void col_print __ARGS((char_u *buf, int col, int vcol)); void maketitle __ARGS((void)); void resettitle __ARGS((void)); ! int build_stl_str_hl __ARGS((win_T *wp, char_u *out, size_t outlen, char_u *fmt, int fillchar, int maxwidth, struct stl_hlrec *hl)); void get_rel_pos __ARGS((win_T *wp, char_u *str)); int append_arg_number __ARGS((win_T *wp, char_u *buf, int add_file, int maxlen)); char_u *fix_fname __ARGS((char_u *fname)); *** ../vim61.382/src/screen.c Sat Mar 8 20:33:33 2003 --- src/screen.c Sat Mar 8 15:09:21 2003 *************** *** 5020,5026 **** int curattr; int row; int col = 0; ! int maxlen; int n; int len; int fillchar; --- 5021,5028 ---- int curattr; int row; int col = 0; ! int maxwidth; ! int width; int n; int len; int fillchar; *************** *** 5032,5038 **** /* setup environment for the task at hand */ row = W_WINROW(wp) + wp->w_height; fillchar = fillchar_status(&attr, wp == curwin); ! maxlen = W_WIDTH(wp); p = p_stl; if (Ruler) { --- 5034,5040 ---- /* setup environment for the task at hand */ row = W_WINROW(wp) + wp->w_height; fillchar = fillchar_status(&attr, wp == curwin); ! maxwidth = W_WIDTH(wp); p = p_stl; if (Ruler) { *************** *** 5057,5086 **** if (col > (Columns + 1) / 2) col = (Columns + 1) / 2; #endif ! maxlen = W_WIDTH(wp) - col; #ifdef FEAT_WINDOWS if (!wp->w_status_height) #endif { row = Rows - 1; ! --maxlen; /* writing in last column may cause scrolling */ fillchar = ' '; attr = 0; } } ! if (maxlen >= sizeof(buf)) ! maxlen = sizeof(buf) - 1; ! if (maxlen <= 0) return; #ifdef FEAT_VERTSPLIT col += W_WINCOL(wp); #endif ! len = build_stl_str_hl(wp, buf, p, fillchar, maxlen, hl); ! for (p = buf + len; p < buf + maxlen; p++) ! *p = fillchar; ! buf[maxlen] = NUL; curattr = attr; p = buf; --- 5059,5090 ---- if (col > (Columns + 1) / 2) col = (Columns + 1) / 2; #endif ! maxwidth = W_WIDTH(wp) - col; #ifdef FEAT_WINDOWS if (!wp->w_status_height) #endif { row = Rows - 1; ! --maxwidth; /* writing in last column may cause scrolling */ fillchar = ' '; attr = 0; } } ! if (maxwidth <= 0) return; #ifdef FEAT_VERTSPLIT col += W_WINCOL(wp); #endif ! width = build_stl_str_hl(wp, buf, sizeof(buf), p, fillchar, maxwidth, hl); ! len = STRLEN(buf); ! while (width < maxwidth && len < sizeof(buf) - 1) ! { ! buf[len++] = fillchar; ! ++width; ! } ! buf[len] = NUL; curattr = attr; p = buf; *** ../vim61.382/src/version.c Sun Mar 9 16:21:47 2003 --- src/version.c Sun Mar 9 17:45:17 2003 *************** *** 613,614 **** --- 613,616 ---- { /* Add new patch number below this line */ + /**/ + 383, /**/ -- hundred-and-one symptoms of being an internet addict: 3. Your bookmark takes 15 minutes to scroll from top to bottom. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// Creator of Vim - Vi IMproved -- http://www.Vim.org \\\ \\\ Project leader for A-A-P -- http://www.A-A-P.org /// \\\ Help AIDS victims, buy at Amazon -- http://ICCF.nl/click1.html ///