comparison src/ops.c @ 35048:f59010300ceb v9.1.0373

patch 9.1.0373: ops.c code uses too many strlen() calls Commit: https://github.com/vim/vim/commit/38b9f45253f582ab63174376e321092f8a9a7808 Author: John Marriott <basilisk@internode.on.net> Date: Thu Apr 25 21:39:18 2024 +0200 patch 9.1.0373: ops.c code uses too many strlen() calls Problem: ops.c code uses too many strlen() calls Solution: Refactor code and remove more strlen() calls (John Marriott) closes: #14598 Signed-off-by: John Marriott <basilisk@internode.on.net> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Thu, 25 Apr 2024 21:45:06 +0200
parents bcacdee71db4
children 617f9087f97c
comparison
equal deleted inserted replaced
35047:6f7c02ee79f5 35048:f59010300ceb
279 { 279 {
280 int left = (oap->op_type == OP_LSHIFT); 280 int left = (oap->op_type == OP_LSHIFT);
281 int oldstate = State; 281 int oldstate = State;
282 int total; 282 int total;
283 char_u *newp, *oldp; 283 char_u *newp, *oldp;
284 size_t newlen, oldlen;
284 int oldcol = curwin->w_cursor.col; 285 int oldcol = curwin->w_cursor.col;
285 int sw_val = (int)get_sw_value_indent(curbuf); 286 int sw_val = (int)get_sw_value_indent(curbuf);
286 int ts_val = (int)curbuf->b_p_ts; 287 int ts_val = (int)curbuf->b_p_ts;
287 struct block_def bd; 288 struct block_def bd;
288 int incr; 289 int incr;
289 colnr_T ws_vcol; 290 colnr_T ws_vcol;
290 int added; 291 int added;
291 unsigned new_line_len; // the length of the line after the 292 size_t new_line_len; // the length of the line after the
292 // block shift 293 // block shift
293 #ifdef FEAT_RIGHTLEFT 294 #ifdef FEAT_RIGHTLEFT
294 int old_p_ri = p_ri; 295 int old_p_ri = p_ri;
295 296
296 p_ri = 0; // don't want revins in indent 297 p_ri = 0; // don't want revins in indent
305 total = (int)((unsigned)amount * (unsigned)sw_val); 306 total = (int)((unsigned)amount * (unsigned)sw_val);
306 if ((total / sw_val) != amount) 307 if ((total / sw_val) != amount)
307 return; // multiplication overflow 308 return; // multiplication overflow
308 309
309 oldp = ml_get_curline(); 310 oldp = ml_get_curline();
311 oldlen = ml_get_curline_len();
310 312
311 if (!left) 313 if (!left)
312 { 314 {
313 int tabs = 0, spaces = 0; 315 int tabs = 0, spaces = 0;
314 chartabsize_T cts; 316 chartabsize_T cts;
367 spaces = total; 369 spaces = total;
368 #endif 370 #endif
369 // if we're splitting a TAB, allow for it 371 // if we're splitting a TAB, allow for it
370 bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0); 372 bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
371 373
372 new_line_len = bd.textcol + tabs + spaces + (int)STRLEN(bd.textstart); 374 new_line_len = bd.textcol + tabs + spaces + (oldlen - (bd.textstart - oldp));
373 newp = alloc(new_line_len + 1); 375 newp = alloc(new_line_len + 1);
374 if (newp == NULL) 376 if (newp == NULL)
375 return; 377 return;
376 mch_memmove(newp, oldp, (size_t)bd.textcol); 378 mch_memmove(newp, oldp, (size_t)bd.textcol);
377 vim_memset(newp + bd.textcol, TAB, (size_t)tabs); 379 newlen = bd.textcol;
378 vim_memset(newp + bd.textcol + tabs, ' ', (size_t)spaces); 380 vim_memset(newp + newlen, TAB, (size_t)tabs);
379 // Note that STRMOVE() copies the trailing NUL. 381 newlen += tabs;
380 STRMOVE(newp + bd.textcol + tabs + spaces, bd.textstart); 382 vim_memset(newp + newlen, ' ', (size_t)spaces);
383 STRCPY(newp + newlen + spaces, bd.textstart);
381 } 384 }
382 else // left 385 else // left
383 { 386 {
384 colnr_T destination_col; // column to which text in block will 387 colnr_T destination_col; // column to which text in block will
385 // be shifted 388 // be shifted
386 char_u *verbatim_copy_end; // end of the part of the line which is 389 char_u *verbatim_copy_end; // end of the part of the line which is
387 // copied verbatim 390 // copied verbatim
388 colnr_T verbatim_copy_width;// the (displayed) width of this part 391 colnr_T verbatim_copy_width;// the (displayed) width of this part
389 // of line 392 // of line
390 unsigned fill; // nr of spaces that replace a TAB 393 size_t fill; // nr of spaces that replace a TAB
391 size_t block_space_width; 394 size_t block_space_width;
392 size_t shift_amount; 395 size_t shift_amount;
393 char_u *non_white = bd.textstart; 396 char_u *non_white = bd.textstart;
394 colnr_T non_white_col; 397 colnr_T non_white_col;
398 size_t fixedlen; // length of string left of the shift
399 // position (ie the string not being shifted)
395 chartabsize_T cts; 400 chartabsize_T cts;
396 401
397 /* 402 /*
398 * Firstly, let's find the first non-whitespace character that is 403 * Firstly, let's find the first non-whitespace character that is
399 * displayed after the block's start column and the character's column 404 * displayed after the block's start column and the character's column
461 466
462 // The replacement line will consist of: 467 // The replacement line will consist of:
463 // - the beginning of the original line up to "verbatim_copy_end", 468 // - the beginning of the original line up to "verbatim_copy_end",
464 // - "fill" number of spaces, 469 // - "fill" number of spaces,
465 // - the rest of the line, pointed to by non_white. 470 // - the rest of the line, pointed to by non_white.
466 new_line_len = (unsigned)(verbatim_copy_end - oldp) 471 fixedlen = verbatim_copy_end - oldp;
467 + fill 472 new_line_len = fixedlen + fill + (oldlen - (non_white - oldp));
468 + (unsigned)STRLEN(non_white);
469 473
470 newp = alloc(new_line_len + 1); 474 newp = alloc(new_line_len + 1);
471 if (newp == NULL) 475 if (newp == NULL)
472 return; 476 return;
473 mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp)); 477 mch_memmove(newp, oldp, fixedlen);
474 vim_memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill); 478 newlen = fixedlen;
475 // Note that STRMOVE() copies the trailing NUL. 479 vim_memset(newp + newlen, ' ', (size_t)fill);
476 STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white); 480 STRCPY(newp + newlen + fill, non_white);
477 } 481 }
478 // replace the line 482 // replace the line
479 added = new_line_len - ml_get_curline_len();
480 ml_replace(curwin->w_cursor.lnum, newp, FALSE); 483 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
484
485 // compute the number of bytes added or subtracted.
486 // note new_line_len and oldlen are unsigned so we have
487 // to be careful about how we calculate this.
488 if (new_line_len >= oldlen)
489 added = (int)(new_line_len - oldlen);
490 else
491 added = 0 - (int)(oldlen - new_line_len);
481 inserted_bytes(curwin->w_cursor.lnum, bd.textcol, added); 492 inserted_bytes(curwin->w_cursor.lnum, bd.textcol, added);
482 State = oldstate; 493 State = oldstate;
483 curwin->w_cursor.col = oldcol; 494 curwin->w_cursor.col = oldcol;
484 #ifdef FEAT_RIGHTLEFT 495 #ifdef FEAT_RIGHTLEFT
485 p_ri = old_p_ri; 496 p_ri = old_p_ri;
492 */ 503 */
493 static void 504 static void
494 block_insert( 505 block_insert(
495 oparg_T *oap, 506 oparg_T *oap,
496 char_u *s, 507 char_u *s,
508 size_t slen,
497 int b_insert, 509 int b_insert,
498 struct block_def *bdp) 510 struct block_def *bdp)
499 { 511 {
500 int ts_val; 512 int ts_val;
501 int count = 0; // extra spaces to replace a cut TAB 513 int count = 0; // extra spaces to replace a cut TAB
502 int spaces = 0; // non-zero if cutting a TAB 514 int spaces = 0; // non-zero if cutting a TAB
503 colnr_T offset; // pointer along new line 515 colnr_T offset; // pointer along new line
504 colnr_T startcol; // column where insert starts 516 colnr_T startcol; // column where insert starts
505 unsigned s_len; // STRLEN(s)
506 char_u *newp, *oldp; // new, old lines 517 char_u *newp, *oldp; // new, old lines
507 linenr_T lnum; // loop var 518 linenr_T lnum; // loop var
508 int oldstate = State; 519 int oldstate = State;
509 520
510 State = MODE_INSERT; // don't want MODE_REPLACE for State 521 State = MODE_INSERT; // don't want MODE_REPLACE for State
511 s_len = (unsigned)STRLEN(s);
512 522
513 for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++) 523 for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++)
514 { 524 {
515 block_prep(oap, bdp, lnum, TRUE); 525 block_prep(oap, bdp, lnum, TRUE);
516 if (bdp->is_short && b_insert) 526 if (bdp->is_short && b_insert)
552 562
553 if (spaces < 0) // can happen when the cursor was moved 563 if (spaces < 0) // can happen when the cursor was moved
554 spaces = 0; 564 spaces = 0;
555 565
556 // Make sure the allocated size matches what is actually copied below. 566 // Make sure the allocated size matches what is actually copied below.
557 newp = alloc(ml_get_len(lnum) + spaces + s_len 567 newp = alloc(ml_get_len(lnum) + spaces + slen
558 + (spaces > 0 && !bdp->is_short ? ts_val - spaces : 0) 568 + (spaces > 0 && !bdp->is_short ? ts_val - spaces : 0)
559 + count + 1); 569 + count + 1);
560 if (newp == NULL) 570 if (newp == NULL)
561 continue; 571 continue;
562 572
567 // insert pre-padding 577 // insert pre-padding
568 vim_memset(newp + offset, ' ', (size_t)spaces); 578 vim_memset(newp + offset, ' ', (size_t)spaces);
569 startcol = offset + spaces; 579 startcol = offset + spaces;
570 580
571 // copy the new text 581 // copy the new text
572 mch_memmove(newp + startcol, s, (size_t)s_len); 582 mch_memmove(newp + startcol, s, slen);
573 offset += s_len; 583 offset += slen;
574 584
575 if (spaces > 0 && !bdp->is_short) 585 if (spaces > 0 && !bdp->is_short)
576 { 586 {
577 if (*oldp == TAB) 587 if (*oldp == TAB)
578 { 588 {
589 count = spaces; 599 count = spaces;
590 } 600 }
591 601
592 if (spaces > 0) 602 if (spaces > 0)
593 offset += count; 603 offset += count;
594 STRMOVE(newp + offset, oldp); 604 STRCPY(newp + offset, oldp);
595 605
596 ml_replace(lnum, newp, FALSE); 606 ml_replace(lnum, newp, FALSE);
597 607
598 if (b_insert) 608 if (b_insert)
599 // correct any text properties 609 // correct any text properties
600 inserted_bytes(lnum, startcol, s_len); 610 inserted_bytes(lnum, startcol, slen);
601 611
602 if (lnum == oap->end.lnum) 612 if (lnum == oap->end.lnum)
603 { 613 {
604 // Set "']" mark to the end of the block instead of the end of 614 // Set "']" mark to the end of the block instead of the end of
605 // the insert in the first line. 615 // the insert in the first line.
807 mch_memmove(newp, oldp, (size_t)bd.textcol); 817 mch_memmove(newp, oldp, (size_t)bd.textcol);
808 // insert spaces 818 // insert spaces
809 vim_memset(newp + bd.textcol, ' ', 819 vim_memset(newp + bd.textcol, ' ',
810 (size_t)(bd.startspaces + bd.endspaces)); 820 (size_t)(bd.startspaces + bd.endspaces));
811 // copy the part after the deleted part 821 // copy the part after the deleted part
812 oldp += bd.textcol + bd.textlen; 822 STRCPY(newp + bd.textcol + bd.startspaces + bd.endspaces,
813 STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp); 823 oldp + bd.textcol + bd.textlen);
814 // replace the line 824 // replace the line
815 ml_replace(lnum, newp, FALSE); 825 ml_replace(lnum, newp, FALSE);
816 826
817 #ifdef FEAT_PROP_POPUP 827 #ifdef FEAT_PROP_POPUP
818 if (curbuf->b_has_textprop && n != 0) 828 if (curbuf->b_has_textprop && n != 0)
1028 op_replace(oparg_T *oap, int c) 1038 op_replace(oparg_T *oap, int c)
1029 { 1039 {
1030 int n, numc; 1040 int n, numc;
1031 int num_chars; 1041 int num_chars;
1032 char_u *newp, *oldp; 1042 char_u *newp, *oldp;
1033 size_t oldlen; 1043 size_t newlen, oldlen;
1034 struct block_def bd; 1044 struct block_def bd;
1035 char_u *after_p = NULL; 1045 char_u *after_p = NULL;
1036 int had_ctrl_v_cr = FALSE; 1046 int had_ctrl_v_cr = FALSE;
1037 1047
1038 if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty) 1048 if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
1120 if (newp == NULL) 1130 if (newp == NULL)
1121 continue; 1131 continue;
1122 vim_memset(newp, NUL, (size_t)(oldlen + 1 + n)); 1132 vim_memset(newp, NUL, (size_t)(oldlen + 1 + n));
1123 // copy up to deleted part 1133 // copy up to deleted part
1124 mch_memmove(newp, oldp, (size_t)bd.textcol); 1134 mch_memmove(newp, oldp, (size_t)bd.textcol);
1125 oldp += bd.textcol + bd.textlen; 1135 newlen = bd.textcol;
1126 // insert pre-spaces 1136 // insert pre-spaces
1127 vim_memset(newp + bd.textcol, ' ', (size_t)bd.startspaces); 1137 vim_memset(newp + newlen, ' ', (size_t)bd.startspaces);
1138 newlen += bd.startspaces;
1128 // insert replacement chars CHECK FOR ALLOCATED SPACE 1139 // insert replacement chars CHECK FOR ALLOCATED SPACE
1129 // REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR 1140 // REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR
1130 // literally. 1141 // literally.
1131 if (had_ctrl_v_cr || (c != '\r' && c != '\n')) 1142 if (had_ctrl_v_cr || (c != '\r' && c != '\n'))
1132 { 1143 {
1133 if (has_mbyte) 1144 if (has_mbyte)
1134 { 1145 {
1135 n = (int)STRLEN(newp);
1136 while (--num_chars >= 0) 1146 while (--num_chars >= 0)
1137 n += (*mb_char2bytes)(c, newp + n); 1147 newlen += (*mb_char2bytes)(c, newp + newlen);
1138 } 1148 }
1139 else 1149 else
1140 vim_memset(newp + STRLEN(newp), c, (size_t)numc); 1150 {
1151 vim_memset(newp + newlen, c, (size_t)numc);
1152 newlen += numc;
1153 }
1141 if (!bd.is_short) 1154 if (!bd.is_short)
1142 { 1155 {
1143 // insert post-spaces 1156 // insert post-spaces
1144 vim_memset(newp + STRLEN(newp), ' ', (size_t)bd.endspaces); 1157 vim_memset(newp + newlen, ' ', (size_t)bd.endspaces);
1145 // copy the part after the changed part 1158 // copy the part after the changed part
1146 STRMOVE(newp + STRLEN(newp), oldp); 1159 STRCPY(newp + newlen + bd.endspaces,
1160 oldp + bd.textcol + bd.textlen);
1147 } 1161 }
1148 } 1162 }
1149 else 1163 else
1150 { 1164 {
1151 // Replacing with \r or \n means splitting the line. 1165 // Replacing with \r or \n means splitting the line.
1152 after_p = alloc(oldlen + 1 + n - STRLEN(newp)); 1166 after_p = alloc(oldlen + 1 + n - newlen);
1153 if (after_p != NULL) 1167 if (after_p != NULL)
1154 STRMOVE(after_p, oldp); 1168 STRCPY(after_p, oldp + bd.textcol + bd.textlen);
1155 } 1169 }
1170
1156 // replace the line 1171 // replace the line
1157 ml_replace(curwin->w_cursor.lnum, newp, FALSE); 1172 ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1158 if (after_p != NULL) 1173 if (after_p != NULL)
1159 { 1174 {
1160 ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE); 1175 ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE);
1713 if (ins_text != NULL) 1728 if (ins_text != NULL)
1714 { 1729 {
1715 // block handled here 1730 // block handled here
1716 if (u_save(oap->start.lnum, 1731 if (u_save(oap->start.lnum,
1717 (linenr_T)(oap->end.lnum + 1)) == OK) 1732 (linenr_T)(oap->end.lnum + 1)) == OK)
1718 block_insert(oap, ins_text, (oap->op_type == OP_INSERT), 1733 block_insert(oap, ins_text, ins_len, (oap->op_type == OP_INSERT),
1719 &bd); 1734 &bd);
1720 1735
1721 curwin->w_cursor.col = oap->start.col; 1736 curwin->w_cursor.col = oap->start.col;
1722 check_cursor(); 1737 check_cursor();
1723 vim_free(ins_text); 1738 vim_free(ins_text);
1734 int 1749 int
1735 op_change(oparg_T *oap) 1750 op_change(oparg_T *oap)
1736 { 1751 {
1737 colnr_T l; 1752 colnr_T l;
1738 int retval; 1753 int retval;
1739 long offset;
1740 linenr_T linenr; 1754 linenr_T linenr;
1741 long ins_len;
1742 long pre_textlen = 0; 1755 long pre_textlen = 0;
1743 long pre_indent = 0; 1756 long pre_indent = 0;
1744 char_u *firstline; 1757 char_u *firstline;
1745 char_u *ins_text, *newp, *oldp; 1758 char_u *ins_text, *newp, *oldp;
1746 struct block_def bd; 1759 struct block_def bd;
1796 * block. 1809 * block.
1797 * Don't repeat the insert when Insert mode ended with CTRL-C. 1810 * Don't repeat the insert when Insert mode ended with CTRL-C.
1798 */ 1811 */
1799 if (oap->block_mode && oap->start.lnum != oap->end.lnum && !got_int) 1812 if (oap->block_mode && oap->start.lnum != oap->end.lnum && !got_int)
1800 { 1813 {
1814 size_t ins_len;
1815
1801 // Auto-indenting may have changed the indent. If the cursor was past 1816 // Auto-indenting may have changed the indent. If the cursor was past
1802 // the indent, exclude that indent change from the inserted text. 1817 // the indent, exclude that indent change from the inserted text.
1803 firstline = ml_get(oap->start.lnum); 1818 firstline = ml_get(oap->start.lnum);
1804 if (bd.textcol > (colnr_T)pre_indent) 1819 if (bd.textcol > (colnr_T)pre_indent)
1805 { 1820 {
1814 { 1829 {
1815 // Subsequent calls to ml_get() flush the firstline data - take a 1830 // Subsequent calls to ml_get() flush the firstline data - take a
1816 // copy of the inserted text. 1831 // copy of the inserted text.
1817 if ((ins_text = alloc(ins_len + 1)) != NULL) 1832 if ((ins_text = alloc(ins_len + 1)) != NULL)
1818 { 1833 {
1819 vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len); 1834 vim_strncpy(ins_text, firstline + bd.textcol, ins_len);
1820 for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; 1835 for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum;
1821 linenr++) 1836 linenr++)
1822 { 1837 {
1823 block_prep(oap, &bd, linenr, TRUE); 1838 block_prep(oap, &bd, linenr, TRUE);
1824 if (!bd.is_short || virtual_op) 1839 if (!bd.is_short || virtual_op)
1825 { 1840 {
1826 pos_T vpos; 1841 pos_T vpos;
1842 size_t newlen;
1827 1843
1828 // If the block starts in virtual space, count the 1844 // If the block starts in virtual space, count the
1829 // initial coladd offset as part of "startspaces" 1845 // initial coladd offset as part of "startspaces"
1830 if (bd.is_short) 1846 if (bd.is_short)
1831 { 1847 {
1833 (void)getvpos(&vpos, oap->start_vcol); 1849 (void)getvpos(&vpos, oap->start_vcol);
1834 } 1850 }
1835 else 1851 else
1836 vpos.coladd = 0; 1852 vpos.coladd = 0;
1837 oldp = ml_get(linenr); 1853 oldp = ml_get(linenr);
1838 newp = alloc(ml_get_len(linenr) 1854 newp = alloc(ml_get_len(linenr) + vpos.coladd + ins_len + 1);
1839 + vpos.coladd + ins_len + 1);
1840 if (newp == NULL) 1855 if (newp == NULL)
1841 continue; 1856 continue;
1842 // copy up to block start 1857 // copy up to block start
1843 mch_memmove(newp, oldp, (size_t)bd.textcol); 1858 mch_memmove(newp, oldp, (size_t)bd.textcol);
1844 offset = bd.textcol; 1859 newlen = bd.textcol;
1845 vim_memset(newp + offset, ' ', (size_t)vpos.coladd); 1860 vim_memset(newp + newlen, ' ', (size_t)vpos.coladd);
1846 offset += vpos.coladd; 1861 newlen += vpos.coladd;
1847 mch_memmove(newp + offset, ins_text, (size_t)ins_len); 1862 mch_memmove(newp + newlen, ins_text, ins_len);
1848 offset += ins_len; 1863 STRCPY(newp + newlen + ins_len, oldp + bd.textcol);
1849 oldp += bd.textcol;
1850 STRMOVE(newp + offset, oldp);
1851 ml_replace(linenr, newp, FALSE); 1864 ml_replace(linenr, newp, FALSE);
1852 #ifdef FEAT_PROP_POPUP 1865 #ifdef FEAT_PROP_POPUP
1853 // Shift the properties for linenr as edit() would do. 1866 // Shift the properties for linenr as edit() would do.
1854 if (curbuf->b_has_textprop) 1867 if (curbuf->b_has_textprop)
1855 adjust_prop_columns(linenr, bd.textcol, 1868 adjust_prop_columns(linenr, bd.textcol,