neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

register.c (82436B)


      1 // register.c: functions for managing registers
      2 
      3 #include "nvim/api/private/helpers.h"
      4 #include "nvim/autocmd.h"
      5 #include "nvim/buffer.h"
      6 #include "nvim/buffer_defs.h"
      7 #include "nvim/buffer_updates.h"
      8 #include "nvim/change.h"
      9 #include "nvim/charset.h"
     10 #include "nvim/clipboard.h"
     11 #include "nvim/cursor.h"
     12 #include "nvim/drawscreen.h"
     13 #include "nvim/edit.h"
     14 #include "nvim/errors.h"
     15 #include "nvim/eval.h"
     16 #include "nvim/eval/typval.h"
     17 #include "nvim/ex_cmds2.h"
     18 #include "nvim/ex_getln.h"
     19 #include "nvim/extmark.h"
     20 #include "nvim/file_search.h"
     21 #include "nvim/fold.h"
     22 #include "nvim/garray.h"
     23 #include "nvim/getchar.h"
     24 #include "nvim/globals.h"
     25 #include "nvim/indent.h"
     26 #include "nvim/insexpand.h"
     27 #include "nvim/keycodes.h"
     28 #include "nvim/mark.h"
     29 #include "nvim/mbyte.h"
     30 #include "nvim/memline.h"
     31 #include "nvim/message.h"
     32 #include "nvim/move.h"
     33 #include "nvim/normal.h"
     34 #include "nvim/ops.h"
     35 #include "nvim/option.h"
     36 #include "nvim/option_vars.h"
     37 #include "nvim/os/input.h"
     38 #include "nvim/os/time.h"
     39 #include "nvim/plines.h"
     40 #include "nvim/register.h"
     41 #include "nvim/search.h"
     42 #include "nvim/strings.h"
     43 #include "nvim/terminal.h"
     44 #include "nvim/types_defs.h"
     45 #include "nvim/ui.h"
     46 #include "nvim/undo.h"
     47 
     48 #include "register.c.generated.h"
     49 
     50 // Keep the last expression line here, for repeating.
     51 static char *expr_line = NULL;
     52 
     53 static int execreg_lastc = NUL;
     54 
     55 static yankreg_T y_regs[NUM_REGISTERS] = { 0 };
     56 
     57 static yankreg_T *y_previous = NULL;  // ptr to last written yankreg
     58 
     59 static const char e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines[]
     60  = N_("E883: Search pattern and expression register may not contain two or more lines");
     61 
     62 /// @return the index of the register "" points to.
     63 int get_unname_register(void)
     64 {
     65  return y_previous == NULL ? -1 : (int)(y_previous - &y_regs[0]);
     66 }
     67 
     68 yankreg_T *get_y_register(int reg)
     69 {
     70  return &y_regs[reg];
     71 }
     72 
     73 yankreg_T *get_y_previous(void)
     74  FUNC_ATTR_PURE
     75 {
     76  return y_previous;
     77 }
     78 
     79 /// Get an expression for the "\"=expr1" or "CTRL-R =expr1"
     80 ///
     81 /// @return  '=' when OK, NUL otherwise.
     82 int get_expr_register(void)
     83 {
     84  char *new_line = getcmdline('=', 0, 0, true);
     85  if (new_line == NULL) {
     86    return NUL;
     87  }
     88  if (*new_line == NUL) {  // use previous line
     89    xfree(new_line);
     90  } else {
     91    set_expr_line(new_line);
     92  }
     93  return '=';
     94 }
     95 
     96 /// Set the expression for the '=' register.
     97 /// Argument must be an allocated string.
     98 void set_expr_line(char *new_line)
     99 {
    100  xfree(expr_line);
    101  expr_line = new_line;
    102 }
    103 
    104 /// Get the result of the '=' register expression.
    105 ///
    106 /// @return  a pointer to allocated memory, or NULL for failure.
    107 char *get_expr_line(void)
    108 {
    109  static int nested = 0;
    110 
    111  if (expr_line == NULL) {
    112    return NULL;
    113  }
    114 
    115  // Make a copy of the expression, because evaluating it may cause it to be
    116  // changed.
    117  char *expr_copy = xstrdup(expr_line);
    118 
    119  // When we are invoked recursively limit the evaluation to 10 levels.
    120  // Then return the string as-is.
    121  if (nested >= 10) {
    122    return expr_copy;
    123  }
    124 
    125  nested++;
    126  char *rv = eval_to_string(expr_copy, true, false);
    127  nested--;
    128  xfree(expr_copy);
    129  return rv;
    130 }
    131 
    132 /// Get the '=' register expression itself, without evaluating it.
    133 char *get_expr_line_src(void)
    134 {
    135  if (expr_line == NULL) {
    136    return NULL;
    137  }
    138  return xstrdup(expr_line);
    139 }
    140 
    141 /// @return  whether `regname` is a valid name of a yank register.
    142 ///
    143 /// @note: There is no check for 0 (default register), caller should do this.
    144 /// The black hole register '_' is regarded as valid.
    145 ///
    146 /// @param regname name of register
    147 /// @param writing allow only writable registers
    148 bool valid_yank_reg(int regname, bool writing)
    149 {
    150  if ((regname > 0 && ASCII_ISALNUM(regname))
    151      || (!writing && vim_strchr("/.%:=", regname) != NULL)
    152      || regname == '#'
    153      || regname == '"'
    154      || regname == '-'
    155      || regname == '_'
    156      || regname == '*'
    157      || regname == '+') {
    158    return true;
    159  }
    160  return false;
    161 }
    162 
    163 /// Check if the default register (used in an unnamed paste) should be a
    164 /// clipboard register. This happens when `clipboard=unnamed[plus]` is set
    165 /// and a provider is available.
    166 ///
    167 /// @returns the name of of a clipboard register that should be used, or `NUL` if none.
    168 int get_default_register_name(void)
    169 {
    170  int name = NUL;
    171  adjust_clipboard_name(&name, true, false);
    172  return name;
    173 }
    174 
    175 /// Iterate over registers `regs`.
    176 ///
    177 /// @param[in]   iter      Iterator. Pass NULL to start iteration.
    178 /// @param[in]   regs      Registers list to be iterated.
    179 /// @param[out]  name      Register name.
    180 /// @param[out]  reg       Register contents.
    181 ///
    182 /// @return Pointer that must be passed to next `op_register_iter` call or
    183 ///         NULL if iteration is over.
    184 const void *op_reg_iter(const void *const iter, const yankreg_T *const regs, char *const name,
    185                        yankreg_T *const reg, bool *is_unnamed)
    186  FUNC_ATTR_NONNULL_ARG(3, 4, 5) FUNC_ATTR_WARN_UNUSED_RESULT
    187 {
    188  *name = NUL;
    189  const yankreg_T *iter_reg = (iter == NULL
    190                               ? &(regs[0])
    191                               : (const yankreg_T *const)iter);
    192  while (iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS && reg_empty(iter_reg)) {
    193    iter_reg++;
    194  }
    195  if (iter_reg - &(regs[0]) == NUM_SAVED_REGISTERS || reg_empty(iter_reg)) {
    196    return NULL;
    197  }
    198  int iter_off = (int)(iter_reg - &(regs[0]));
    199  *name = (char)get_register_name(iter_off);
    200  *reg = *iter_reg;
    201  *is_unnamed = (iter_reg == y_previous);
    202  while (++iter_reg - &(regs[0]) < NUM_SAVED_REGISTERS) {
    203    if (!reg_empty(iter_reg)) {
    204      return (void *)iter_reg;
    205    }
    206  }
    207  return NULL;
    208 }
    209 
    210 /// Iterate over global registers.
    211 ///
    212 /// @see op_register_iter
    213 const void *op_global_reg_iter(const void *const iter, char *const name, yankreg_T *const reg,
    214                               bool *is_unnamed)
    215  FUNC_ATTR_NONNULL_ARG(2, 3, 4) FUNC_ATTR_WARN_UNUSED_RESULT
    216 {
    217  return op_reg_iter(iter, y_regs, name, reg, is_unnamed);
    218 }
    219 
    220 /// Get a number of non-empty registers
    221 size_t op_reg_amount(void)
    222  FUNC_ATTR_WARN_UNUSED_RESULT
    223 {
    224  size_t ret = 0;
    225  for (size_t i = 0; i < NUM_SAVED_REGISTERS; i++) {
    226    if (!reg_empty(y_regs + i)) {
    227      ret++;
    228    }
    229  }
    230  return ret;
    231 }
    232 
    233 /// Set register to a given value
    234 ///
    235 /// @param[in]  name  Register name.
    236 /// @param[in]  reg  Register value.
    237 /// @param[in]  is_unnamed  Whether to set the unnamed regiseter to reg
    238 ///
    239 /// @return true on success, false on failure.
    240 bool op_reg_set(const char name, const yankreg_T reg, bool is_unnamed)
    241 {
    242  int i = op_reg_index(name);
    243  if (i == -1) {
    244    return false;
    245  }
    246  free_register(&y_regs[i]);
    247  y_regs[i] = reg;
    248 
    249  if (is_unnamed) {
    250    y_previous = &y_regs[i];
    251  }
    252  return true;
    253 }
    254 
    255 /// Get register with the given name
    256 ///
    257 /// @param[in]  name  Register name.
    258 ///
    259 /// @return Pointer to the register contents or NULL.
    260 const yankreg_T *op_reg_get(const char name)
    261 {
    262  int i = op_reg_index(name);
    263  if (i == -1) {
    264    return NULL;
    265  }
    266  return &y_regs[i];
    267 }
    268 
    269 /// Set the previous yank register
    270 ///
    271 /// @param[in]  name  Register name.
    272 ///
    273 /// @return true on success, false on failure.
    274 bool op_reg_set_previous(const char name)
    275 {
    276  int i = op_reg_index(name);
    277  if (i == -1) {
    278    return false;
    279  }
    280 
    281  y_previous = &y_regs[i];
    282  return true;
    283 }
    284 
    285 /// Updates the "y_width" of a blockwise register based on its contents.
    286 /// Do nothing on a non-blockwise register.
    287 void update_yankreg_width(yankreg_T *reg)
    288 {
    289  if (reg->y_type == kMTBlockWise) {
    290    size_t maxlen = 0;
    291    for (size_t i = 0; i < reg->y_size; i++) {
    292      size_t rowlen = mb_string2cells_len(reg->y_array[i].data, reg->y_array[i].size);
    293      maxlen = MAX(maxlen, rowlen);
    294    }
    295    assert(maxlen <= INT_MAX);
    296    reg->y_width = MAX(reg->y_width, (int)maxlen - 1);
    297  }
    298 }
    299 
    300 /// @return yankreg_T to use, according to the value of `regname`.
    301 /// Cannot handle the '_' (black hole) register.
    302 /// Must only be called with a valid register name!
    303 ///
    304 /// @param regname The name of the register used or 0 for the unnamed register
    305 /// @param mode One of the following three flags:
    306 ///
    307 /// `YREG_PASTE`:
    308 /// Prepare for pasting the register `regname`. With no regname specified,
    309 /// read from last written register, or from unnamed clipboard (depending on the
    310 /// `clipboard=unnamed` option). Queries the clipboard provider if necessary.
    311 ///
    312 /// `YREG_YANK`:
    313 /// Preparare for yanking into `regname`. With no regname specified,
    314 /// yank into `"0` register. Update `y_previous` for next unnamed paste.
    315 ///
    316 /// `YREG_PUT`:
    317 /// Obtain the location that would be read when pasting `regname`.
    318 yankreg_T *get_yank_register(int regname, int mode)
    319 {
    320  yankreg_T *reg;
    321 
    322  if ((mode == YREG_PASTE || mode == YREG_PUT)
    323      && get_clipboard(regname, &reg, false)) {
    324    // reg is set to clipboard contents.
    325    return reg;
    326  } else if (mode == YREG_PUT && (regname == '*' || regname == '+')) {
    327    // in case clipboard not available and we aren't actually pasting,
    328    // return an empty register
    329    static yankreg_T empty_reg = { .y_array = NULL };
    330    return &empty_reg;
    331  } else if (mode != YREG_YANK
    332             && (regname == 0 || regname == '"' || regname == '*' || regname == '+')
    333             && y_previous != NULL) {
    334    // in case clipboard not available, paste from previous used register
    335    return y_previous;
    336  }
    337 
    338  int i = op_reg_index(regname);
    339  // when not 0-9, a-z, A-Z or '-'/'+'/'*': use register 0
    340  if (i == -1) {
    341    i = 0;
    342  }
    343  reg = &y_regs[i];
    344 
    345  if (mode == YREG_YANK) {
    346    // remember the written register for unnamed paste
    347    y_previous = reg;
    348  }
    349  return reg;
    350 }
    351 
    352 /// Check if the current yank register has kMTLineWise register type
    353 /// For valid, non-blackhole registers also provides pointer to the register
    354 /// structure prepared for pasting.
    355 ///
    356 /// @param regname The name of the register used or 0 for the unnamed register
    357 /// @param reg Pointer to store yankreg_T* for the requested register. Will be
    358 ///        set to NULL for invalid or blackhole registers.
    359 bool yank_register_mline(int regname, yankreg_T **reg)
    360 {
    361  *reg = NULL;
    362  if (regname != 0 && !valid_yank_reg(regname, false)) {
    363    return false;
    364  }
    365  if (regname == '_') {  // black hole is always empty
    366    return false;
    367  }
    368  *reg = get_yank_register(regname, YREG_PASTE);
    369  return (*reg)->y_type == kMTLineWise;
    370 }
    371 
    372 /// @return  a copy of contents in register `name` for use in do_put. Should be
    373 ///          freed by caller.
    374 yankreg_T *copy_register(int name)
    375  FUNC_ATTR_NONNULL_RET
    376 {
    377  yankreg_T *reg = get_yank_register(name, YREG_PASTE);
    378 
    379  yankreg_T *copy = xmalloc(sizeof(yankreg_T));
    380  *copy = *reg;
    381  if (copy->y_size == 0) {
    382    copy->y_array = NULL;
    383  } else {
    384    copy->y_array = xcalloc(copy->y_size, sizeof(String));
    385    for (size_t i = 0; i < copy->y_size; i++) {
    386      copy->y_array[i] = copy_string(reg->y_array[i], NULL);
    387    }
    388  }
    389  return copy;
    390 }
    391 
    392 /// Stuff string "p" into yank register "regname" as a single line (append if
    393 /// uppercase). "p" must have been allocated.
    394 ///
    395 /// @return  FAIL for failure, OK otherwise
    396 static int stuff_yank(int regname, char *p)
    397 {
    398  // check for read-only register
    399  if (regname != 0 && !valid_yank_reg(regname, true)) {
    400    xfree(p);
    401    return FAIL;
    402  }
    403  if (regname == '_') {             // black hole: don't do anything
    404    xfree(p);
    405    return OK;
    406  }
    407 
    408  const size_t plen = strlen(p);
    409  yankreg_T *reg = get_yank_register(regname, YREG_YANK);
    410  if (is_append_register(regname) && reg->y_array != NULL) {
    411    String *pp = &(reg->y_array[reg->y_size - 1]);
    412    const size_t tmplen = pp->size + plen;
    413    char *tmp = xmalloc(tmplen + 1);
    414    memcpy(tmp, pp->data, pp->size);
    415    memcpy(tmp + pp->size, p, plen);
    416    *(tmp + tmplen) = NUL;
    417    xfree(p);
    418    xfree(pp->data);
    419    *pp = cbuf_as_string(tmp, tmplen);
    420  } else {
    421    free_register(reg);
    422    reg->additional_data = NULL;
    423    reg->y_array = xmalloc(sizeof(String));
    424    reg->y_array[0] = cbuf_as_string(p, plen);
    425    reg->y_size = 1;
    426    reg->y_type = kMTCharWise;
    427  }
    428  reg->timestamp = os_time();
    429  return OK;
    430 }
    431 
    432 /// Start or stop recording into a yank register.
    433 ///
    434 /// @return  FAIL for failure, OK otherwise.
    435 int do_record(int c)
    436 {
    437  static int regname;
    438  int retval;
    439 
    440  if (reg_recording == 0) {
    441    // start recording
    442    // registers 0-9, a-z and " are allowed
    443    if (c < 0 || (!ASCII_ISALNUM(c) && c != '"')) {
    444      retval = FAIL;
    445    } else {
    446      reg_recording = c;
    447      // TODO(bfredl): showmode based messaging is currently missing with cmdheight=0
    448      showmode();
    449      regname = c;
    450      retval = OK;
    451 
    452      apply_autocmds(EVENT_RECORDINGENTER, NULL, NULL, false, curbuf);
    453    }
    454  } else {  // stop recording
    455    save_v_event_T save_v_event;
    456    // Set the v:event dictionary with information about the recording.
    457    dict_T *dict = get_v_event(&save_v_event);
    458 
    459    // The recorded text contents.
    460    char *p = get_recorded();
    461    if (p != NULL) {
    462      // Remove escaping for K_SPECIAL in multi-byte chars.
    463      vim_unescape_ks(p);
    464      tv_dict_add_str(dict, S_LEN("regcontents"), p);
    465    }
    466 
    467    // Name of requested register, or empty string for unnamed operation.
    468    char buf[NUMBUFLEN + 2];
    469    buf[0] = (char)regname;
    470    buf[1] = NUL;
    471    tv_dict_add_str(dict, S_LEN("regname"), buf);
    472    tv_dict_set_keys_readonly(dict);
    473 
    474    // Get the recorded key hits.  K_SPECIAL will be escaped, this
    475    // needs to be removed again to put it in a register.  exec_reg then
    476    // adds the escaping back later.
    477    apply_autocmds(EVENT_RECORDINGLEAVE, NULL, NULL, false, curbuf);
    478    restore_v_event(dict, &save_v_event);
    479    reg_recorded = reg_recording;
    480    reg_recording = 0;
    481    if (p_ch == 0 || ui_has(kUIMessages)) {
    482      showmode();
    483    } else {
    484      msg("", 0);
    485    }
    486    if (p == NULL) {
    487      retval = FAIL;
    488    } else {
    489      // We don't want to change the default register here, so save and
    490      // restore the current register name.
    491      yankreg_T *old_y_previous = y_previous;
    492 
    493      retval = stuff_yank(regname, p);
    494 
    495      y_previous = old_y_previous;
    496    }
    497  }
    498  return retval;
    499 }
    500 
    501 /// Insert register contents "s" into the typeahead buffer, so that it will be
    502 /// executed again.
    503 ///
    504 /// @param esc    when true then it is to be taken literally: Escape K_SPECIAL
    505 ///               characters and no remapping.
    506 /// @param colon  add ':' before the line
    507 static int put_in_typebuf(char *s, bool esc, bool colon, int silent)
    508 {
    509  int retval = OK;
    510 
    511  put_reedit_in_typebuf(silent);
    512  if (colon) {
    513    retval = ins_typebuf("\n", REMAP_NONE, 0, true, silent);
    514  }
    515  if (retval == OK) {
    516    char *p;
    517 
    518    if (esc) {
    519      p = vim_strsave_escape_ks(s);
    520    } else {
    521      p = s;
    522    }
    523    if (p == NULL) {
    524      retval = FAIL;
    525    } else {
    526      retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES, 0, true, silent);
    527    }
    528    if (esc) {
    529      xfree(p);
    530    }
    531  }
    532  if (colon && retval == OK) {
    533    retval = ins_typebuf(":", REMAP_NONE, 0, true, silent);
    534  }
    535  return retval;
    536 }
    537 
    538 /// If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
    539 /// used only after other typeahead has been processed.
    540 static void put_reedit_in_typebuf(int silent)
    541 {
    542  uint8_t buf[3];
    543 
    544  if (restart_edit == NUL) {
    545    return;
    546  }
    547 
    548  if (restart_edit == 'V') {
    549    buf[0] = 'g';
    550    buf[1] = 'R';
    551    buf[2] = NUL;
    552  } else {
    553    buf[0] = (uint8_t)(restart_edit == 'I' ? 'i' : restart_edit);
    554    buf[1] = NUL;
    555  }
    556  if (ins_typebuf((char *)buf, REMAP_NONE, 0, true, silent) == OK) {
    557    restart_edit = NUL;
    558  }
    559 }
    560 
    561 /// When executing a register as a series of ex-commands, if the
    562 /// line-continuation character is used for a line, then join it with one or
    563 /// more previous lines. Note that lines are processed backwards starting from
    564 /// the last line in the register.
    565 ///
    566 /// @param lines list of lines in the register
    567 /// @param idx   index of the line starting with \ or "\. Join this line with all the immediate
    568 ///              predecessor lines that start with a \ and the first line that doesn't start
    569 ///              with a \. Lines that start with a comment "\ character are ignored.
    570 /// @returns the concatenated line. The index of the line that should be
    571 ///          processed next is returned in idx.
    572 static char *execreg_line_continuation(String *lines, size_t *idx)
    573 {
    574  size_t cmd_start = *idx;
    575  assert(cmd_start > 0);
    576  const size_t cmd_end = cmd_start;
    577 
    578  garray_T ga;
    579  ga_init(&ga, (int)sizeof(char), 400);
    580 
    581  // search backwards to find the first line of this command.
    582  // Any line not starting with \ or "\ is the start of the
    583  // command.
    584  while (--cmd_start > 0) {
    585    char *p = skipwhite(lines[cmd_start].data);
    586    if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
    587      break;
    588    }
    589  }
    590 
    591  // join all the lines
    592  String *tmp = &lines[cmd_start];
    593  ga_concat_len(&ga, tmp->data, tmp->size);
    594  for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
    595    tmp = &lines[j];
    596    char *p = skipwhite(tmp->data);
    597    if (*p == '\\') {
    598      // Adjust the growsize to the current length to
    599      // speed up concatenating many lines.
    600      if (ga.ga_len > 400) {
    601        ga_set_growsize(&ga, MIN(ga.ga_len, 8000));
    602      }
    603      p++;
    604      ga_concat_len(&ga, p, (size_t)(tmp->data + tmp->size - p));
    605    }
    606  }
    607  ga_append(&ga, NUL);
    608  char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len);
    609  ga_clear(&ga);
    610 
    611  *idx = cmd_start;
    612  return str;
    613 }
    614 
    615 /// Execute a yank register: copy it into the stuff buffer
    616 ///
    617 /// @param colon   insert ':' before each line
    618 /// @param addcr   always add '\n' to end of line
    619 /// @param silent  set "silent" flag in typeahead buffer
    620 ///
    621 /// @return FAIL for failure, OK otherwise
    622 int do_execreg(int regname, int colon, int addcr, int silent)
    623 {
    624  int retval = OK;
    625 
    626  if (regname == '@') {                 // repeat previous one
    627    if (execreg_lastc == NUL) {
    628      emsg(_("E748: No previously used register"));
    629      return FAIL;
    630    }
    631    regname = execreg_lastc;
    632  }
    633  // check for valid regname
    634  if (regname == '%' || regname == '#' || !valid_yank_reg(regname, false)) {
    635    emsg_invreg(regname);
    636    return FAIL;
    637  }
    638  execreg_lastc = regname;
    639 
    640  if (regname == '_') {                 // black hole: don't stuff anything
    641    return OK;
    642  }
    643 
    644  if (regname == ':') {                 // use last command line
    645    if (last_cmdline == NULL) {
    646      emsg(_(e_nolastcmd));
    647      return FAIL;
    648    }
    649    // don't keep the cmdline containing @:
    650    XFREE_CLEAR(new_last_cmdline);
    651    // Escape all control characters with a CTRL-V
    652    char *p = vim_strsave_escaped_ext(last_cmdline,
    653                                      "\001\002\003\004\005\006\007"
    654                                      "\010\011\012\013\014\015\016\017"
    655                                      "\020\021\022\023\024\025\026\027"
    656                                      "\030\031\032\033\034\035\036\037",
    657                                      Ctrl_V, false);
    658    // When in Visual mode "'<,'>" will be prepended to the command.
    659    // Remove it when it's already there.
    660    if (VIsual_active && strncmp(p, "'<,'>", 5) == 0) {
    661      retval = put_in_typebuf(p + 5, true, true, silent);
    662    } else {
    663      retval = put_in_typebuf(p, true, true, silent);
    664    }
    665    xfree(p);
    666  } else if (regname == '=') {
    667    char *p = get_expr_line();
    668    if (p == NULL) {
    669      return FAIL;
    670    }
    671    retval = put_in_typebuf(p, true, colon, silent);
    672    xfree(p);
    673  } else if (regname == '.') {        // use last inserted text
    674    char *p = get_last_insert_save();
    675    if (p == NULL) {
    676      emsg(_(e_noinstext));
    677      return FAIL;
    678    }
    679    retval = put_in_typebuf(p, false, colon, silent);
    680    xfree(p);
    681  } else {
    682    yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
    683    if (reg->y_array == NULL) {
    684      return FAIL;
    685    }
    686 
    687    // Disallow remapping for ":@r".
    688    int remap = colon ? REMAP_NONE : REMAP_YES;
    689 
    690    // Insert lines into typeahead buffer, from last one to first one.
    691    put_reedit_in_typebuf(silent);
    692    for (size_t i = reg->y_size; i-- > 0;) {  // from y_size - 1 to 0 included
    693      // insert NL between lines and after last line if type is kMTLineWise
    694      if (reg->y_type == kMTLineWise || i < reg->y_size - 1 || addcr) {
    695        if (ins_typebuf("\n", remap, 0, true, silent) == FAIL) {
    696          return FAIL;
    697        }
    698      }
    699 
    700      // Handle line-continuation for :@<register>
    701      char *str = reg->y_array[i].data;
    702      bool free_str = false;
    703      if (colon && i > 0) {
    704        char *p = skipwhite(str);
    705        if (*p == '\\' || (p[0] == '"' && p[1] == '\\' && p[2] == ' ')) {
    706          str = execreg_line_continuation(reg->y_array, &i);
    707          free_str = true;
    708        }
    709      }
    710      char *escaped = vim_strsave_escape_ks(str);
    711      if (free_str) {
    712        xfree(str);
    713      }
    714      retval = ins_typebuf(escaped, remap, 0, true, silent);
    715      xfree(escaped);
    716      if (retval == FAIL) {
    717        return FAIL;
    718      }
    719      if (colon
    720          && ins_typebuf(":", remap, 0, true, silent) == FAIL) {
    721        return FAIL;
    722      }
    723    }
    724    reg_executing = regname == 0 ? '"' : regname;  // disable the 'q' command
    725    pending_end_reg_executing = false;
    726  }
    727  return retval;
    728 }
    729 
    730 /// Insert a yank register: copy it into the Read buffer.
    731 /// Used by CTRL-R command and middle mouse button in insert mode.
    732 ///
    733 /// @param literally_arg  insert literally, not as if typed
    734 ///
    735 /// @return FAIL for failure, OK otherwise
    736 int insert_reg(int regname, yankreg_T *reg, bool literally_arg)
    737 {
    738  int retval = OK;
    739  bool allocated;
    740  const bool literally = literally_arg || is_literal_register(regname);
    741 
    742  // It is possible to get into an endless loop by having CTRL-R a in
    743  // register a and then, in insert mode, doing CTRL-R a.
    744  // If you hit CTRL-C, the loop will be broken here.
    745  os_breakcheck();
    746  if (got_int) {
    747    return FAIL;
    748  }
    749 
    750  // check for valid regname
    751  if (regname != NUL && !valid_yank_reg(regname, false)) {
    752    return FAIL;
    753  }
    754 
    755  char *arg;
    756  if (regname == '.') {  // Insert last inserted text.
    757    retval = stuff_inserted(NUL, 1, true);
    758  } else if (get_spec_reg(regname, &arg, &allocated, true)) {
    759    if (arg == NULL) {
    760      return FAIL;
    761    }
    762    stuffescaped(arg, literally);
    763    if (allocated) {
    764      xfree(arg);
    765    }
    766  } else {  // Name or number register.
    767    if (reg == NULL) {
    768      reg = get_yank_register(regname, YREG_PASTE);
    769    }
    770    if (reg->y_array == NULL) {
    771      retval = FAIL;
    772    } else {
    773      for (size_t i = 0; i < reg->y_size; i++) {
    774        if (regname == '-' && reg->y_type == kMTCharWise) {
    775          Direction dir = BACKWARD;
    776          if ((State & REPLACE_FLAG) != 0) {
    777            pos_T curpos;
    778            if (u_save_cursor() == FAIL) {
    779              return FAIL;
    780            }
    781            del_chars(mb_charlen(reg->y_array[0].data), true);
    782            curpos = curwin->w_cursor;
    783            if (oneright() == FAIL) {
    784              // hit end of line, need to put forward (after the current position)
    785              dir = FORWARD;
    786            }
    787            curwin->w_cursor = curpos;
    788          }
    789 
    790          AppendCharToRedobuff(Ctrl_R);
    791          AppendCharToRedobuff(regname);
    792          do_put(regname, NULL, dir, 1, PUT_CURSEND);
    793        } else {
    794          stuffescaped(reg->y_array[i].data, literally);
    795          // Insert a newline between lines and after last line if
    796          // y_type is kMTLineWise.
    797          if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
    798            stuffcharReadbuff('\n');
    799          }
    800        }
    801      }
    802    }
    803  }
    804 
    805  return retval;
    806 }
    807 
    808 /// If "regname" is a special register, return true and store a pointer to its
    809 /// value in "argp".
    810 ///
    811 /// @param allocated  return: true when value was allocated
    812 /// @param errmsg     give error message when failing
    813 ///
    814 /// @return  true if "regname" is a special register,
    815 bool get_spec_reg(int regname, char **argp, bool *allocated, bool errmsg)
    816 {
    817  *argp = NULL;
    818  *allocated = false;
    819  switch (regname) {
    820  case '%':                     // file name
    821    if (errmsg) {
    822      check_fname();            // will give emsg if not set
    823    }
    824    *argp = curbuf->b_fname;
    825    return true;
    826 
    827  case '#':                       // alternate file name
    828    *argp = getaltfname(errmsg);  // may give emsg if not set
    829    return true;
    830 
    831  case '=':                     // result of expression
    832    *argp = get_expr_line();
    833    *allocated = true;
    834    return true;
    835 
    836  case ':':                     // last command line
    837    if (last_cmdline == NULL && errmsg) {
    838      emsg(_(e_nolastcmd));
    839    }
    840    *argp = last_cmdline;
    841    return true;
    842 
    843  case '/':                     // last search-pattern
    844    if (last_search_pat() == NULL && errmsg) {
    845      emsg(_(e_noprevre));
    846    }
    847    *argp = last_search_pat();
    848    return true;
    849 
    850  case '.':                     // last inserted text
    851    *argp = get_last_insert_save();
    852    *allocated = true;
    853    if (*argp == NULL && errmsg) {
    854      emsg(_(e_noinstext));
    855    }
    856    return true;
    857 
    858  case Ctrl_F:                  // Filename under cursor
    859  case Ctrl_P:                  // Path under cursor, expand via "path"
    860    if (!errmsg) {
    861      return false;
    862    }
    863    *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP | (regname == Ctrl_P ? FNAME_EXP : 0),
    864                                1, NULL);
    865    *allocated = true;
    866    return true;
    867 
    868  case Ctrl_W:                  // word under cursor
    869  case Ctrl_A:                  // WORD (mnemonic All) under cursor
    870    if (!errmsg) {
    871      return false;
    872    }
    873    size_t cnt = find_ident_under_cursor(argp, (regname == Ctrl_W
    874                                                ? (FIND_IDENT|FIND_STRING)
    875                                                : FIND_STRING));
    876    *argp = cnt ? xmemdupz(*argp, cnt) : NULL;
    877    *allocated = true;
    878    return true;
    879 
    880  case Ctrl_L:                  // Line under cursor
    881    if (!errmsg) {
    882      return false;
    883    }
    884 
    885    *argp = ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum);
    886    return true;
    887 
    888  case '_':                     // black hole: always empty
    889    *argp = "";
    890    return true;
    891  }
    892 
    893  return false;
    894 }
    895 
    896 /// Paste a yank register into the command line.
    897 /// Only for non-special registers.
    898 /// Used by CTRL-R in command-line mode.
    899 /// insert_reg() can't be used here, because special characters from the
    900 /// register contents will be interpreted as commands.
    901 ///
    902 /// @param regname   Register name.
    903 /// @param literally_arg Insert text literally instead of "as typed".
    904 /// @param remcr     When true, don't add CR characters.
    905 ///
    906 /// @returns FAIL for failure, OK otherwise
    907 bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
    908 {
    909  const bool literally = literally_arg || is_literal_register(regname);
    910 
    911  yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
    912  if (reg->y_array == NULL) {
    913    return FAIL;
    914  }
    915 
    916  for (size_t i = 0; i < reg->y_size; i++) {
    917    cmdline_paste_str(reg->y_array[i].data, literally);
    918 
    919    // Insert ^M between lines, unless `remcr` is true.
    920    if (i < reg->y_size - 1 && !remcr) {
    921      cmdline_paste_str("\r", literally);
    922    }
    923 
    924    // Check for CTRL-C, in case someone tries to paste a few thousand
    925    // lines and gets bored.
    926    os_breakcheck();
    927    if (got_int) {
    928      return FAIL;
    929    }
    930  }
    931  return OK;
    932 }
    933 
    934 /// Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
    935 void shift_delete_registers(bool y_append)
    936 {
    937  free_register(&y_regs[9]);  // free register "9
    938  for (int n = 9; n > 1; n--) {
    939    y_regs[n] = y_regs[n - 1];
    940  }
    941  if (!y_append) {
    942    y_previous = &y_regs[1];
    943  }
    944  y_regs[1].y_array = NULL;  // set register "1 to empty
    945 }
    946 
    947 #if defined(EXITFREE)
    948 void clear_registers(void)
    949 {
    950  for (int i = 0; i < NUM_REGISTERS; i++) {
    951    free_register(&y_regs[i]);
    952  }
    953 }
    954 #endif
    955 
    956 /// Free contents of yankreg `reg`.
    957 /// Called for normal freeing and in case of error.
    958 ///
    959 /// @param reg  must not be NULL (but `reg->y_array` might be)
    960 void free_register(yankreg_T *reg)
    961  FUNC_ATTR_NONNULL_ALL
    962 {
    963  XFREE_CLEAR(reg->additional_data);
    964  if (reg->y_array == NULL) {
    965    return;
    966  }
    967 
    968  for (size_t i = reg->y_size; i-- > 0;) {  // from y_size - 1 to 0 included
    969    API_CLEAR_STRING(reg->y_array[i]);
    970  }
    971  XFREE_CLEAR(reg->y_array);
    972 }
    973 
    974 /// Copy a block range into a register.
    975 ///
    976 /// @param exclude_trailing_space  if true, do not copy trailing whitespaces.
    977 static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
    978                           bool exclude_trailing_space)
    979  FUNC_ATTR_NONNULL_ALL
    980 {
    981  if (exclude_trailing_space) {
    982    bd->endspaces = 0;
    983  }
    984  int size = bd->startspaces + bd->endspaces + bd->textlen;
    985  assert(size >= 0);
    986  char *pnew = xmallocz((size_t)size);
    987  reg->y_array[y_idx].data = pnew;
    988  memset(pnew, ' ', (size_t)bd->startspaces);
    989  pnew += bd->startspaces;
    990  memmove(pnew, bd->textstart, (size_t)bd->textlen);
    991  pnew += bd->textlen;
    992  memset(pnew, ' ', (size_t)bd->endspaces);
    993  pnew += bd->endspaces;
    994  if (exclude_trailing_space) {
    995    int s = bd->textlen + bd->endspaces;
    996 
    997    while (s > 0 && ascii_iswhite(*(bd->textstart + s - 1))) {
    998      s = s - utf_head_off(bd->textstart, bd->textstart + s - 1) - 1;
    999      pnew--;
   1000    }
   1001  }
   1002  *pnew = NUL;
   1003  reg->y_array[y_idx].size = (size_t)(pnew - reg->y_array[y_idx].data);
   1004 }
   1005 
   1006 void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
   1007 {
   1008  yankreg_T newreg;  // new yank register when appending
   1009  MotionType yank_type = oap->motion_type;
   1010  size_t yanklines = (size_t)oap->line_count;
   1011  linenr_T yankendlnum = oap->end.lnum;
   1012  struct block_def bd;
   1013 
   1014  yankreg_T *curr = reg;  // copy of current register
   1015  // append to existing contents
   1016  if (append && reg->y_array != NULL) {
   1017    reg = &newreg;
   1018  } else {
   1019    free_register(reg);  // free previously yanked lines
   1020  }
   1021 
   1022  // If the cursor was in column 1 before and after the movement, and the
   1023  // operator is not inclusive, the yank is always linewise.
   1024  if (oap->motion_type == kMTCharWise
   1025      && oap->start.col == 0
   1026      && !oap->inclusive
   1027      && (!oap->is_VIsual || *p_sel == 'o')
   1028      && oap->end.col == 0
   1029      && yanklines > 1) {
   1030    yank_type = kMTLineWise;
   1031    yankendlnum--;
   1032    yanklines--;
   1033  }
   1034 
   1035  reg->y_size = yanklines;
   1036  reg->y_type = yank_type;  // set the yank register type
   1037  reg->y_width = 0;
   1038  reg->y_array = xcalloc(yanklines, sizeof(String));
   1039  reg->additional_data = NULL;
   1040  reg->timestamp = os_time();
   1041 
   1042  size_t y_idx = 0;  // index in y_array[]
   1043  linenr_T lnum = oap->start.lnum;  // current line number
   1044 
   1045  if (yank_type == kMTBlockWise) {
   1046    // Visual block mode
   1047    reg->y_width = oap->end_vcol - oap->start_vcol;
   1048 
   1049    if (curwin->w_curswant == MAXCOL && reg->y_width > 0) {
   1050      reg->y_width--;
   1051    }
   1052  }
   1053 
   1054  for (; lnum <= yankendlnum; lnum++, y_idx++) {
   1055    switch (reg->y_type) {
   1056    case kMTBlockWise:
   1057      block_prep(oap, &bd, lnum, false);
   1058      yank_copy_line(reg, &bd, y_idx, oap->excl_tr_ws);
   1059      break;
   1060 
   1061    case kMTLineWise:
   1062      reg->y_array[y_idx] = cbuf_to_string(ml_get(lnum), (size_t)ml_get_len(lnum));
   1063      break;
   1064 
   1065    case kMTCharWise:
   1066      charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive);
   1067      // make sure bd.textlen is not longer than the text
   1068      int tmp = (int)strlen(bd.textstart);
   1069      if (tmp < bd.textlen) {
   1070        bd.textlen = tmp;
   1071      }
   1072      yank_copy_line(reg, &bd, y_idx, false);
   1073      break;
   1074 
   1075    // NOTREACHED
   1076    case kMTUnknown:
   1077      abort();
   1078    }
   1079  }
   1080 
   1081  if (curr != reg) {      // append the new block to the old block
   1082    size_t j;
   1083    String *new_ptr = xmalloc(sizeof(String) * (curr->y_size + reg->y_size));
   1084    for (j = 0; j < curr->y_size; j++) {
   1085      new_ptr[j] = curr->y_array[j];
   1086    }
   1087    xfree(curr->y_array);
   1088    curr->y_array = new_ptr;
   1089 
   1090    if (yank_type == kMTLineWise) {
   1091      // kMTLineWise overrides kMTCharWise and kMTBlockWise
   1092      curr->y_type = kMTLineWise;
   1093    }
   1094 
   1095    // Concatenate the last line of the old block with the first line of
   1096    // the new block, unless being Vi compatible.
   1097    if (curr->y_type == kMTCharWise
   1098        && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) {
   1099      char *pnew = xmalloc(curr->y_array[curr->y_size - 1].size
   1100                           + reg->y_array[0].size + 1);
   1101      j--;
   1102      STRCPY(pnew, curr->y_array[j].data);
   1103      STRCPY(pnew + curr->y_array[j].size, reg->y_array[0].data);
   1104      xfree(curr->y_array[j].data);
   1105      curr->y_array[j] = cbuf_as_string(pnew,
   1106                                        curr->y_array[j].size + reg->y_array[0].size);
   1107      j++;
   1108      API_CLEAR_STRING(reg->y_array[0]);
   1109      y_idx = 1;
   1110    } else {
   1111      y_idx = 0;
   1112    }
   1113    while (y_idx < reg->y_size) {
   1114      curr->y_array[j++] = reg->y_array[y_idx++];
   1115    }
   1116    curr->y_size = j;
   1117    xfree(reg->y_array);
   1118  }
   1119 
   1120  if (message) {  // Display message about yank?
   1121    if (yank_type == kMTCharWise && yanklines == 1) {
   1122      yanklines = 0;
   1123    }
   1124    // Some versions of Vi use ">=" here, some don't...
   1125    if (yanklines > (size_t)p_report) {
   1126      char namebuf[100];
   1127 
   1128      if (oap->regname == NUL) {
   1129        *namebuf = NUL;
   1130      } else {
   1131        vim_snprintf(namebuf, sizeof(namebuf), _(" into \"%c"), oap->regname);
   1132      }
   1133 
   1134      // redisplay now, so message is not deleted
   1135      update_topline(curwin);
   1136      if (must_redraw) {
   1137        update_screen();
   1138      }
   1139      if (yank_type == kMTBlockWise) {
   1140        smsg(0, NGETTEXT("block of %" PRId64 " line yanked%s",
   1141                         "block of %" PRId64 " lines yanked%s", yanklines),
   1142             (int64_t)yanklines, namebuf);
   1143      } else {
   1144        smsg(0, NGETTEXT("%" PRId64 " line yanked%s",
   1145                         "%" PRId64 " lines yanked%s", yanklines),
   1146             (int64_t)yanklines, namebuf);
   1147      }
   1148    }
   1149  }
   1150 
   1151  if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) {
   1152    // Set "'[" and "']" marks.
   1153    curbuf->b_op_start = oap->start;
   1154    curbuf->b_op_end = oap->end;
   1155    if (yank_type == kMTLineWise) {
   1156      curbuf->b_op_start.col = 0;
   1157      curbuf->b_op_end.col = MAXCOL;
   1158    }
   1159    if (yank_type != kMTLineWise && !oap->inclusive) {
   1160      // Exclude the end position.
   1161      decl(&curbuf->b_op_end);
   1162    }
   1163  }
   1164 }
   1165 
   1166 /// Format the register type as a string.
   1167 ///
   1168 /// @param reg_type The register type.
   1169 /// @param reg_width The width, only used if "reg_type" is kMTBlockWise.
   1170 /// @param[out] buf Buffer to store formatted string. The allocated size should
   1171 ///                 be at least NUMBUFLEN+2 to always fit the value.
   1172 /// @param buf_len The allocated size of the buffer.
   1173 void format_reg_type(MotionType reg_type, colnr_T reg_width, char *buf, size_t buf_len)
   1174  FUNC_ATTR_NONNULL_ALL
   1175 {
   1176  assert(buf_len > 1);
   1177  switch (reg_type) {
   1178  case kMTLineWise:
   1179    buf[0] = 'V';
   1180    buf[1] = NUL;
   1181    break;
   1182  case kMTCharWise:
   1183    buf[0] = 'v';
   1184    buf[1] = NUL;
   1185    break;
   1186  case kMTBlockWise:
   1187    snprintf(buf, buf_len, CTRL_V_STR "%" PRIdCOLNR, reg_width + 1);
   1188    break;
   1189  case kMTUnknown:
   1190    buf[0] = NUL;
   1191    break;
   1192  }
   1193 }
   1194 
   1195 /// Execute autocommands for TextYankPost.
   1196 ///
   1197 /// @param oap Operator arguments.
   1198 /// @param reg The yank register used.
   1199 void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
   1200  FUNC_ATTR_NONNULL_ALL
   1201 {
   1202  static bool recursive = false;
   1203 
   1204  if (recursive || !has_event(EVENT_TEXTYANKPOST)) {
   1205    // No autocommand was defined, or we yanked from this autocommand.
   1206    return;
   1207  }
   1208 
   1209  recursive = true;
   1210 
   1211  save_v_event_T save_v_event;
   1212  // Set the v:event dictionary with information about the yank.
   1213  dict_T *dict = get_v_event(&save_v_event);
   1214 
   1215  // The yanked text contents.
   1216  list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
   1217  for (size_t i = 0; i < reg->y_size; i++) {
   1218    tv_list_append_string(list, reg->y_array[i].data, (int)reg->y_array[i].size);
   1219  }
   1220  tv_list_set_lock(list, VAR_FIXED);
   1221  tv_dict_add_list(dict, S_LEN("regcontents"), list);
   1222 
   1223  // Register type.
   1224  char buf[NUMBUFLEN + 2];
   1225  format_reg_type(reg->y_type, reg->y_width, buf, ARRAY_SIZE(buf));
   1226  tv_dict_add_str(dict, S_LEN("regtype"), buf);
   1227 
   1228  // Name of requested register, or empty string for unnamed operation.
   1229  buf[0] = (char)oap->regname;
   1230  buf[1] = NUL;
   1231  tv_dict_add_str(dict, S_LEN("regname"), buf);
   1232 
   1233  // Motion type: inclusive or exclusive.
   1234  tv_dict_add_bool(dict, S_LEN("inclusive"),
   1235                   oap->inclusive ? kBoolVarTrue : kBoolVarFalse);
   1236 
   1237  // Kind of operation: yank, delete, change).
   1238  buf[0] = (char)get_op_char(oap->op_type);
   1239  buf[1] = NUL;
   1240  tv_dict_add_str(dict, S_LEN("operator"), buf);
   1241 
   1242  // Selection type: visual or not.
   1243  tv_dict_add_bool(dict, S_LEN("visual"),
   1244                   oap->is_VIsual ? kBoolVarTrue : kBoolVarFalse);
   1245 
   1246  tv_dict_set_keys_readonly(dict);
   1247  textlock++;
   1248  apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, false, curbuf);
   1249  textlock--;
   1250  restore_v_event(dict, &save_v_event);
   1251 
   1252  recursive = false;
   1253 }
   1254 
   1255 /// Yanks the text between "oap->start" and "oap->end" into a yank register.
   1256 /// If we are to append (uppercase register), we first yank into a new yank
   1257 /// register and then concatenate the old and the new one.
   1258 /// Do not call this from a delete operation. Use op_yank_reg() instead.
   1259 ///
   1260 /// @param oap operator arguments
   1261 /// @param message show message when more than `&report` lines are yanked.
   1262 /// @returns whether the operation register was writable.
   1263 bool op_yank(oparg_T *oap, bool message)
   1264  FUNC_ATTR_NONNULL_ALL
   1265 {
   1266  // check for read-only register
   1267  if (oap->regname != 0 && !valid_yank_reg(oap->regname, true)) {
   1268    beep_flush();
   1269    return false;
   1270  }
   1271  if (oap->regname == '_') {
   1272    return true;  // black hole: nothing to do
   1273  }
   1274 
   1275  yankreg_T *reg = get_yank_register(oap->regname, YREG_YANK);
   1276  op_yank_reg(oap, message, reg, is_append_register(oap->regname));
   1277  set_clipboard(oap->regname, reg);
   1278  do_autocmd_textyankpost(oap, reg);
   1279  return true;
   1280 }
   1281 
   1282 /// Put contents of register "regname" into the text.
   1283 /// Caller must check "regname" to be valid!
   1284 ///
   1285 /// @param flags  PUT_FIXINDENT     make indent look nice
   1286 ///               PUT_CURSEND       leave cursor after end of new text
   1287 ///               PUT_LINE          force linewise put (":put")
   1288 ///               PUT_BLOCK_INNER   in block mode, do not add trailing spaces
   1289 /// @param dir    BACKWARD for 'P', FORWARD for 'p'
   1290 void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
   1291 {
   1292  size_t totlen = 0;  // init for gcc
   1293  linenr_T lnum = 0;
   1294  MotionType y_type;
   1295  size_t y_size;
   1296  int y_width = 0;
   1297  colnr_T vcol = 0;
   1298  String *y_array = NULL;
   1299  linenr_T nr_lines = 0;
   1300  bool allocated = false;
   1301  const pos_T orig_start = curbuf->b_op_start;
   1302  const pos_T orig_end = curbuf->b_op_end;
   1303  unsigned cur_ve_flags = get_ve_flags(curwin);
   1304 
   1305  // Remove any preinserted text (issue vim/vim#19329)
   1306  if (ins_compl_preinsert_effect()) {
   1307    ins_compl_delete(false);
   1308  }
   1309 
   1310  curbuf->b_op_start = curwin->w_cursor;        // default for '[ mark
   1311  curbuf->b_op_end = curwin->w_cursor;          // default for '] mark
   1312 
   1313  // Using inserted text works differently, because the register includes
   1314  // special characters (newlines, etc.).
   1315  if (regname == '.' && !reg) {
   1316    bool non_linewise_vis = (VIsual_active && VIsual_mode != 'V');
   1317 
   1318    // PUT_LINE has special handling below which means we use 'i' to start.
   1319    char command_start_char = non_linewise_vis
   1320                              ? 'c'
   1321                              : (flags & PUT_LINE ? 'i' : (dir == FORWARD ? 'a' : 'i'));
   1322 
   1323    // To avoid 'autoindent' on linewise puts, create a new line with `:put _`.
   1324    if (flags & PUT_LINE) {
   1325      do_put('_', NULL, dir, 1, PUT_LINE);
   1326    }
   1327 
   1328    // If given a count when putting linewise, we stuff the readbuf with the
   1329    // dot register 'count' times split by newlines.
   1330    if (flags & PUT_LINE) {
   1331      stuffcharReadbuff(command_start_char);
   1332      for (; count > 0; count--) {
   1333        stuff_inserted(NUL, 1, count != 1);
   1334        if (count != 1) {
   1335          // To avoid 'autoindent' affecting the text, use Ctrl_U to remove any
   1336          // whitespace. Can't just insert Ctrl_U into readbuf1, this would go
   1337          // back to the previous line in the case of 'noautoindent' and
   1338          // 'backspace' includes "eol". So we insert a dummy space for Ctrl_U
   1339          // to consume.
   1340          stuffReadbuff("\n ");
   1341          stuffcharReadbuff(Ctrl_U);
   1342        }
   1343      }
   1344    } else {
   1345      stuff_inserted(command_start_char, count, false);
   1346    }
   1347 
   1348    // Putting the text is done later, so can't move the cursor to the next
   1349    // character.  Simulate it with motion commands after the insert.
   1350    if (flags & PUT_CURSEND) {
   1351      if (flags & PUT_LINE) {
   1352        stuffReadbuff("j0");
   1353      } else {
   1354        // Avoid ringing the bell from attempting to move into the space after
   1355        // the current line. We can stuff the readbuffer with "l" if:
   1356        // 1) 'virtualedit' is "all" or "onemore"
   1357        // 2) We are not at the end of the line
   1358        // 3) We are not  (one past the end of the line && on the last line)
   1359        //    This allows a visual put over a selection one past the end of the
   1360        //    line joining the current line with the one below.
   1361 
   1362        // curwin->w_cursor.col marks the byte position of the cursor in the
   1363        // currunt line. It increases up to a max of
   1364        // strlen(ml_get(curwin->w_cursor.lnum)). With 'virtualedit' and the
   1365        // cursor past the end of the line, curwin->w_cursor.coladd is
   1366        // incremented instead of curwin->w_cursor.col.
   1367        char *cursor_pos = get_cursor_pos_ptr();
   1368        bool one_past_line = (*cursor_pos == NUL);
   1369        bool eol = false;
   1370        if (!one_past_line) {
   1371          eol = (*(cursor_pos + utfc_ptr2len(cursor_pos)) == NUL);
   1372        }
   1373 
   1374        bool ve_allows = (cur_ve_flags == kOptVeFlagAll || cur_ve_flags == kOptVeFlagOnemore);
   1375        bool eof = curbuf->b_ml.ml_line_count == curwin->w_cursor.lnum
   1376                   && one_past_line;
   1377        if (ve_allows || !(eol || eof)) {
   1378          stuffcharReadbuff('l');
   1379        }
   1380      }
   1381    } else if (flags & PUT_LINE) {
   1382      stuffReadbuff("g'[");
   1383    }
   1384 
   1385    // So the 'u' command restores cursor position after ".p, save the cursor
   1386    // position now (though not saving any text).
   1387    if (command_start_char == 'a') {
   1388      if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL) {
   1389        return;
   1390      }
   1391    }
   1392    return;
   1393  }
   1394 
   1395  // For special registers '%' (file name), '#' (alternate file name) and
   1396  // ':' (last command line), etc. we have to create a fake yank register.
   1397  String insert_string = STRING_INIT;
   1398  if (!reg && get_spec_reg(regname, &insert_string.data, &allocated, true)) {
   1399    if (insert_string.data == NULL) {
   1400      return;
   1401    }
   1402  }
   1403 
   1404  if (!curbuf->terminal) {
   1405    // Autocommands may be executed when saving lines for undo.  This might
   1406    // make y_array invalid, so we start undo now to avoid that.
   1407    if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL) {
   1408      return;
   1409    }
   1410  }
   1411 
   1412  if (insert_string.data != NULL) {
   1413    insert_string.size = strlen(insert_string.data);
   1414    y_type = kMTCharWise;
   1415    if (regname == '=') {
   1416      // For the = register we need to split the string at NL
   1417      // characters.
   1418      // Loop twice: count the number of lines and save them.
   1419      while (true) {
   1420        y_size = 0;
   1421        char *ptr = insert_string.data;
   1422        size_t ptrlen = insert_string.size;
   1423        while (ptr != NULL) {
   1424          if (y_array != NULL) {
   1425            y_array[y_size].data = ptr;
   1426          }
   1427          y_size++;
   1428          char *tmp = vim_strchr(ptr, '\n');
   1429          if (tmp == NULL) {
   1430            if (y_array != NULL) {
   1431              y_array[y_size - 1].size = ptrlen;
   1432            }
   1433          } else {
   1434            if (y_array != NULL) {
   1435              *tmp = NUL;
   1436              y_array[y_size - 1].size = (size_t)(tmp - ptr);
   1437              ptrlen -= y_array[y_size - 1].size + 1;
   1438            }
   1439            tmp++;
   1440            // A trailing '\n' makes the register linewise.
   1441            if (*tmp == NUL) {
   1442              y_type = kMTLineWise;
   1443              break;
   1444            }
   1445          }
   1446          ptr = tmp;
   1447        }
   1448        if (y_array != NULL) {
   1449          break;
   1450        }
   1451        y_array = xmalloc(y_size * sizeof(String));
   1452      }
   1453    } else {
   1454      y_size = 1;               // use fake one-line yank register
   1455      y_array = &insert_string;
   1456    }
   1457  } else {
   1458    // in case of replacing visually selected text
   1459    // the yankreg might already have been saved to avoid
   1460    // just restoring the deleted text.
   1461    if (reg == NULL) {
   1462      reg = get_yank_register(regname, YREG_PASTE);
   1463    }
   1464 
   1465    y_type = reg->y_type;
   1466    y_width = reg->y_width;
   1467    y_size = reg->y_size;
   1468    y_array = reg->y_array;
   1469  }
   1470 
   1471  if (curbuf->terminal) {
   1472    terminal_paste(count, y_array, y_size);
   1473    return;
   1474  }
   1475 
   1476  colnr_T split_pos = 0;
   1477  if (y_type == kMTLineWise) {
   1478    if (flags & PUT_LINE_SPLIT) {
   1479      // "p" or "P" in Visual mode: split the lines to put the text in
   1480      // between.
   1481      if (u_save_cursor() == FAIL) {
   1482        goto end;
   1483      }
   1484      char *curline = get_cursor_line_ptr();
   1485      char *p = get_cursor_pos_ptr();
   1486      char *const p_orig = p;
   1487      const size_t plen = (size_t)get_cursor_pos_len();
   1488      if (dir == FORWARD && *p != NUL) {
   1489        MB_PTR_ADV(p);
   1490      }
   1491      // we need this later for the correct extmark_splice() event
   1492      split_pos = (colnr_T)(p - curline);
   1493 
   1494      char *ptr = xmemdupz(p, plen - (size_t)(p - p_orig));
   1495      ml_append(curwin->w_cursor.lnum, ptr, 0, false);
   1496      xfree(ptr);
   1497 
   1498      ptr = xmemdupz(get_cursor_line_ptr(), (size_t)split_pos);
   1499      ml_replace(curwin->w_cursor.lnum, ptr, false);
   1500      nr_lines++;
   1501      dir = FORWARD;
   1502 
   1503      buf_updates_send_changes(curbuf, curwin->w_cursor.lnum, 1, 1);
   1504    }
   1505    if (flags & PUT_LINE_FORWARD) {
   1506      // Must be "p" for a Visual block, put lines below the block.
   1507      curwin->w_cursor = curbuf->b_visual.vi_end;
   1508      dir = FORWARD;
   1509    }
   1510    curbuf->b_op_start = curwin->w_cursor;      // default for '[ mark
   1511    curbuf->b_op_end = curwin->w_cursor;        // default for '] mark
   1512  }
   1513 
   1514  if (flags & PUT_LINE) {  // :put command or "p" in Visual line mode.
   1515    y_type = kMTLineWise;
   1516  }
   1517 
   1518  if (y_size == 0 || y_array == NULL) {
   1519    semsg(_("E353: Nothing in register %s"),
   1520          regname == 0 ? "\"" : transchar(regname));
   1521    goto end;
   1522  }
   1523 
   1524  if (y_type == kMTBlockWise) {
   1525    lnum = curwin->w_cursor.lnum + (linenr_T)y_size + 1;
   1526    lnum = MIN(lnum, curbuf->b_ml.ml_line_count + 1);
   1527    if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL) {
   1528      goto end;
   1529    }
   1530  } else if (y_type == kMTLineWise) {
   1531    lnum = curwin->w_cursor.lnum;
   1532    // Correct line number for closed fold.  Don't move the cursor yet,
   1533    // u_save() uses it.
   1534    if (dir == BACKWARD) {
   1535      hasFolding(curwin, lnum, &lnum, NULL);
   1536    } else {
   1537      hasFolding(curwin, lnum, NULL, &lnum);
   1538    }
   1539    if (dir == FORWARD) {
   1540      lnum++;
   1541    }
   1542    // In an empty buffer the empty line is going to be replaced, include
   1543    // it in the saved lines.
   1544    if ((buf_is_empty(curbuf)
   1545         ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL) {
   1546      goto end;
   1547    }
   1548    if (dir == FORWARD) {
   1549      curwin->w_cursor.lnum = lnum - 1;
   1550    } else {
   1551      curwin->w_cursor.lnum = lnum;
   1552    }
   1553    curbuf->b_op_start = curwin->w_cursor;      // for mark_adjust()
   1554  } else if (u_save_cursor() == FAIL) {
   1555    goto end;
   1556  }
   1557 
   1558  if (cur_ve_flags == kOptVeFlagAll && y_type == kMTCharWise) {
   1559    if (gchar_cursor() == TAB) {
   1560      int viscol = getviscol();
   1561      OptInt ts = curbuf->b_p_ts;
   1562      // Don't need to insert spaces when "p" on the last position of a
   1563      // tab or "P" on the first position.
   1564      if (dir == FORWARD
   1565          ? tabstop_padding(viscol, ts, curbuf->b_p_vts_array) != 1
   1566          : curwin->w_cursor.coladd > 0) {
   1567        coladvance_force(viscol);
   1568      } else {
   1569        curwin->w_cursor.coladd = 0;
   1570      }
   1571    } else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL) {
   1572      coladvance_force(getviscol() + (dir == FORWARD));
   1573    }
   1574  }
   1575 
   1576  lnum = curwin->w_cursor.lnum;
   1577  colnr_T col = curwin->w_cursor.col;
   1578 
   1579  // Block mode
   1580  if (y_type == kMTBlockWise) {
   1581    int incr = 0;
   1582    struct block_def bd;
   1583    int c = gchar_cursor();
   1584    colnr_T endcol2 = 0;
   1585 
   1586    if (dir == FORWARD && c != NUL) {
   1587      if (cur_ve_flags == kOptVeFlagAll) {
   1588        getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
   1589      } else {
   1590        getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
   1591      }
   1592 
   1593      // move to start of next multi-byte character
   1594      curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr());
   1595      col++;
   1596    } else {
   1597      getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
   1598    }
   1599 
   1600    col += curwin->w_cursor.coladd;
   1601    if (cur_ve_flags == kOptVeFlagAll
   1602        && (curwin->w_cursor.coladd > 0 || endcol2 == curwin->w_cursor.col)) {
   1603      if (dir == FORWARD && c == NUL) {
   1604        col++;
   1605      }
   1606      if (dir != FORWARD && c != NUL && curwin->w_cursor.coladd > 0) {
   1607        curwin->w_cursor.col++;
   1608      }
   1609      if (c == TAB) {
   1610        if (dir == BACKWARD && curwin->w_cursor.col) {
   1611          curwin->w_cursor.col--;
   1612        }
   1613        if (dir == FORWARD && col - 1 == endcol2) {
   1614          curwin->w_cursor.col++;
   1615        }
   1616      }
   1617    }
   1618    curwin->w_cursor.coladd = 0;
   1619    bd.textcol = 0;
   1620    for (size_t i = 0; i < y_size; i++) {
   1621      int spaces = 0;
   1622      char shortline;
   1623      // can just be 0 or 1, needed for blockwise paste beyond the current
   1624      // buffer end
   1625      int lines_appended = 0;
   1626 
   1627      bd.startspaces = 0;
   1628      bd.endspaces = 0;
   1629      vcol = 0;
   1630      int delcount = 0;
   1631 
   1632      // add a new line
   1633      if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
   1634        if (ml_append(curbuf->b_ml.ml_line_count, "", 1, false) == FAIL) {
   1635          break;
   1636        }
   1637        nr_lines++;
   1638        lines_appended = 1;
   1639      }
   1640      // get the old line and advance to the position to insert at
   1641      char *oldp = get_cursor_line_ptr();
   1642      colnr_T oldlen = get_cursor_line_len();
   1643 
   1644      CharsizeArg csarg;
   1645      CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, oldp);
   1646      StrCharInfo ci = utf_ptr2StrCharInfo(oldp);
   1647      vcol = 0;
   1648      while (vcol < col && *ci.ptr != NUL) {
   1649        incr = win_charsize(cstype, vcol, ci.ptr, ci.chr.value, &csarg).width;
   1650        vcol += incr;
   1651        ci = utfc_next(ci);
   1652      }
   1653      char *ptr = ci.ptr;
   1654      bd.textcol = (colnr_T)(ptr - oldp);
   1655 
   1656      shortline = (vcol < col) || (vcol == col && !*ptr);
   1657 
   1658      if (vcol < col) {     // line too short, pad with spaces
   1659        bd.startspaces = col - vcol;
   1660      } else if (vcol > col) {
   1661        bd.endspaces = vcol - col;
   1662        bd.startspaces = incr - bd.endspaces;
   1663        bd.textcol--;
   1664        delcount = 1;
   1665        bd.textcol -= utf_head_off(oldp, oldp + bd.textcol);
   1666        if (oldp[bd.textcol] != TAB) {
   1667          // Only a Tab can be split into spaces.  Other
   1668          // characters will have to be moved to after the
   1669          // block, causing misalignment.
   1670          delcount = 0;
   1671          bd.endspaces = 0;
   1672        }
   1673      }
   1674 
   1675      const int yanklen = (int)y_array[i].size;
   1676 
   1677      if ((flags & PUT_BLOCK_INNER) == 0) {
   1678        // calculate number of spaces required to fill right side of block
   1679        spaces = y_width + 1;
   1680 
   1681        cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i].data);
   1682        ci = utf_ptr2StrCharInfo(y_array[i].data);
   1683        while (*ci.ptr != NUL) {
   1684          spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width;
   1685          ci = utfc_next(ci);
   1686        }
   1687        spaces = MAX(spaces, 0);
   1688      }
   1689 
   1690      // Insert the new text.
   1691      // First check for multiplication overflow.
   1692      if (yanklen + spaces != 0
   1693          && count > ((INT_MAX - (bd.startspaces + bd.endspaces)) / (yanklen + spaces))) {
   1694        emsg(_(e_resulting_text_too_long));
   1695        break;
   1696      }
   1697 
   1698      totlen = (size_t)count * (size_t)(yanklen + spaces) + (size_t)bd.startspaces +
   1699               (size_t)bd.endspaces;
   1700      char *newp = xmalloc(totlen + (size_t)oldlen + 1);
   1701 
   1702      // copy part up to cursor to new line
   1703      ptr = newp;
   1704      memmove(ptr, oldp, (size_t)bd.textcol);
   1705      ptr += bd.textcol;
   1706 
   1707      // may insert some spaces before the new text
   1708      memset(ptr, ' ', (size_t)bd.startspaces);
   1709      ptr += bd.startspaces;
   1710 
   1711      // insert the new text
   1712      for (int j = 0; j < count; j++) {
   1713        memmove(ptr, y_array[i].data, (size_t)yanklen);
   1714        ptr += yanklen;
   1715 
   1716        // insert block's trailing spaces only if there's text behind
   1717        if ((j < count - 1 || !shortline) && spaces > 0) {
   1718          memset(ptr, ' ', (size_t)spaces);
   1719          ptr += spaces;
   1720        } else {
   1721          totlen -= (size_t)spaces;  // didn't use these spaces
   1722        }
   1723      }
   1724 
   1725      // may insert some spaces after the new text
   1726      memset(ptr, ' ', (size_t)bd.endspaces);
   1727      ptr += bd.endspaces;
   1728 
   1729      // move the text after the cursor to the end of the line.
   1730      int columns = oldlen - bd.textcol - delcount + 1;
   1731      assert(columns >= 0);
   1732      memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns);
   1733      ml_replace(curwin->w_cursor.lnum, newp, false);
   1734      extmark_splice_cols(curbuf, (int)curwin->w_cursor.lnum - 1, bd.textcol,
   1735                          delcount, (int)totlen + lines_appended, kExtmarkUndo);
   1736 
   1737      curwin->w_cursor.lnum++;
   1738      if (i == 0) {
   1739        curwin->w_cursor.col += bd.startspaces;
   1740      }
   1741    }
   1742 
   1743    changed_lines(curbuf, lnum, 0, curbuf->b_op_start.lnum + (linenr_T)y_size
   1744                  - nr_lines, nr_lines, true);
   1745 
   1746    // Set '[ mark.
   1747    curbuf->b_op_start = curwin->w_cursor;
   1748    curbuf->b_op_start.lnum = lnum;
   1749 
   1750    // adjust '] mark
   1751    curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
   1752    curbuf->b_op_end.col = MAX(bd.textcol + (colnr_T)totlen - 1, 0);
   1753    curbuf->b_op_end.coladd = 0;
   1754    if (flags & PUT_CURSEND) {
   1755      curwin->w_cursor = curbuf->b_op_end;
   1756      curwin->w_cursor.col++;
   1757 
   1758      // in Insert mode we might be after the NUL, correct for that
   1759      colnr_T len = get_cursor_line_len();
   1760      curwin->w_cursor.col = MIN(curwin->w_cursor.col, len);
   1761    } else {
   1762      curwin->w_cursor.lnum = lnum;
   1763    }
   1764  } else {
   1765    const int yanklen = (int)y_array[0].size;
   1766 
   1767    // Character or Line mode
   1768    if (y_type == kMTCharWise) {
   1769      // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next
   1770      // char
   1771      if (dir == FORWARD && gchar_cursor() != NUL) {
   1772        int bytelen = utfc_ptr2len(get_cursor_pos_ptr());
   1773 
   1774        // put it on the next of the multi-byte character.
   1775        col += bytelen;
   1776        if (yanklen) {
   1777          curwin->w_cursor.col += bytelen;
   1778          curbuf->b_op_end.col += bytelen;
   1779        }
   1780      }
   1781      curbuf->b_op_start = curwin->w_cursor;
   1782    } else if (dir == BACKWARD) {
   1783      // Line mode: BACKWARD is the same as FORWARD on the previous line
   1784      lnum--;
   1785    }
   1786    pos_T new_cursor = curwin->w_cursor;
   1787 
   1788    // simple case: insert into one line at a time
   1789    if (y_type == kMTCharWise && y_size == 1) {
   1790      linenr_T end_lnum = 0;  // init for gcc
   1791      linenr_T start_lnum = lnum;
   1792      int first_byte_off = 0;
   1793 
   1794      if (VIsual_active) {
   1795        end_lnum = MAX(curbuf->b_visual.vi_end.lnum, curbuf->b_visual.vi_start.lnum);
   1796        if (end_lnum > start_lnum) {
   1797          // "col" is valid for the first line, in following lines
   1798          // the virtual column needs to be used.  Matters for
   1799          // multi-byte characters.
   1800          pos_T pos = {
   1801            .lnum = lnum,
   1802            .col = col,
   1803            .coladd = 0,
   1804          };
   1805          getvcol(curwin, &pos, NULL, &vcol, NULL);
   1806        }
   1807      }
   1808 
   1809      if (count == 0 || yanklen == 0) {
   1810        if (VIsual_active) {
   1811          lnum = end_lnum;
   1812        }
   1813      } else if (count > INT_MAX / yanklen) {
   1814        // multiplication overflow
   1815        emsg(_(e_resulting_text_too_long));
   1816      } else {
   1817        totlen = (size_t)count * (size_t)yanklen;
   1818        do {
   1819          char *oldp = ml_get(lnum);
   1820          colnr_T oldlen = ml_get_len(lnum);
   1821          if (lnum > start_lnum) {
   1822            pos_T pos = {
   1823              .lnum = lnum,
   1824            };
   1825            if (getvpos(curwin, &pos, vcol) == OK) {
   1826              col = pos.col;
   1827            } else {
   1828              col = MAXCOL;
   1829            }
   1830          }
   1831          if (VIsual_active && col > oldlen) {
   1832            lnum++;
   1833            continue;
   1834          }
   1835          char *newp = xmalloc(totlen + (size_t)oldlen + 1);
   1836          memmove(newp, oldp, (size_t)col);
   1837          char *ptr = newp + col;
   1838          for (size_t i = 0; i < (size_t)count; i++) {
   1839            memmove(ptr, y_array[0].data, (size_t)yanklen);
   1840            ptr += yanklen;
   1841          }
   1842          memmove(ptr, oldp + col, (size_t)(oldlen - col) + 1);  // +1 for NUL
   1843          ml_replace(lnum, newp, false);
   1844 
   1845          // compute the byte offset for the last character
   1846          first_byte_off = utf_head_off(newp, ptr - 1);
   1847 
   1848          // Place cursor on last putted char.
   1849          if (lnum == curwin->w_cursor.lnum) {
   1850            // make sure curwin->w_virtcol is updated
   1851            changed_cline_bef_curs(curwin);
   1852            invalidate_botline_win(curwin);
   1853            curwin->w_cursor.col += (colnr_T)(totlen - 1);
   1854          }
   1855          changed_bytes(lnum, col);
   1856          extmark_splice_cols(curbuf, (int)lnum - 1, col,
   1857                              0, (int)totlen, kExtmarkUndo);
   1858          if (VIsual_active) {
   1859            lnum++;
   1860          }
   1861        } while (VIsual_active && lnum <= end_lnum);
   1862 
   1863        if (VIsual_active) {  // reset lnum to the last visual line
   1864          lnum--;
   1865        }
   1866      }
   1867 
   1868      // put '] at the first byte of the last character
   1869      curbuf->b_op_end = curwin->w_cursor;
   1870      curbuf->b_op_end.col -= first_byte_off;
   1871 
   1872      // For "CTRL-O p" in Insert mode, put cursor after last char
   1873      if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND))) {
   1874        curwin->w_cursor.col++;
   1875      } else {
   1876        curwin->w_cursor.col -= first_byte_off;
   1877      }
   1878    } else {
   1879      linenr_T new_lnum = new_cursor.lnum;
   1880      int indent;
   1881      int orig_indent = 0;
   1882      int indent_diff = 0;        // init for gcc
   1883      bool first_indent = true;
   1884      int lendiff = 0;
   1885 
   1886      if (flags & PUT_FIXINDENT) {
   1887        orig_indent = get_indent();
   1888      }
   1889 
   1890      // Insert at least one line.  When y_type is kMTCharWise, break the first
   1891      // line in two.
   1892      for (int cnt = 1; cnt <= count; cnt++) {
   1893        size_t i = 0;
   1894        if (y_type == kMTCharWise) {
   1895          // Split the current line in two at the insert position.
   1896          // First insert y_array[size - 1] in front of second line.
   1897          // Then append y_array[0] to first line.
   1898          lnum = new_cursor.lnum;
   1899          char *ptr = ml_get(lnum) + col;
   1900          size_t ptrlen = (size_t)ml_get_len(lnum) - (size_t)col;
   1901          totlen = y_array[y_size - 1].size;
   1902          char *newp = xmalloc(ptrlen + totlen + 1);
   1903          STRCPY(newp, y_array[y_size - 1].data);
   1904          STRCPY(newp + totlen, ptr);
   1905          // insert second line
   1906          ml_append(lnum, newp, 0, false);
   1907          new_lnum++;
   1908          xfree(newp);
   1909 
   1910          char *oldp = ml_get(lnum);
   1911          newp = xmalloc((size_t)col + (size_t)yanklen + 1);
   1912          // copy first part of line
   1913          memmove(newp, oldp, (size_t)col);
   1914          // append to first line
   1915          memmove(newp + col, y_array[0].data, (size_t)yanklen + 1);
   1916          ml_replace(lnum, newp, false);
   1917 
   1918          curwin->w_cursor.lnum = lnum;
   1919          i = 1;
   1920        }
   1921 
   1922        for (; i < y_size; i++) {
   1923          if ((y_type != kMTCharWise || i < y_size - 1)) {
   1924            if (ml_append(lnum, y_array[i].data, 0, false) == FAIL) {
   1925              goto error;
   1926            }
   1927            new_lnum++;
   1928          }
   1929          lnum++;
   1930          nr_lines++;
   1931          if (flags & PUT_FIXINDENT) {
   1932            pos_T old_pos = curwin->w_cursor;
   1933            curwin->w_cursor.lnum = lnum;
   1934            char *ptr = ml_get(lnum);
   1935            if (cnt == count && i == y_size - 1) {
   1936              lendiff = ml_get_len(lnum);
   1937            }
   1938            if (*ptr == '#' && preprocs_left()) {
   1939              indent = 0;                   // Leave # lines at start
   1940            } else if (*ptr == NUL) {
   1941              indent = 0;                   // Ignore empty lines
   1942            } else if (first_indent) {
   1943              indent_diff = orig_indent - get_indent();
   1944              indent = orig_indent;
   1945              first_indent = false;
   1946            } else if ((indent = get_indent() + indent_diff) < 0) {
   1947              indent = 0;
   1948            }
   1949            set_indent(indent, SIN_NOMARK);
   1950            curwin->w_cursor = old_pos;
   1951            // remember how many chars were removed
   1952            if (cnt == count && i == y_size - 1) {
   1953              lendiff -= ml_get_len(lnum);
   1954            }
   1955          }
   1956        }
   1957 
   1958        bcount_t totsize = 0;
   1959        int lastsize = 0;
   1960        if (y_type == kMTCharWise
   1961            || (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) {
   1962          for (i = 0; i < y_size - 1; i++) {
   1963            totsize += (bcount_t)y_array[i].size + 1;
   1964          }
   1965          lastsize = (int)y_array[y_size - 1].size;
   1966          totsize += lastsize;
   1967        }
   1968        if (y_type == kMTCharWise) {
   1969          extmark_splice(curbuf, (int)new_cursor.lnum - 1, col, 0, 0, 0,
   1970                         (int)y_size - 1, lastsize, totsize,
   1971                         kExtmarkUndo);
   1972        } else if (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT)) {
   1973          // Account for last pasted NL + last NL
   1974          extmark_splice(curbuf, (int)new_cursor.lnum - 1, split_pos, 0, 0, 0,
   1975                         (int)y_size + 1, 0, totsize + 2, kExtmarkUndo);
   1976        }
   1977 
   1978        if (cnt == 1) {
   1979          new_lnum = lnum;
   1980        }
   1981      }
   1982 
   1983 error:
   1984      // Adjust marks.
   1985      if (y_type == kMTLineWise) {
   1986        curbuf->b_op_start.col = 0;
   1987        if (dir == FORWARD) {
   1988          curbuf->b_op_start.lnum++;
   1989        }
   1990      }
   1991 
   1992      ExtmarkOp kind = (y_type == kMTLineWise && !(flags & PUT_LINE_SPLIT))
   1993                       ? kExtmarkUndo : kExtmarkNOOP;
   1994      mark_adjust(curbuf->b_op_start.lnum + (y_type == kMTCharWise),
   1995                  (linenr_T)MAXLNUM, nr_lines, 0, kind);
   1996 
   1997      // note changed text for displaying and folding
   1998      if (y_type == kMTCharWise) {
   1999        changed_lines(curbuf, curwin->w_cursor.lnum, col,
   2000                      curwin->w_cursor.lnum + 1, nr_lines, true);
   2001      } else {
   2002        changed_lines(curbuf, curbuf->b_op_start.lnum, 0,
   2003                      curbuf->b_op_start.lnum, nr_lines, true);
   2004      }
   2005 
   2006      // Put the '] mark on the first byte of the last inserted character.
   2007      // Correct the length for change in indent.
   2008      curbuf->b_op_end.lnum = new_lnum;
   2009      col = MAX(0, (colnr_T)y_array[y_size - 1].size - lendiff);
   2010      if (col > 1) {
   2011        curbuf->b_op_end.col = col - 1;
   2012        if (y_array[y_size - 1].size > 0) {
   2013          curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1].data,
   2014                                               y_array[y_size - 1].data
   2015                                               + y_array[y_size - 1].size - 1);
   2016        }
   2017      } else {
   2018        curbuf->b_op_end.col = 0;
   2019      }
   2020 
   2021      if (flags & PUT_CURSLINE) {
   2022        // ":put": put cursor on last inserted line
   2023        curwin->w_cursor.lnum = lnum;
   2024        beginline(BL_WHITE | BL_FIX);
   2025      } else if (flags & PUT_CURSEND) {
   2026        // put cursor after inserted text
   2027        if (y_type == kMTLineWise) {
   2028          if (lnum >= curbuf->b_ml.ml_line_count) {
   2029            curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
   2030          } else {
   2031            curwin->w_cursor.lnum = lnum + 1;
   2032          }
   2033          curwin->w_cursor.col = 0;
   2034        } else {
   2035          curwin->w_cursor.lnum = new_lnum;
   2036          curwin->w_cursor.col = col;
   2037          curbuf->b_op_end = curwin->w_cursor;
   2038          if (col > 1) {
   2039            curbuf->b_op_end.col = col - 1;
   2040          }
   2041        }
   2042      } else if (y_type == kMTLineWise) {
   2043        // put cursor on first non-blank in first inserted line
   2044        curwin->w_cursor.col = 0;
   2045        if (dir == FORWARD) {
   2046          curwin->w_cursor.lnum++;
   2047        }
   2048        beginline(BL_WHITE | BL_FIX);
   2049      } else {  // put cursor on first inserted character
   2050        curwin->w_cursor = new_cursor;
   2051      }
   2052    }
   2053  }
   2054 
   2055  msgmore(nr_lines);
   2056  curwin->w_set_curswant = true;
   2057 
   2058  // Make sure the cursor is not after the NUL.
   2059  int len = get_cursor_line_len();
   2060  if (curwin->w_cursor.col > len) {
   2061    if (cur_ve_flags == kOptVeFlagAll) {
   2062      curwin->w_cursor.coladd = curwin->w_cursor.col - len;
   2063    }
   2064    curwin->w_cursor.col = len;
   2065  }
   2066 
   2067 end:
   2068  if (cmdmod.cmod_flags & CMOD_LOCKMARKS) {
   2069    curbuf->b_op_start = orig_start;
   2070    curbuf->b_op_end = orig_end;
   2071  }
   2072  if (allocated) {
   2073    xfree(insert_string.data);
   2074  }
   2075  if (regname == '=') {
   2076    xfree(y_array);
   2077  }
   2078 
   2079  VIsual_active = false;
   2080 
   2081  // If the cursor is past the end of the line put it at the end.
   2082  adjust_cursor_eol();
   2083 }
   2084 
   2085 /// display a string for do_dis()
   2086 /// truncate at end of screen line
   2087 ///
   2088 /// @param skip_esc  if true, ignore trailing ESC
   2089 static void dis_msg(const char *p, bool skip_esc)
   2090  FUNC_ATTR_NONNULL_ALL
   2091 {
   2092  int n = Columns - 6;
   2093  while (*p != NUL
   2094         && !(*p == ESC && skip_esc && *(p + 1) == NUL)
   2095         && (n -= ptr2cells(p)) >= 0) {
   2096    int l;
   2097    if ((l = utfc_ptr2len(p)) > 1) {
   2098      msg_outtrans_len(p, l, 0, false);
   2099      p += l;
   2100    } else {
   2101      msg_outtrans_len(p++, 1, 0, false);
   2102    }
   2103  }
   2104  os_breakcheck();
   2105 }
   2106 
   2107 /// ":dis" and ":registers": Display the contents of the yank registers.
   2108 void ex_display(exarg_T *eap)
   2109 {
   2110  char *p;
   2111  yankreg_T *yb;
   2112  char *arg = eap->arg;
   2113  int type;
   2114 
   2115  if (arg != NULL && *arg == NUL) {
   2116    arg = NULL;
   2117  }
   2118  int hl_id = HLF_8;
   2119 
   2120  msg_ext_set_kind("list_cmd");
   2121  msg_ext_skip_flush = true;
   2122  // Highlight title
   2123  msg_puts_title(_("\nType Name Content"));
   2124  for (int i = -1; i < NUM_REGISTERS && !got_int; i++) {
   2125    int name = get_register_name(i);
   2126    if (arg != NULL && vim_strchr(arg, name) == NULL) {
   2127      continue;             // did not ask for this register
   2128    }
   2129 
   2130    switch (get_reg_type(name, NULL)) {
   2131    case kMTLineWise:
   2132      type = 'l'; break;
   2133    case kMTCharWise:
   2134      type = 'c'; break;
   2135    default:
   2136      type = 'b'; break;
   2137    }
   2138 
   2139    if (i == -1) {
   2140      if (y_previous != NULL) {
   2141        yb = y_previous;
   2142      } else {
   2143        yb = &(y_regs[0]);
   2144      }
   2145    } else {
   2146      yb = &(y_regs[i]);
   2147    }
   2148 
   2149    get_clipboard(name, &yb, true);
   2150 
   2151    if (name == mb_tolower(redir_reg)
   2152        || (redir_reg == '"' && yb == y_previous)) {
   2153      continue;  // do not list register being written to, the
   2154                 // pointer can be freed
   2155    }
   2156 
   2157    if (yb->y_array != NULL) {
   2158      bool do_show = false;
   2159 
   2160      for (size_t j = 0; !do_show && j < yb->y_size; j++) {
   2161        do_show = !message_filtered(yb->y_array[j].data);
   2162      }
   2163 
   2164      if (do_show || yb->y_size == 0) {
   2165        msg_putchar('\n');
   2166        msg_puts("  ");
   2167        msg_putchar(type);
   2168        msg_puts("  ");
   2169        msg_putchar('"');
   2170        msg_putchar(name);
   2171        msg_puts("   ");
   2172 
   2173        int n = Columns - 11;
   2174        for (size_t j = 0; j < yb->y_size && n > 1; j++) {
   2175          if (j) {
   2176            msg_puts_hl("^J", hl_id, false);
   2177            n -= 2;
   2178          }
   2179          for (p = yb->y_array[j].data;
   2180               *p != NUL && (n -= ptr2cells(p)) >= 0; p++) {
   2181            int clen = utfc_ptr2len(p);
   2182            msg_outtrans_len(p, clen, 0, false);
   2183            p += clen - 1;
   2184          }
   2185        }
   2186        if (n > 1 && yb->y_type == kMTLineWise) {
   2187          msg_puts_hl("^J", hl_id, false);
   2188        }
   2189      }
   2190      os_breakcheck();
   2191    }
   2192  }
   2193 
   2194  // display last inserted text
   2195  String insert = get_last_insert();
   2196  if ((p = insert.data) != NULL
   2197      && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int
   2198      && !message_filtered(p)) {
   2199    msg_puts("\n  c  \".   ");
   2200    dis_msg(p, true);
   2201  }
   2202 
   2203  // display last command line
   2204  if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
   2205      && !got_int && !message_filtered(last_cmdline)) {
   2206    msg_puts("\n  c  \":   ");
   2207    dis_msg(last_cmdline, false);
   2208  }
   2209 
   2210  // display current file name
   2211  if (curbuf->b_fname != NULL
   2212      && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int
   2213      && !message_filtered(curbuf->b_fname)) {
   2214    msg_puts("\n  c  \"%   ");
   2215    dis_msg(curbuf->b_fname, false);
   2216  }
   2217 
   2218  // display alternate file name
   2219  if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int) {
   2220    char *fname;
   2221    linenr_T dummy;
   2222 
   2223    if (buflist_name_nr(0, &fname, &dummy) != FAIL && !message_filtered(fname)) {
   2224      msg_puts("\n  c  \"#   ");
   2225      dis_msg(fname, false);
   2226    }
   2227  }
   2228 
   2229  // display last search pattern
   2230  if (last_search_pat() != NULL
   2231      && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int
   2232      && !message_filtered(last_search_pat())) {
   2233    msg_puts("\n  c  \"/   ");
   2234    dis_msg(last_search_pat(), false);
   2235  }
   2236 
   2237  // display last used expression
   2238  if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
   2239      && !got_int && !message_filtered(expr_line)) {
   2240    msg_puts("\n  c  \"=   ");
   2241    dis_msg(expr_line, false);
   2242  }
   2243  msg_ext_skip_flush = false;
   2244 }
   2245 
   2246 /// Used for getregtype()
   2247 ///
   2248 /// @return  the type of a register or
   2249 ///          kMTUnknown for error.
   2250 MotionType get_reg_type(int regname, colnr_T *reg_width)
   2251 {
   2252  switch (regname) {
   2253  case '%':     // file name
   2254  case '#':     // alternate file name
   2255  case '=':     // expression
   2256  case ':':     // last command line
   2257  case '/':     // last search-pattern
   2258  case '.':     // last inserted text
   2259  case Ctrl_F:  // Filename under cursor
   2260  case Ctrl_P:  // Path under cursor, expand via "path"
   2261  case Ctrl_W:  // word under cursor
   2262  case Ctrl_A:  // WORD (mnemonic All) under cursor
   2263  case '_':     // black hole: always empty
   2264    return kMTCharWise;
   2265  }
   2266 
   2267  if (regname != NUL && !valid_yank_reg(regname, false)) {
   2268    return kMTUnknown;
   2269  }
   2270 
   2271  yankreg_T *reg = get_yank_register(regname, YREG_PASTE);
   2272 
   2273  if (reg->y_array != NULL) {
   2274    if (reg_width != NULL && reg->y_type == kMTBlockWise) {
   2275      *reg_width = reg->y_width;
   2276    }
   2277    return reg->y_type;
   2278  }
   2279  return kMTUnknown;
   2280 }
   2281 
   2282 /// When `flags` has `kGRegList` return a list with text `s`.
   2283 /// Otherwise just return `s`.
   2284 ///
   2285 /// @return  a void * for use in get_reg_contents().
   2286 static void *get_reg_wrap_one_line(char *s, int flags)
   2287 {
   2288  if (!(flags & kGRegList)) {
   2289    return s;
   2290  }
   2291  list_T *const list = tv_list_alloc(1);
   2292  tv_list_append_allocated_string(list, s);
   2293  return list;
   2294 }
   2295 
   2296 /// Gets the contents of a register.
   2297 /// @remark Used for `@r` in expressions and for `getreg()`.
   2298 ///
   2299 /// @param regname  The register.
   2300 /// @param flags    see @ref GRegFlags
   2301 ///
   2302 /// @returns The contents of the register as an allocated string.
   2303 /// @returns A linked list when `flags` contains @ref kGRegList.
   2304 /// @returns NULL for error.
   2305 void *get_reg_contents(int regname, int flags)
   2306 {
   2307  // Don't allow using an expression register inside an expression.
   2308  if (regname == '=') {
   2309    if (flags & kGRegNoExpr) {
   2310      return NULL;
   2311    }
   2312    if (flags & kGRegExprSrc) {
   2313      return get_reg_wrap_one_line(get_expr_line_src(), flags);
   2314    }
   2315    return get_reg_wrap_one_line(get_expr_line(), flags);
   2316  }
   2317 
   2318  if (regname == '@') {     // "@@" is used for unnamed register
   2319    regname = '"';
   2320  }
   2321 
   2322  // check for valid regname
   2323  if (regname != NUL && !valid_yank_reg(regname, false)) {
   2324    return NULL;
   2325  }
   2326 
   2327  char *retval;
   2328  bool allocated;
   2329  if (get_spec_reg(regname, &retval, &allocated, false)) {
   2330    if (retval == NULL) {
   2331      return NULL;
   2332    }
   2333    if (allocated) {
   2334      return get_reg_wrap_one_line(retval, flags);
   2335    }
   2336    return get_reg_wrap_one_line(xstrdup(retval), flags);
   2337  }
   2338 
   2339  yankreg_T *reg = get_yank_register(regname, YREG_PUT);
   2340  if (reg->y_array == NULL) {
   2341    return NULL;
   2342  }
   2343 
   2344  if (flags & kGRegList) {
   2345    list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
   2346    for (size_t i = 0; i < reg->y_size; i++) {
   2347      tv_list_append_string(list, reg->y_array[i].data, (int)reg->y_array[i].size);
   2348    }
   2349 
   2350    return list;
   2351  }
   2352 
   2353  // Compute length of resulting string.
   2354  size_t len = 0;
   2355  for (size_t i = 0; i < reg->y_size; i++) {
   2356    len += reg->y_array[i].size;
   2357    // Insert a newline between lines and after last line if y_type is kMTLineWise.
   2358    if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
   2359      len++;
   2360    }
   2361  }
   2362 
   2363  retval = xmalloc(len + 1);
   2364 
   2365  // Copy the lines of the yank register into the string.
   2366  len = 0;
   2367  for (size_t i = 0; i < reg->y_size; i++) {
   2368    STRCPY(retval + len, reg->y_array[i].data);
   2369    len += reg->y_array[i].size;
   2370 
   2371    // Insert a newline between lines and after the last line if y_type is kMTLineWise.
   2372    if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
   2373      retval[len++] = '\n';
   2374    }
   2375  }
   2376  retval[len] = NUL;
   2377 
   2378  return retval;
   2379 }
   2380 
   2381 static yankreg_T *init_write_reg(int name, yankreg_T **old_y_previous, bool must_append)
   2382 {
   2383  if (!valid_yank_reg(name, true)) {  // check for valid reg name
   2384    emsg_invreg(name);
   2385    return NULL;
   2386  }
   2387 
   2388  // Don't want to change the current (unnamed) register.
   2389  *old_y_previous = y_previous;
   2390 
   2391  yankreg_T *reg = get_yank_register(name, YREG_YANK);
   2392  if (!is_append_register(name) && !must_append) {
   2393    free_register(reg);
   2394  }
   2395  return reg;
   2396 }
   2397 
   2398 /// str_to_reg - Put a string into a register.
   2399 ///
   2400 /// When the register is not empty, the string is appended.
   2401 ///
   2402 /// @param y_ptr pointer to yank register
   2403 /// @param yank_type The motion type (kMTUnknown to auto detect)
   2404 /// @param str string or list of strings to put in register
   2405 /// @param len length of the string (Ignored when str_list=true.)
   2406 /// @param blocklen width of visual block, or -1 for "I don't know."
   2407 /// @param str_list True if str is `char **`.
   2408 static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str, size_t len,
   2409                       colnr_T blocklen, bool str_list)
   2410  FUNC_ATTR_NONNULL_ALL
   2411 {
   2412  if (y_ptr->y_array == NULL) {  // NULL means empty register
   2413    y_ptr->y_size = 0;
   2414  }
   2415 
   2416  if (yank_type == kMTUnknown) {
   2417    yank_type = ((str_list
   2418                  || (len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
   2419                 ? kMTLineWise : kMTCharWise);
   2420  }
   2421 
   2422  size_t newlines = 0;
   2423  bool extraline = false;  // extra line at the end
   2424  bool append = false;     // append to last line in register
   2425 
   2426  // Count the number of lines within the string
   2427  if (str_list) {
   2428    for (char **ss = (char **)str; *ss != NULL; ss++) {
   2429      newlines++;
   2430    }
   2431  } else {
   2432    newlines = memcnt(str, '\n', len);
   2433    if (yank_type == kMTCharWise || len == 0 || str[len - 1] != '\n') {
   2434      extraline = 1;
   2435      newlines++;         // count extra newline at the end
   2436    }
   2437    if (y_ptr->y_size > 0 && y_ptr->y_type == kMTCharWise) {
   2438      append = true;
   2439      newlines--;         // uncount newline when appending first line
   2440    }
   2441  }
   2442 
   2443  // Without any lines make the register empty.
   2444  if (y_ptr->y_size + newlines == 0) {
   2445    XFREE_CLEAR(y_ptr->y_array);
   2446    return;
   2447  }
   2448 
   2449  // Grow the register array to hold the pointers to the new lines.
   2450  String *pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(String));
   2451  y_ptr->y_array = pp;
   2452 
   2453  size_t lnum = y_ptr->y_size;  // The current line number.
   2454 
   2455  // If called with `blocklen < 0`, we have to update the yank reg's width.
   2456  size_t maxlen = 0;
   2457 
   2458  // Find the end of each line and save it into the array.
   2459  if (str_list) {
   2460    for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) {
   2461      pp[lnum] = cstr_to_string(*ss);
   2462      if (yank_type == kMTBlockWise) {
   2463        size_t charlen = mb_string2cells(*ss);
   2464        maxlen = MAX(maxlen, charlen);
   2465      }
   2466    }
   2467  } else {
   2468    size_t line_len;
   2469    for (const char *start = str, *end = str + len;
   2470         start < end + extraline;
   2471         start += line_len + 1, lnum++) {
   2472      int charlen = 0;
   2473 
   2474      const char *line_end = start;
   2475      while (line_end < end) {  // find the end of the line
   2476        if (*line_end == '\n') {
   2477          break;
   2478        }
   2479        if (yank_type == kMTBlockWise) {
   2480          charlen += utf_ptr2cells_len(line_end, (int)(end - line_end));
   2481        }
   2482 
   2483        if (*line_end == NUL) {
   2484          line_end++;  // registers can have NUL chars
   2485        } else {
   2486          line_end += utf_ptr2len_len(line_end, (int)(end - line_end));
   2487        }
   2488      }
   2489      assert(line_end - start >= 0);
   2490      line_len = (size_t)(line_end - start);
   2491      maxlen = MAX(maxlen, (size_t)charlen);
   2492 
   2493      // When appending, copy the previous line and free it after.
   2494      size_t extra = append ? pp[--lnum].size : 0;
   2495      char *s = xmallocz(line_len + extra);
   2496      if (extra > 0) {
   2497        memcpy(s, pp[lnum].data, extra);
   2498      }
   2499      if (line_len > 0) {
   2500        memcpy(s + extra, start, line_len);
   2501      }
   2502      size_t s_len = extra + line_len;
   2503 
   2504      if (append) {
   2505        xfree(pp[lnum].data);
   2506        append = false;  // only first line is appended
   2507      }
   2508      pp[lnum] = cbuf_as_string(s, s_len);
   2509 
   2510      // Convert NULs to '\n' to prevent truncation.
   2511      memchrsub(pp[lnum].data, NUL, '\n', s_len);
   2512    }
   2513  }
   2514  y_ptr->y_type = yank_type;
   2515  y_ptr->y_size = lnum;
   2516  XFREE_CLEAR(y_ptr->additional_data);
   2517  y_ptr->timestamp = os_time();
   2518  if (yank_type == kMTBlockWise) {
   2519    y_ptr->y_width = (blocklen == -1 ? (colnr_T)maxlen - 1 : blocklen);
   2520  } else {
   2521    y_ptr->y_width = 0;
   2522  }
   2523 }
   2524 
   2525 static void finish_write_reg(int name, yankreg_T *reg, yankreg_T *old_y_previous)
   2526 {
   2527  // Send text of clipboard register to the clipboard.
   2528  set_clipboard(name, reg);
   2529 
   2530  // ':let @" = "val"' should change the meaning of the "" register
   2531  if (name != '"') {
   2532    y_previous = old_y_previous;
   2533  }
   2534 }
   2535 
   2536 /// store `str` in register `name`
   2537 ///
   2538 /// @see write_reg_contents_ex
   2539 void write_reg_contents(int name, const char *str, ssize_t len, int must_append)
   2540 {
   2541  write_reg_contents_ex(name, str, len, must_append, kMTUnknown, 0);
   2542 }
   2543 
   2544 void write_reg_contents_lst(int name, char **strings, bool must_append, MotionType yank_type,
   2545                            colnr_T block_len)
   2546 {
   2547  if (name == '/' || name == '=') {
   2548    char *s = strings[0];
   2549    if (strings[0] == NULL) {
   2550      s = "";
   2551    } else if (strings[1] != NULL) {
   2552      emsg(_(e_search_pattern_and_expression_register_may_not_contain_two_or_more_lines));
   2553      return;
   2554    }
   2555    write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
   2556    return;
   2557  }
   2558 
   2559  // black hole: nothing to do
   2560  if (name == '_') {
   2561    return;
   2562  }
   2563 
   2564  yankreg_T *old_y_previous, *reg;
   2565  if (!(reg = init_write_reg(name, &old_y_previous, must_append))) {
   2566    return;
   2567  }
   2568 
   2569  str_to_reg(reg, yank_type, (char *)strings, strlen((char *)strings),
   2570             block_len, true);
   2571  finish_write_reg(name, reg, old_y_previous);
   2572 }
   2573 
   2574 /// write_reg_contents_ex - store `str` in register `name`
   2575 ///
   2576 /// If `str` ends in '\n' or '\r', use linewise, otherwise use charwise.
   2577 ///
   2578 /// @warning when `name` is '/', `len` and `must_append` are ignored. This
   2579 ///          means that `str` MUST be NUL-terminated.
   2580 ///
   2581 /// @param name The name of the register
   2582 /// @param str The contents to write
   2583 /// @param len If >= 0, write `len` bytes of `str`. Otherwise, write
   2584 ///               `strlen(str)` bytes. If `len` is larger than the
   2585 ///               allocated size of `src`, the behaviour is undefined.
   2586 /// @param must_append If true, append the contents of `str` to the current
   2587 ///                    contents of the register. Note that regardless of
   2588 ///                    `must_append`, this function will append when `name`
   2589 ///                    is an uppercase letter.
   2590 /// @param yank_type The motion type (kMTUnknown to auto detect)
   2591 /// @param block_len width of visual block
   2592 void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_append,
   2593                           MotionType yank_type, colnr_T block_len)
   2594 {
   2595  if (len < 0) {
   2596    len = (ssize_t)strlen(str);
   2597  }
   2598 
   2599  // Special case: '/' search pattern
   2600  if (name == '/') {
   2601    set_last_search_pat(str, RE_SEARCH, true, true);
   2602    return;
   2603  }
   2604 
   2605  if (name == '#') {
   2606    buf_T *buf;
   2607 
   2608    if (ascii_isdigit(*str)) {
   2609      int num = atoi(str);
   2610 
   2611      buf = buflist_findnr(num);
   2612      if (buf == NULL) {
   2613        semsg(_(e_nobufnr), (int64_t)num);
   2614      }
   2615    } else {
   2616      buf = buflist_findnr(buflist_findpat(str, str + len, true, false, false));
   2617    }
   2618    if (buf == NULL) {
   2619      return;
   2620    }
   2621    curwin->w_alt_fnum = buf->b_fnum;
   2622    return;
   2623  }
   2624 
   2625  if (name == '=') {
   2626    size_t offset = 0;
   2627    size_t totlen = (size_t)len;
   2628 
   2629    if (must_append && expr_line) {
   2630      // append has been specified and expr_line already exists, so we'll
   2631      // append the new string to expr_line.
   2632      size_t exprlen = strlen(expr_line);
   2633 
   2634      totlen += exprlen;
   2635      offset = exprlen;
   2636    }
   2637 
   2638    // modify the global expr_line, extend/shrink it if necessary (realloc).
   2639    // Copy the input string into the adjusted memory at the specified
   2640    // offset.
   2641    expr_line = xrealloc(expr_line, totlen + 1);
   2642    memcpy(expr_line + offset, str, (size_t)len);
   2643    expr_line[totlen] = NUL;
   2644 
   2645    return;
   2646  }
   2647 
   2648  if (name == '_') {        // black hole: nothing to do
   2649    return;
   2650  }
   2651 
   2652  yankreg_T *old_y_previous, *reg;
   2653  if (!(reg = init_write_reg(name, &old_y_previous, must_append))) {
   2654    return;
   2655  }
   2656  str_to_reg(reg, yank_type, str, (size_t)len, block_len, false);
   2657  finish_write_reg(name, reg, old_y_previous);
   2658 }
   2659 
   2660 /// @param[out] reg Expected to be empty
   2661 bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
   2662 {
   2663  char type = regtype.data ? regtype.data[0] : NUL;
   2664 
   2665  switch (type) {
   2666  case 0:
   2667    reg->y_type = kMTUnknown;
   2668    break;
   2669  case 'v':
   2670  case 'c':
   2671    reg->y_type = kMTCharWise;
   2672    break;
   2673  case 'V':
   2674  case 'l':
   2675    reg->y_type = kMTLineWise;
   2676    break;
   2677  case 'b':
   2678  case Ctrl_V:
   2679    reg->y_type = kMTBlockWise;
   2680    break;
   2681  default:
   2682    return false;
   2683  }
   2684 
   2685  reg->y_width = 0;
   2686  if (regtype.size > 1) {
   2687    if (reg->y_type != kMTBlockWise) {
   2688      return false;
   2689    }
   2690 
   2691    // allow "b7" for a block at least 7 spaces wide
   2692    if (!ascii_isdigit(regtype.data[1])) {
   2693      return false;
   2694    }
   2695    const char *p = regtype.data + 1;
   2696    reg->y_width = getdigits_int((char **)&p, false, 1) - 1;
   2697    if (regtype.size > (size_t)(p - regtype.data)) {
   2698      return false;
   2699    }
   2700  }
   2701 
   2702  reg->additional_data = NULL;
   2703  reg->timestamp = 0;
   2704  return true;
   2705 }
   2706 
   2707 void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
   2708 {
   2709  if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
   2710    // a known-to-be charwise yank might have a final linebreak
   2711    // but otherwise there is no line after the final newline
   2712    if (reg->y_type != kMTCharWise) {
   2713      if (reg->y_type == kMTUnknown || clipboard_adjust) {
   2714        reg->y_size--;
   2715      }
   2716      if (reg->y_type == kMTUnknown) {
   2717        reg->y_type = kMTLineWise;
   2718      }
   2719    }
   2720  } else {
   2721    if (reg->y_type == kMTUnknown) {
   2722      reg->y_type = kMTCharWise;
   2723    }
   2724  }
   2725 
   2726  update_yankreg_width(reg);
   2727 }