xref: /vim-8.2.3635/src/ops.c (revision fcfe1a9b)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * ops.c: implementation of various operators: op_shift, op_delete, op_tilde,
12  *	  op_change, op_yank, do_put, do_join
13  */
14 
15 #include "vim.h"
16 
17 /*
18  * Number of registers.
19  *	0 = unnamed register, for normal yanks and puts
20  *   1..9 = registers '1' to '9', for deletes
21  * 10..35 = registers 'a' to 'z'
22  *     36 = delete register '-'
23  *     37 = Selection register '*'. Only if FEAT_CLIPBOARD defined
24  *     38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined
25  */
26 
27 static yankreg_T	y_regs[NUM_REGISTERS];
28 
29 static yankreg_T	*y_current;	    /* ptr to current yankreg */
30 static int		y_append;	    /* TRUE when appending */
31 static yankreg_T	*y_previous = NULL; /* ptr to last written yankreg */
32 
33 /*
34  * structure used by block_prep, op_delete and op_yank for blockwise operators
35  * also op_change, op_shift, op_insert, op_replace - AKelly
36  */
37 struct block_def
38 {
39     int		startspaces;	/* 'extra' cols before first char */
40     int		endspaces;	/* 'extra' cols after last char */
41     int		textlen;	/* chars in block */
42     char_u	*textstart;	/* pointer to 1st char (partially) in block */
43     colnr_T	textcol;	/* index of chars (partially) in block */
44     colnr_T	start_vcol;	/* start col of 1st char wholly inside block */
45     colnr_T	end_vcol;	/* start col of 1st char wholly after block */
46     int		is_short;	/* TRUE if line is too short to fit in block */
47     int		is_MAX;		/* TRUE if curswant==MAXCOL when starting */
48     int		is_oneChar;	/* TRUE if block within one character */
49     int		pre_whitesp;	/* screen cols of ws before block */
50     int		pre_whitesp_c;	/* chars of ws before block */
51     colnr_T	end_char_vcols;	/* number of vcols of post-block char */
52     colnr_T	start_char_vcols; /* number of vcols of pre-block char */
53 };
54 
55 static void shift_block(oparg_T *oap, int amount);
56 static int	stuff_yank(int, char_u *);
57 static void	put_reedit_in_typebuf(int silent);
58 static int	put_in_typebuf(char_u *s, int esc, int colon,
59 								 int silent);
60 static void	stuffescaped(char_u *arg, int literally);
61 static void	mb_adjust_opend(oparg_T *oap);
62 static void	free_yank_all(void);
63 static int	yank_copy_line(struct block_def *bd, long y_idx);
64 #ifdef FEAT_CLIPBOARD
65 static void	copy_yank_reg(yankreg_T *reg);
66 static void	may_set_selection(void);
67 #endif
68 static void	dis_msg(char_u *p, int skip_esc);
69 static void	block_prep(oparg_T *oap, struct block_def *, linenr_T, int);
70 static int	do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1);
71 #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
72 static void	str_to_reg(yankreg_T *y_ptr, int yank_type, char_u *str, long len, long blocklen, int str_list);
73 #endif
74 static int	ends_in_white(linenr_T lnum);
75 #ifdef FEAT_COMMENTS
76 static int	fmt_check_par(linenr_T, int *, char_u **, int do_comments);
77 #else
78 static int	fmt_check_par(linenr_T);
79 #endif
80 
81 // Flags for third item in "opchars".
82 #define OPF_LINES  1	// operator always works on lines
83 #define OPF_CHANGE 2	// operator changes text
84 
85 /*
86  * The names of operators.
87  * IMPORTANT: Index must correspond with defines in vim.h!!!
88  * The third field holds OPF_ flags.
89  */
90 static char opchars[][3] =
91 {
92     {NUL, NUL, 0},			// OP_NOP
93     {'d', NUL, OPF_CHANGE},		// OP_DELETE
94     {'y', NUL, 0},			// OP_YANK
95     {'c', NUL, OPF_CHANGE},		// OP_CHANGE
96     {'<', NUL, OPF_LINES | OPF_CHANGE},	// OP_LSHIFT
97     {'>', NUL, OPF_LINES | OPF_CHANGE},	// OP_RSHIFT
98     {'!', NUL, OPF_LINES | OPF_CHANGE},	// OP_FILTER
99     {'g', '~', OPF_CHANGE},		// OP_TILDE
100     {'=', NUL, OPF_LINES | OPF_CHANGE},	// OP_INDENT
101     {'g', 'q', OPF_LINES | OPF_CHANGE},	// OP_FORMAT
102     {':', NUL, OPF_LINES},		// OP_COLON
103     {'g', 'U', OPF_CHANGE},		// OP_UPPER
104     {'g', 'u', OPF_CHANGE},		// OP_LOWER
105     {'J', NUL, OPF_LINES | OPF_CHANGE},	// DO_JOIN
106     {'g', 'J', OPF_LINES | OPF_CHANGE},	// DO_JOIN_NS
107     {'g', '?', OPF_CHANGE},		// OP_ROT13
108     {'r', NUL, OPF_CHANGE},		// OP_REPLACE
109     {'I', NUL, OPF_CHANGE},		// OP_INSERT
110     {'A', NUL, OPF_CHANGE},		// OP_APPEND
111     {'z', 'f', OPF_LINES},		// OP_FOLD
112     {'z', 'o', OPF_LINES},		// OP_FOLDOPEN
113     {'z', 'O', OPF_LINES},		// OP_FOLDOPENREC
114     {'z', 'c', OPF_LINES},		// OP_FOLDCLOSE
115     {'z', 'C', OPF_LINES},		// OP_FOLDCLOSEREC
116     {'z', 'd', OPF_LINES},		// OP_FOLDDEL
117     {'z', 'D', OPF_LINES},		// OP_FOLDDELREC
118     {'g', 'w', OPF_LINES | OPF_CHANGE},	// OP_FORMAT2
119     {'g', '@', OPF_CHANGE},		// OP_FUNCTION
120     {Ctrl_A, NUL, OPF_CHANGE},		// OP_NR_ADD
121     {Ctrl_X, NUL, OPF_CHANGE},		// OP_NR_SUB
122 };
123 
124     yankreg_T *
125 get_y_regs(void)
126 {
127     return y_regs;
128 }
129 
130     yankreg_T *
131 get_y_current(void)
132 {
133     return y_current;
134 }
135 
136     yankreg_T *
137 get_y_previous(void)
138 {
139     return y_previous;
140 }
141 
142     void
143 set_y_previous(yankreg_T *yreg)
144 {
145     y_previous = yreg;
146 }
147 
148 
149 /*
150  * Translate a command name into an operator type.
151  * Must only be called with a valid operator name!
152  */
153     int
154 get_op_type(int char1, int char2)
155 {
156     int		i;
157 
158     if (char1 == 'r')		/* ignore second character */
159 	return OP_REPLACE;
160     if (char1 == '~')		/* when tilde is an operator */
161 	return OP_TILDE;
162     if (char1 == 'g' && char2 == Ctrl_A)	/* add */
163 	return OP_NR_ADD;
164     if (char1 == 'g' && char2 == Ctrl_X)	/* subtract */
165 	return OP_NR_SUB;
166     for (i = 0; ; ++i)
167     {
168 	if (opchars[i][0] == char1 && opchars[i][1] == char2)
169 	    break;
170 	if (i == (int)(sizeof(opchars) / sizeof(char [3]) - 1))
171 	{
172 	    internal_error("get_op_type()");
173 	    break;
174 	}
175     }
176     return i;
177 }
178 
179 /*
180  * Return TRUE if operator "op" always works on whole lines.
181  */
182     int
183 op_on_lines(int op)
184 {
185     return opchars[op][2] & OPF_LINES;
186 }
187 
188 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
189 /*
190  * Return TRUE if operator "op" changes text.
191  */
192     int
193 op_is_change(int op)
194 {
195     return opchars[op][2] & OPF_CHANGE;
196 }
197 #endif
198 
199 /*
200  * Get first operator command character.
201  * Returns 'g' or 'z' if there is another command character.
202  */
203     int
204 get_op_char(int optype)
205 {
206     return opchars[optype][0];
207 }
208 
209 /*
210  * Get second operator command character.
211  */
212     int
213 get_extra_op_char(int optype)
214 {
215     return opchars[optype][1];
216 }
217 
218 /*
219  * op_shift - handle a shift operation
220  */
221     void
222 op_shift(oparg_T *oap, int curs_top, int amount)
223 {
224     long	    i;
225     int		    first_char;
226     int		    block_col = 0;
227 
228     if (u_save((linenr_T)(oap->start.lnum - 1),
229 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
230 	return;
231 
232     if (oap->block_mode)
233 	block_col = curwin->w_cursor.col;
234 
235     for (i = oap->line_count; --i >= 0; )
236     {
237 	first_char = *ml_get_curline();
238 	if (first_char == NUL)				/* empty line */
239 	    curwin->w_cursor.col = 0;
240 	else if (oap->block_mode)
241 	    shift_block(oap, amount);
242 	else
243 	    /* Move the line right if it doesn't start with '#', 'smartindent'
244 	     * isn't set or 'cindent' isn't set or '#' isn't in 'cino'. */
245 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
246 	    if (first_char != '#' || !preprocs_left())
247 #endif
248 	    shift_line(oap->op_type == OP_LSHIFT, p_sr, amount, FALSE);
249 	++curwin->w_cursor.lnum;
250     }
251 
252     changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
253     if (oap->block_mode)
254     {
255 	curwin->w_cursor.lnum = oap->start.lnum;
256 	curwin->w_cursor.col = block_col;
257     }
258     else if (curs_top)	    /* put cursor on first line, for ">>" */
259     {
260 	curwin->w_cursor.lnum = oap->start.lnum;
261 	beginline(BL_SOL | BL_FIX);   /* shift_line() may have set cursor.col */
262     }
263     else
264 	--curwin->w_cursor.lnum;	/* put cursor on last line, for ":>" */
265 
266 #ifdef FEAT_FOLDING
267     /* The cursor line is not in a closed fold */
268     foldOpenCursor();
269 #endif
270 
271 
272     if (oap->line_count > p_report)
273     {
274 	char	    *op;
275 	char	    *msg_line_single;
276 	char	    *msg_line_plural;
277 
278 	if (oap->op_type == OP_RSHIFT)
279 	    op = ">";
280 	else
281 	    op = "<";
282 	msg_line_single = NGETTEXT("%ld line %sed %d time",
283 					     "%ld line %sed %d times", amount);
284 	msg_line_plural = NGETTEXT("%ld lines %sed %d time",
285 					    "%ld lines %sed %d times", amount);
286 	vim_snprintf((char *)IObuff, IOSIZE,
287 		NGETTEXT(msg_line_single, msg_line_plural, oap->line_count),
288 		oap->line_count, op, amount);
289 	msg((char *)IObuff);
290     }
291 
292     /*
293      * Set "'[" and "']" marks.
294      */
295     curbuf->b_op_start = oap->start;
296     curbuf->b_op_end.lnum = oap->end.lnum;
297     curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
298     if (curbuf->b_op_end.col > 0)
299 	--curbuf->b_op_end.col;
300 }
301 
302 /*
303  * Shift the current line one shiftwidth left (if left != 0) or right
304  * leaves cursor on first blank in the line.
305  */
306     void
307 shift_line(
308     int	left,
309     int	round,
310     int	amount,
311     int call_changed_bytes)	/* call changed_bytes() */
312 {
313     int		count;
314     int		i, j;
315     int		p_sw = (int)get_sw_value_indent(curbuf);
316 
317     count = get_indent();	/* get current indent */
318 
319     if (round)			/* round off indent */
320     {
321 	i = count / p_sw;	/* number of p_sw rounded down */
322 	j = count % p_sw;	/* extra spaces */
323 	if (j && left)		/* first remove extra spaces */
324 	    --amount;
325 	if (left)
326 	{
327 	    i -= amount;
328 	    if (i < 0)
329 		i = 0;
330 	}
331 	else
332 	    i += amount;
333 	count = i * p_sw;
334     }
335     else		/* original vi indent */
336     {
337 	if (left)
338 	{
339 	    count -= p_sw * amount;
340 	    if (count < 0)
341 		count = 0;
342 	}
343 	else
344 	    count += p_sw * amount;
345     }
346 
347     /* Set new indent */
348     if (State & VREPLACE_FLAG)
349 	change_indent(INDENT_SET, count, FALSE, NUL, call_changed_bytes);
350     else
351 	(void)set_indent(count, call_changed_bytes ? SIN_CHANGED : 0);
352 }
353 
354 /*
355  * Shift one line of the current block one shiftwidth right or left.
356  * Leaves cursor on first character in block.
357  */
358     static void
359 shift_block(oparg_T *oap, int amount)
360 {
361     int			left = (oap->op_type == OP_LSHIFT);
362     int			oldstate = State;
363     int			total;
364     char_u		*newp, *oldp;
365     int			oldcol = curwin->w_cursor.col;
366     int			p_sw = (int)get_sw_value_indent(curbuf);
367 #ifdef FEAT_VARTABS
368     int			*p_vts = curbuf->b_p_vts_array;
369 #endif
370     int			p_ts = (int)curbuf->b_p_ts;
371     struct block_def	bd;
372     int			incr;
373     colnr_T		ws_vcol;
374     int			i = 0, j = 0;
375     int			len;
376 #ifdef FEAT_RIGHTLEFT
377     int			old_p_ri = p_ri;
378 
379     p_ri = 0;			/* don't want revins in indent */
380 #endif
381 
382     State = INSERT;		/* don't want REPLACE for State */
383     block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
384     if (bd.is_short)
385 	return;
386 
387     /* total is number of screen columns to be inserted/removed */
388     total = (int)((unsigned)amount * (unsigned)p_sw);
389     if ((total / p_sw) != amount)
390 	return; /* multiplication overflow */
391 
392     oldp = ml_get_curline();
393 
394     if (!left)
395     {
396 	/*
397 	 *  1. Get start vcol
398 	 *  2. Total ws vcols
399 	 *  3. Divvy into TABs & spp
400 	 *  4. Construct new string
401 	 */
402 	total += bd.pre_whitesp; /* all virtual WS upto & incl a split TAB */
403 	ws_vcol = bd.start_vcol - bd.pre_whitesp;
404 	if (bd.startspaces)
405 	{
406 	    if (has_mbyte)
407 	    {
408 		if ((*mb_ptr2len)(bd.textstart) == 1)
409 		    ++bd.textstart;
410 		else
411 		{
412 		    ws_vcol = 0;
413 		    bd.startspaces = 0;
414 		}
415 	    }
416 	    else
417 		++bd.textstart;
418 	}
419 	for ( ; VIM_ISWHITE(*bd.textstart); )
420 	{
421 	    /* TODO: is passing bd.textstart for start of the line OK? */
422 	    incr = lbr_chartabsize_adv(bd.textstart, &bd.textstart,
423 						    (colnr_T)(bd.start_vcol));
424 	    total += incr;
425 	    bd.start_vcol += incr;
426 	}
427 	/* OK, now total=all the VWS reqd, and textstart points at the 1st
428 	 * non-ws char in the block. */
429 #ifdef FEAT_VARTABS
430 	if (!curbuf->b_p_et)
431 	    tabstop_fromto(ws_vcol, ws_vcol + total, p_ts, p_vts, &i, &j);
432 	else
433 	    j = total;
434 #else
435 	if (!curbuf->b_p_et)
436 	    i = ((ws_vcol % p_ts) + total) / p_ts; /* number of tabs */
437 	if (i)
438 	    j = ((ws_vcol % p_ts) + total) % p_ts; /* number of spp */
439 	else
440 	    j = total;
441 #endif
442 	/* if we're splitting a TAB, allow for it */
443 	bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);
444 	len = (int)STRLEN(bd.textstart) + 1;
445 	newp = alloc(bd.textcol + i + j + len);
446 	if (newp == NULL)
447 	    return;
448 	vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + len));
449 	mch_memmove(newp, oldp, (size_t)bd.textcol);
450 	vim_memset(newp + bd.textcol, TAB, (size_t)i);
451 	vim_memset(newp + bd.textcol + i, ' ', (size_t)j);
452 	/* the end */
453 	mch_memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);
454     }
455     else /* left */
456     {
457 	colnr_T	    destination_col;	/* column to which text in block will
458 					   be shifted */
459 	char_u	    *verbatim_copy_end;	/* end of the part of the line which is
460 					   copied verbatim */
461 	colnr_T	    verbatim_copy_width;/* the (displayed) width of this part
462 					   of line */
463 	unsigned    fill;		/* nr of spaces that replace a TAB */
464 	unsigned    new_line_len;	/* the length of the line after the
465 					   block shift */
466 	size_t	    block_space_width;
467 	size_t	    shift_amount;
468 	char_u	    *non_white = bd.textstart;
469 	colnr_T	    non_white_col;
470 
471 	/*
472 	 * Firstly, let's find the first non-whitespace character that is
473 	 * displayed after the block's start column and the character's column
474 	 * number. Also, let's calculate the width of all the whitespace
475 	 * characters that are displayed in the block and precede the searched
476 	 * non-whitespace character.
477 	 */
478 
479 	/* If "bd.startspaces" is set, "bd.textstart" points to the character,
480 	 * the part of which is displayed at the block's beginning. Let's start
481 	 * searching from the next character. */
482 	if (bd.startspaces)
483 	    MB_PTR_ADV(non_white);
484 
485 	/* The character's column is in "bd.start_vcol".  */
486 	non_white_col = bd.start_vcol;
487 
488 	while (VIM_ISWHITE(*non_white))
489 	{
490 	    incr = lbr_chartabsize_adv(bd.textstart, &non_white, non_white_col);
491 	    non_white_col += incr;
492 	}
493 
494 	block_space_width = non_white_col - oap->start_vcol;
495 	/* We will shift by "total" or "block_space_width", whichever is less.
496 	 */
497 	shift_amount = (block_space_width < (size_t)total
498 					 ? block_space_width : (size_t)total);
499 
500 	/* The column to which we will shift the text.  */
501 	destination_col = (colnr_T)(non_white_col - shift_amount);
502 
503 	/* Now let's find out how much of the beginning of the line we can
504 	 * reuse without modification.  */
505 	verbatim_copy_end = bd.textstart;
506 	verbatim_copy_width = bd.start_vcol;
507 
508 	/* If "bd.startspaces" is set, "bd.textstart" points to the character
509 	 * preceding the block. We have to subtract its width to obtain its
510 	 * column number.  */
511 	if (bd.startspaces)
512 	    verbatim_copy_width -= bd.start_char_vcols;
513 	while (verbatim_copy_width < destination_col)
514 	{
515 	    char_u *line = verbatim_copy_end;
516 
517 	    /* TODO: is passing verbatim_copy_end for start of the line OK? */
518 	    incr = lbr_chartabsize(line, verbatim_copy_end,
519 							 verbatim_copy_width);
520 	    if (verbatim_copy_width + incr > destination_col)
521 		break;
522 	    verbatim_copy_width += incr;
523 	    MB_PTR_ADV(verbatim_copy_end);
524 	}
525 
526 	/* If "destination_col" is different from the width of the initial
527 	 * part of the line that will be copied, it means we encountered a tab
528 	 * character, which we will have to partly replace with spaces.  */
529 	fill = destination_col - verbatim_copy_width;
530 
531 	/* The replacement line will consist of:
532 	 * - the beginning of the original line up to "verbatim_copy_end",
533 	 * - "fill" number of spaces,
534 	 * - the rest of the line, pointed to by non_white.  */
535 	new_line_len = (unsigned)(verbatim_copy_end - oldp)
536 		       + fill
537 		       + (unsigned)STRLEN(non_white) + 1;
538 
539 	newp = alloc(new_line_len);
540 	if (newp == NULL)
541 	    return;
542 	mch_memmove(newp, oldp, (size_t)(verbatim_copy_end - oldp));
543 	vim_memset(newp + (verbatim_copy_end - oldp), ' ', (size_t)fill);
544 	STRMOVE(newp + (verbatim_copy_end - oldp) + fill, non_white);
545     }
546     /* replace the line */
547     ml_replace(curwin->w_cursor.lnum, newp, FALSE);
548     changed_bytes(curwin->w_cursor.lnum, (colnr_T)bd.textcol);
549     State = oldstate;
550     curwin->w_cursor.col = oldcol;
551 #ifdef FEAT_RIGHTLEFT
552     p_ri = old_p_ri;
553 #endif
554 }
555 
556 /*
557  * Insert string "s" (b_insert ? before : after) block :AKelly
558  * Caller must prepare for undo.
559  */
560     static void
561 block_insert(
562     oparg_T		*oap,
563     char_u		*s,
564     int			b_insert,
565     struct block_def	*bdp)
566 {
567     int		p_ts;
568     int		count = 0;	/* extra spaces to replace a cut TAB */
569     int		spaces = 0;	/* non-zero if cutting a TAB */
570     colnr_T	offset;		/* pointer along new line */
571     unsigned	s_len;		/* STRLEN(s) */
572     char_u	*newp, *oldp;	/* new, old lines */
573     linenr_T	lnum;		/* loop var */
574     int		oldstate = State;
575 
576     State = INSERT;		/* don't want REPLACE for State */
577     s_len = (unsigned)STRLEN(s);
578 
579     for (lnum = oap->start.lnum + 1; lnum <= oap->end.lnum; lnum++)
580     {
581 	block_prep(oap, bdp, lnum, TRUE);
582 	if (bdp->is_short && b_insert)
583 	    continue;	/* OP_INSERT, line ends before block start */
584 
585 	oldp = ml_get(lnum);
586 
587 	if (b_insert)
588 	{
589 	    p_ts = bdp->start_char_vcols;
590 	    spaces = bdp->startspaces;
591 	    if (spaces != 0)
592 		count = p_ts - 1; /* we're cutting a TAB */
593 	    offset = bdp->textcol;
594 	}
595 	else /* append */
596 	{
597 	    p_ts = bdp->end_char_vcols;
598 	    if (!bdp->is_short) /* spaces = padding after block */
599 	    {
600 		spaces = (bdp->endspaces ? p_ts - bdp->endspaces : 0);
601 		if (spaces != 0)
602 		    count = p_ts - 1; /* we're cutting a TAB */
603 		offset = bdp->textcol + bdp->textlen - (spaces != 0);
604 	    }
605 	    else /* spaces = padding to block edge */
606 	    {
607 		/* if $ used, just append to EOL (ie spaces==0) */
608 		if (!bdp->is_MAX)
609 		    spaces = (oap->end_vcol - bdp->end_vcol) + 1;
610 		count = spaces;
611 		offset = bdp->textcol + bdp->textlen;
612 	    }
613 	}
614 
615 	if (has_mbyte && spaces > 0)
616 	{
617 	    int off;
618 
619 	    /* Avoid starting halfway a multi-byte character. */
620 	    if (b_insert)
621 	    {
622 		off = (*mb_head_off)(oldp, oldp + offset + spaces);
623 	    }
624 	    else
625 	    {
626 		off = (*mb_off_next)(oldp, oldp + offset);
627 		offset += off;
628 	    }
629 	    spaces -= off;
630 	    count -= off;
631 	}
632 
633 	newp = alloc(STRLEN(oldp) + s_len + count + 1);
634 	if (newp == NULL)
635 	    continue;
636 
637 	/* copy up to shifted part */
638 	mch_memmove(newp, oldp, (size_t)(offset));
639 	oldp += offset;
640 
641 	/* insert pre-padding */
642 	vim_memset(newp + offset, ' ', (size_t)spaces);
643 
644 	/* copy the new text */
645 	mch_memmove(newp + offset + spaces, s, (size_t)s_len);
646 	offset += s_len;
647 
648 	if (spaces && !bdp->is_short)
649 	{
650 	    /* insert post-padding */
651 	    vim_memset(newp + offset + spaces, ' ', (size_t)(p_ts - spaces));
652 	    /* We're splitting a TAB, don't copy it. */
653 	    oldp++;
654 	    /* We allowed for that TAB, remember this now */
655 	    count++;
656 	}
657 
658 	if (spaces > 0)
659 	    offset += count;
660 	STRMOVE(newp + offset, oldp);
661 
662 	ml_replace(lnum, newp, FALSE);
663 
664 	if (lnum == oap->end.lnum)
665 	{
666 	    /* Set "']" mark to the end of the block instead of the end of
667 	     * the insert in the first line.  */
668 	    curbuf->b_op_end.lnum = oap->end.lnum;
669 	    curbuf->b_op_end.col = offset;
670 	}
671     } /* for all lnum */
672 
673     changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L);
674 
675     State = oldstate;
676 }
677 
678 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
679 /*
680  * op_reindent - handle reindenting a block of lines.
681  */
682     void
683 op_reindent(oparg_T *oap, int (*how)(void))
684 {
685     long	i;
686     char_u	*l;
687     int		amount;
688     linenr_T	first_changed = 0;
689     linenr_T	last_changed = 0;
690     linenr_T	start_lnum = curwin->w_cursor.lnum;
691 
692     /* Don't even try when 'modifiable' is off. */
693     if (!curbuf->b_p_ma)
694     {
695 	emsg(_(e_modifiable));
696 	return;
697     }
698 
699     for (i = oap->line_count; --i >= 0 && !got_int; )
700     {
701 	/* it's a slow thing to do, so give feedback so there's no worry that
702 	 * the computer's just hung. */
703 
704 	if (i > 1
705 		&& (i % 50 == 0 || i == oap->line_count - 1)
706 		&& oap->line_count > p_report)
707 	    smsg(_("%ld lines to indent... "), i);
708 
709 	/*
710 	 * Be vi-compatible: For lisp indenting the first line is not
711 	 * indented, unless there is only one line.
712 	 */
713 #ifdef FEAT_LISP
714 	if (i != oap->line_count - 1 || oap->line_count == 1
715 						    || how != get_lisp_indent)
716 #endif
717 	{
718 	    l = skipwhite(ml_get_curline());
719 	    if (*l == NUL)		    /* empty or blank line */
720 		amount = 0;
721 	    else
722 		amount = how();		    /* get the indent for this line */
723 
724 	    if (amount >= 0 && set_indent(amount, SIN_UNDO))
725 	    {
726 		/* did change the indent, call changed_lines() later */
727 		if (first_changed == 0)
728 		    first_changed = curwin->w_cursor.lnum;
729 		last_changed = curwin->w_cursor.lnum;
730 	    }
731 	}
732 	++curwin->w_cursor.lnum;
733 	curwin->w_cursor.col = 0;  /* make sure it's valid */
734     }
735 
736     /* put cursor on first non-blank of indented line */
737     curwin->w_cursor.lnum = start_lnum;
738     beginline(BL_SOL | BL_FIX);
739 
740     /* Mark changed lines so that they will be redrawn.  When Visual
741      * highlighting was present, need to continue until the last line.  When
742      * there is no change still need to remove the Visual highlighting. */
743     if (last_changed != 0)
744 	changed_lines(first_changed, 0,
745 		oap->is_VIsual ? start_lnum + oap->line_count :
746 		last_changed + 1, 0L);
747     else if (oap->is_VIsual)
748 	redraw_curbuf_later(INVERTED);
749 
750     if (oap->line_count > p_report)
751     {
752 	i = oap->line_count - (i + 1);
753 	smsg(NGETTEXT("%ld line indented ",
754 						 "%ld lines indented ", i), i);
755     }
756     /* set '[ and '] marks */
757     curbuf->b_op_start = oap->start;
758     curbuf->b_op_end = oap->end;
759 }
760 #endif /* defined(FEAT_LISP) || defined(FEAT_CINDENT) */
761 
762 #if defined(FEAT_EVAL) || defined(PROTO)
763 /*
764  * Keep the last expression line here, for repeating.
765  */
766 static char_u	*expr_line = NULL;
767 
768 /*
769  * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
770  * Returns '=' when OK, NUL otherwise.
771  */
772     int
773 get_expr_register(void)
774 {
775     char_u	*new_line;
776 
777     new_line = getcmdline('=', 0L, 0, TRUE);
778     if (new_line == NULL)
779 	return NUL;
780     if (*new_line == NUL)	/* use previous line */
781 	vim_free(new_line);
782     else
783 	set_expr_line(new_line);
784     return '=';
785 }
786 
787 /*
788  * Set the expression for the '=' register.
789  * Argument must be an allocated string.
790  */
791     void
792 set_expr_line(char_u *new_line)
793 {
794     vim_free(expr_line);
795     expr_line = new_line;
796 }
797 
798 /*
799  * Get the result of the '=' register expression.
800  * Returns a pointer to allocated memory, or NULL for failure.
801  */
802     char_u *
803 get_expr_line(void)
804 {
805     char_u	*expr_copy;
806     char_u	*rv;
807     static int	nested = 0;
808 
809     if (expr_line == NULL)
810 	return NULL;
811 
812     /* Make a copy of the expression, because evaluating it may cause it to be
813      * changed. */
814     expr_copy = vim_strsave(expr_line);
815     if (expr_copy == NULL)
816 	return NULL;
817 
818     /* When we are invoked recursively limit the evaluation to 10 levels.
819      * Then return the string as-is. */
820     if (nested >= 10)
821 	return expr_copy;
822 
823     ++nested;
824     rv = eval_to_string(expr_copy, NULL, TRUE);
825     --nested;
826     vim_free(expr_copy);
827     return rv;
828 }
829 
830 /*
831  * Get the '=' register expression itself, without evaluating it.
832  */
833     char_u *
834 get_expr_line_src(void)
835 {
836     if (expr_line == NULL)
837 	return NULL;
838     return vim_strsave(expr_line);
839 }
840 #endif /* FEAT_EVAL */
841 
842 /*
843  * Check if 'regname' is a valid name of a yank register.
844  * Note: There is no check for 0 (default register), caller should do this
845  */
846     int
847 valid_yank_reg(
848     int	    regname,
849     int	    writing)	    /* if TRUE check for writable registers */
850 {
851     if (       (regname > 0 && ASCII_ISALNUM(regname))
852 	    || (!writing && vim_strchr((char_u *)
853 #ifdef FEAT_EVAL
854 				    "/.%:="
855 #else
856 				    "/.%:"
857 #endif
858 					, regname) != NULL)
859 	    || regname == '#'
860 	    || regname == '"'
861 	    || regname == '-'
862 	    || regname == '_'
863 #ifdef FEAT_CLIPBOARD
864 	    || regname == '*'
865 	    || regname == '+'
866 #endif
867 #ifdef FEAT_DND
868 	    || (!writing && regname == '~')
869 #endif
870 							)
871 	return TRUE;
872     return FALSE;
873 }
874 
875 /*
876  * Set y_current and y_append, according to the value of "regname".
877  * Cannot handle the '_' register.
878  * Must only be called with a valid register name!
879  *
880  * If regname is 0 and writing, use register 0
881  * If regname is 0 and reading, use previous register
882  *
883  * Return TRUE when the register should be inserted literally (selection or
884  * clipboard).
885  */
886     int
887 get_yank_register(int regname, int writing)
888 {
889     int	    i;
890     int	    ret = FALSE;
891 
892     y_append = FALSE;
893     if ((regname == 0 || regname == '"') && !writing && y_previous != NULL)
894     {
895 	y_current = y_previous;
896 	return ret;
897     }
898     i = regname;
899     if (VIM_ISDIGIT(i))
900 	i -= '0';
901     else if (ASCII_ISLOWER(i))
902 	i = CharOrdLow(i) + 10;
903     else if (ASCII_ISUPPER(i))
904     {
905 	i = CharOrdUp(i) + 10;
906 	y_append = TRUE;
907     }
908     else if (regname == '-')
909 	i = DELETION_REGISTER;
910 #ifdef FEAT_CLIPBOARD
911     /* When selection is not available, use register 0 instead of '*' */
912     else if (clip_star.available && regname == '*')
913     {
914 	i = STAR_REGISTER;
915 	ret = TRUE;
916     }
917     /* When clipboard is not available, use register 0 instead of '+' */
918     else if (clip_plus.available && regname == '+')
919     {
920 	i = PLUS_REGISTER;
921 	ret = TRUE;
922     }
923 #endif
924 #ifdef FEAT_DND
925     else if (!writing && regname == '~')
926 	i = TILDE_REGISTER;
927 #endif
928     else		/* not 0-9, a-z, A-Z or '-': use register 0 */
929 	i = 0;
930     y_current = &(y_regs[i]);
931     if (writing)	/* remember the register we write into for do_put() */
932 	y_previous = y_current;
933     return ret;
934 }
935 
936 #if defined(FEAT_CLIPBOARD) || defined(PROTO)
937 /*
938  * When "regname" is a clipboard register, obtain the selection.  If it's not
939  * available return zero, otherwise return "regname".
940  */
941     int
942 may_get_selection(int regname)
943 {
944     if (regname == '*')
945     {
946 	if (!clip_star.available)
947 	    regname = 0;
948 	else
949 	    clip_get_selection(&clip_star);
950     }
951     else if (regname == '+')
952     {
953 	if (!clip_plus.available)
954 	    regname = 0;
955 	else
956 	    clip_get_selection(&clip_plus);
957     }
958     return regname;
959 }
960 #endif
961 
962 /*
963  * Obtain the contents of a "normal" register. The register is made empty.
964  * The returned pointer has allocated memory, use put_register() later.
965  */
966     void *
967 get_register(
968     int		name,
969     int		copy)	/* make a copy, if FALSE make register empty. */
970 {
971     yankreg_T	*reg;
972     int		i;
973 
974 #ifdef FEAT_CLIPBOARD
975     /* When Visual area changed, may have to update selection.  Obtain the
976      * selection too. */
977     if (name == '*' && clip_star.available)
978     {
979 	if (clip_isautosel_star())
980 	    clip_update_selection(&clip_star);
981 	may_get_selection(name);
982     }
983     if (name == '+' && clip_plus.available)
984     {
985 	if (clip_isautosel_plus())
986 	    clip_update_selection(&clip_plus);
987 	may_get_selection(name);
988     }
989 #endif
990 
991     get_yank_register(name, 0);
992     reg = ALLOC_ONE(yankreg_T);
993     if (reg != NULL)
994     {
995 	*reg = *y_current;
996 	if (copy)
997 	{
998 	    /* If we run out of memory some or all of the lines are empty. */
999 	    if (reg->y_size == 0)
1000 		reg->y_array = NULL;
1001 	    else
1002 		reg->y_array = ALLOC_MULT(char_u *, reg->y_size);
1003 	    if (reg->y_array != NULL)
1004 	    {
1005 		for (i = 0; i < reg->y_size; ++i)
1006 		    reg->y_array[i] = vim_strsave(y_current->y_array[i]);
1007 	    }
1008 	}
1009 	else
1010 	    y_current->y_array = NULL;
1011     }
1012     return (void *)reg;
1013 }
1014 
1015 /*
1016  * Put "reg" into register "name".  Free any previous contents and "reg".
1017  */
1018     void
1019 put_register(int name, void *reg)
1020 {
1021     get_yank_register(name, 0);
1022     free_yank_all();
1023     *y_current = *(yankreg_T *)reg;
1024     vim_free(reg);
1025 
1026 #ifdef FEAT_CLIPBOARD
1027     /* Send text written to clipboard register to the clipboard. */
1028     may_set_selection();
1029 #endif
1030 }
1031 
1032 #if (defined(FEAT_CLIPBOARD) && defined(FEAT_X11) && defined(USE_SYSTEM)) \
1033 	|| defined(PROTO)
1034     void
1035 free_register(void *reg)
1036 {
1037     yankreg_T tmp;
1038 
1039     tmp = *y_current;
1040     *y_current = *(yankreg_T *)reg;
1041     free_yank_all();
1042     vim_free(reg);
1043     *y_current = tmp;
1044 }
1045 #endif
1046 
1047 #if defined(FEAT_MOUSE) || defined(PROTO)
1048 /*
1049  * return TRUE if the current yank register has type MLINE
1050  */
1051     int
1052 yank_register_mline(int regname)
1053 {
1054     if (regname != 0 && !valid_yank_reg(regname, FALSE))
1055 	return FALSE;
1056     if (regname == '_')		/* black hole is always empty */
1057 	return FALSE;
1058     get_yank_register(regname, FALSE);
1059     return (y_current->y_type == MLINE);
1060 }
1061 #endif
1062 
1063 /*
1064  * Start or stop recording into a yank register.
1065  *
1066  * Return FAIL for failure, OK otherwise.
1067  */
1068     int
1069 do_record(int c)
1070 {
1071     char_u	    *p;
1072     static int	    regname;
1073     yankreg_T	    *old_y_previous, *old_y_current;
1074     int		    retval;
1075 
1076     if (reg_recording == 0)	    /* start recording */
1077     {
1078 	/* registers 0-9, a-z and " are allowed */
1079 	if (c < 0 || (!ASCII_ISALNUM(c) && c != '"'))
1080 	    retval = FAIL;
1081 	else
1082 	{
1083 	    reg_recording = c;
1084 	    showmode();
1085 	    regname = c;
1086 	    retval = OK;
1087 	}
1088     }
1089     else			    /* stop recording */
1090     {
1091 	/*
1092 	 * Get the recorded key hits.  K_SPECIAL and CSI will be escaped, this
1093 	 * needs to be removed again to put it in a register.  exec_reg then
1094 	 * adds the escaping back later.
1095 	 */
1096 	reg_recording = 0;
1097 	msg("");
1098 	p = get_recorded();
1099 	if (p == NULL)
1100 	    retval = FAIL;
1101 	else
1102 	{
1103 	    /* Remove escaping for CSI and K_SPECIAL in multi-byte chars. */
1104 	    vim_unescape_csi(p);
1105 
1106 	    /*
1107 	     * We don't want to change the default register here, so save and
1108 	     * restore the current register name.
1109 	     */
1110 	    old_y_previous = y_previous;
1111 	    old_y_current = y_current;
1112 
1113 	    retval = stuff_yank(regname, p);
1114 
1115 	    y_previous = old_y_previous;
1116 	    y_current = old_y_current;
1117 	}
1118     }
1119     return retval;
1120 }
1121 
1122 /*
1123  * Stuff string "p" into yank register "regname" as a single line (append if
1124  * uppercase).	"p" must have been alloced.
1125  *
1126  * return FAIL for failure, OK otherwise
1127  */
1128     static int
1129 stuff_yank(int regname, char_u *p)
1130 {
1131     char_u	*lp;
1132     char_u	**pp;
1133 
1134     /* check for read-only register */
1135     if (regname != 0 && !valid_yank_reg(regname, TRUE))
1136     {
1137 	vim_free(p);
1138 	return FAIL;
1139     }
1140     if (regname == '_')		    /* black hole: don't do anything */
1141     {
1142 	vim_free(p);
1143 	return OK;
1144     }
1145     get_yank_register(regname, TRUE);
1146     if (y_append && y_current->y_array != NULL)
1147     {
1148 	pp = &(y_current->y_array[y_current->y_size - 1]);
1149 	lp = alloc(STRLEN(*pp) + STRLEN(p) + 1);
1150 	if (lp == NULL)
1151 	{
1152 	    vim_free(p);
1153 	    return FAIL;
1154 	}
1155 	STRCPY(lp, *pp);
1156 	STRCAT(lp, p);
1157 	vim_free(p);
1158 	vim_free(*pp);
1159 	*pp = lp;
1160     }
1161     else
1162     {
1163 	free_yank_all();
1164 	if ((y_current->y_array = ALLOC_ONE(char_u *)) == NULL)
1165 	{
1166 	    vim_free(p);
1167 	    return FAIL;
1168 	}
1169 	y_current->y_array[0] = p;
1170 	y_current->y_size = 1;
1171 	y_current->y_type = MCHAR;  /* used to be MLINE, why? */
1172 #ifdef FEAT_VIMINFO
1173 	y_current->y_time_set = vim_time();
1174 #endif
1175     }
1176     return OK;
1177 }
1178 
1179 static int execreg_lastc = NUL;
1180 
1181     int
1182 get_execreg_lastc(void)
1183 {
1184     return execreg_lastc;
1185 }
1186 
1187     void
1188 set_execreg_lastc(int lastc)
1189 {
1190     execreg_lastc = lastc;
1191 }
1192 
1193 /*
1194  * Execute a yank register: copy it into the stuff buffer.
1195  *
1196  * Return FAIL for failure, OK otherwise.
1197  */
1198     int
1199 do_execreg(
1200     int	    regname,
1201     int	    colon,		/* insert ':' before each line */
1202     int	    addcr,		/* always add '\n' to end of line */
1203     int	    silent)		/* set "silent" flag in typeahead buffer */
1204 {
1205     long	i;
1206     char_u	*p;
1207     int		retval = OK;
1208     int		remap;
1209 
1210     // repeat previous one
1211     if (regname == '@')
1212     {
1213 	if (execreg_lastc == NUL)
1214 	{
1215 	    emsg(_("E748: No previously used register"));
1216 	    return FAIL;
1217 	}
1218 	regname = execreg_lastc;
1219     }
1220     // check for valid regname
1221     if (regname == '%' || regname == '#' || !valid_yank_reg(regname, FALSE))
1222     {
1223 	emsg_invreg(regname);
1224 	return FAIL;
1225     }
1226     execreg_lastc = regname;
1227 
1228 #ifdef FEAT_CLIPBOARD
1229     regname = may_get_selection(regname);
1230 #endif
1231 
1232     // black hole: don't stuff anything
1233     if (regname == '_')
1234 	return OK;
1235 
1236 #ifdef FEAT_CMDHIST
1237     // use last command line
1238     if (regname == ':')
1239     {
1240 	if (last_cmdline == NULL)
1241 	{
1242 	    emsg(_(e_nolastcmd));
1243 	    return FAIL;
1244 	}
1245 	// don't keep the cmdline containing @:
1246 	VIM_CLEAR(new_last_cmdline);
1247 	// Escape all control characters with a CTRL-V
1248 	p = vim_strsave_escaped_ext(last_cmdline,
1249 		    (char_u *)"\001\002\003\004\005\006\007"
1250 			  "\010\011\012\013\014\015\016\017"
1251 			  "\020\021\022\023\024\025\026\027"
1252 			  "\030\031\032\033\034\035\036\037",
1253 		    Ctrl_V, FALSE);
1254 	if (p != NULL)
1255 	{
1256 	    /* When in Visual mode "'<,'>" will be prepended to the command.
1257 	     * Remove it when it's already there. */
1258 	    if (VIsual_active && STRNCMP(p, "'<,'>", 5) == 0)
1259 		retval = put_in_typebuf(p + 5, TRUE, TRUE, silent);
1260 	    else
1261 		retval = put_in_typebuf(p, TRUE, TRUE, silent);
1262 	}
1263 	vim_free(p);
1264     }
1265 #endif
1266 #ifdef FEAT_EVAL
1267     else if (regname == '=')
1268     {
1269 	p = get_expr_line();
1270 	if (p == NULL)
1271 	    return FAIL;
1272 	retval = put_in_typebuf(p, TRUE, colon, silent);
1273 	vim_free(p);
1274     }
1275 #endif
1276     else if (regname == '.')		/* use last inserted text */
1277     {
1278 	p = get_last_insert_save();
1279 	if (p == NULL)
1280 	{
1281 	    emsg(_(e_noinstext));
1282 	    return FAIL;
1283 	}
1284 	retval = put_in_typebuf(p, FALSE, colon, silent);
1285 	vim_free(p);
1286     }
1287     else
1288     {
1289 	get_yank_register(regname, FALSE);
1290 	if (y_current->y_array == NULL)
1291 	    return FAIL;
1292 
1293 	/* Disallow remaping for ":@r". */
1294 	remap = colon ? REMAP_NONE : REMAP_YES;
1295 
1296 	/*
1297 	 * Insert lines into typeahead buffer, from last one to first one.
1298 	 */
1299 	put_reedit_in_typebuf(silent);
1300 	for (i = y_current->y_size; --i >= 0; )
1301 	{
1302 	    char_u *escaped;
1303 
1304 	    /* insert NL between lines and after last line if type is MLINE */
1305 	    if (y_current->y_type == MLINE || i < y_current->y_size - 1
1306 								     || addcr)
1307 	    {
1308 		if (ins_typebuf((char_u *)"\n", remap, 0, TRUE, silent) == FAIL)
1309 		    return FAIL;
1310 	    }
1311 	    escaped = vim_strsave_escape_csi(y_current->y_array[i]);
1312 	    if (escaped == NULL)
1313 		return FAIL;
1314 	    retval = ins_typebuf(escaped, remap, 0, TRUE, silent);
1315 	    vim_free(escaped);
1316 	    if (retval == FAIL)
1317 		return FAIL;
1318 	    if (colon && ins_typebuf((char_u *)":", remap, 0, TRUE, silent)
1319 								      == FAIL)
1320 		return FAIL;
1321 	}
1322 	reg_executing = regname == 0 ? '"' : regname; // disable "q" command
1323     }
1324     return retval;
1325 }
1326 
1327 /*
1328  * If "restart_edit" is not zero, put it in the typeahead buffer, so that it's
1329  * used only after other typeahead has been processed.
1330  */
1331     static void
1332 put_reedit_in_typebuf(int silent)
1333 {
1334     char_u	buf[3];
1335 
1336     if (restart_edit != NUL)
1337     {
1338 	if (restart_edit == 'V')
1339 	{
1340 	    buf[0] = 'g';
1341 	    buf[1] = 'R';
1342 	    buf[2] = NUL;
1343 	}
1344 	else
1345 	{
1346 	    buf[0] = restart_edit == 'I' ? 'i' : restart_edit;
1347 	    buf[1] = NUL;
1348 	}
1349 	if (ins_typebuf(buf, REMAP_NONE, 0, TRUE, silent) == OK)
1350 	    restart_edit = NUL;
1351     }
1352 }
1353 
1354 /*
1355  * Insert register contents "s" into the typeahead buffer, so that it will be
1356  * executed again.
1357  * When "esc" is TRUE it is to be taken literally: Escape CSI characters and
1358  * no remapping.
1359  */
1360     static int
1361 put_in_typebuf(
1362     char_u	*s,
1363     int		esc,
1364     int		colon,	    /* add ':' before the line */
1365     int		silent)
1366 {
1367     int		retval = OK;
1368 
1369     put_reedit_in_typebuf(silent);
1370     if (colon)
1371 	retval = ins_typebuf((char_u *)"\n", REMAP_NONE, 0, TRUE, silent);
1372     if (retval == OK)
1373     {
1374 	char_u	*p;
1375 
1376 	if (esc)
1377 	    p = vim_strsave_escape_csi(s);
1378 	else
1379 	    p = s;
1380 	if (p == NULL)
1381 	    retval = FAIL;
1382 	else
1383 	    retval = ins_typebuf(p, esc ? REMAP_NONE : REMAP_YES,
1384 							     0, TRUE, silent);
1385 	if (esc)
1386 	    vim_free(p);
1387     }
1388     if (colon && retval == OK)
1389 	retval = ins_typebuf((char_u *)":", REMAP_NONE, 0, TRUE, silent);
1390     return retval;
1391 }
1392 
1393 /*
1394  * Insert a yank register: copy it into the Read buffer.
1395  * Used by CTRL-R command and middle mouse button in insert mode.
1396  *
1397  * return FAIL for failure, OK otherwise
1398  */
1399     int
1400 insert_reg(
1401     int		regname,
1402     int		literally_arg)	/* insert literally, not as if typed */
1403 {
1404     long	i;
1405     int		retval = OK;
1406     char_u	*arg;
1407     int		allocated;
1408     int		literally = literally_arg;
1409 
1410     /*
1411      * It is possible to get into an endless loop by having CTRL-R a in
1412      * register a and then, in insert mode, doing CTRL-R a.
1413      * If you hit CTRL-C, the loop will be broken here.
1414      */
1415     ui_breakcheck();
1416     if (got_int)
1417 	return FAIL;
1418 
1419     /* check for valid regname */
1420     if (regname != NUL && !valid_yank_reg(regname, FALSE))
1421 	return FAIL;
1422 
1423 #ifdef FEAT_CLIPBOARD
1424     regname = may_get_selection(regname);
1425 #endif
1426 
1427     if (regname == '.')			/* insert last inserted text */
1428 	retval = stuff_inserted(NUL, 1L, TRUE);
1429     else if (get_spec_reg(regname, &arg, &allocated, TRUE))
1430     {
1431 	if (arg == NULL)
1432 	    return FAIL;
1433 	stuffescaped(arg, literally);
1434 	if (allocated)
1435 	    vim_free(arg);
1436     }
1437     else				/* name or number register */
1438     {
1439 	if (get_yank_register(regname, FALSE))
1440 	    literally = TRUE;
1441 	if (y_current->y_array == NULL)
1442 	    retval = FAIL;
1443 	else
1444 	{
1445 	    for (i = 0; i < y_current->y_size; ++i)
1446 	    {
1447 		stuffescaped(y_current->y_array[i], literally);
1448 		/*
1449 		 * Insert a newline between lines and after last line if
1450 		 * y_type is MLINE.
1451 		 */
1452 		if (y_current->y_type == MLINE || i < y_current->y_size - 1)
1453 		    stuffcharReadbuff('\n');
1454 	    }
1455 	}
1456     }
1457 
1458     return retval;
1459 }
1460 
1461 /*
1462  * Stuff a string into the typeahead buffer, such that edit() will insert it
1463  * literally ("literally" TRUE) or interpret is as typed characters.
1464  */
1465     static void
1466 stuffescaped(char_u *arg, int literally)
1467 {
1468     int		c;
1469     char_u	*start;
1470 
1471     while (*arg != NUL)
1472     {
1473 	/* Stuff a sequence of normal ASCII characters, that's fast.  Also
1474 	 * stuff K_SPECIAL to get the effect of a special key when "literally"
1475 	 * is TRUE. */
1476 	start = arg;
1477 	while ((*arg >= ' '
1478 #ifndef EBCDIC
1479 		    && *arg < DEL /* EBCDIC: chars above space are normal */
1480 #endif
1481 		    )
1482 		|| (*arg == K_SPECIAL && !literally))
1483 	    ++arg;
1484 	if (arg > start)
1485 	    stuffReadbuffLen(start, (long)(arg - start));
1486 
1487 	/* stuff a single special character */
1488 	if (*arg != NUL)
1489 	{
1490 	    if (has_mbyte)
1491 		c = mb_cptr2char_adv(&arg);
1492 	    else
1493 		c = *arg++;
1494 	    if (literally && ((c < ' ' && c != TAB) || c == DEL))
1495 		stuffcharReadbuff(Ctrl_V);
1496 	    stuffcharReadbuff(c);
1497 	}
1498     }
1499 }
1500 
1501 /*
1502  * If "regname" is a special register, return TRUE and store a pointer to its
1503  * value in "argp".
1504  */
1505     int
1506 get_spec_reg(
1507     int		regname,
1508     char_u	**argp,
1509     int		*allocated,	/* return: TRUE when value was allocated */
1510     int		errmsg)		/* give error message when failing */
1511 {
1512     int		cnt;
1513 
1514     *argp = NULL;
1515     *allocated = FALSE;
1516     switch (regname)
1517     {
1518 	case '%':		/* file name */
1519 	    if (errmsg)
1520 		check_fname();	/* will give emsg if not set */
1521 	    *argp = curbuf->b_fname;
1522 	    return TRUE;
1523 
1524 	case '#':		/* alternate file name */
1525 	    *argp = getaltfname(errmsg);	/* may give emsg if not set */
1526 	    return TRUE;
1527 
1528 #ifdef FEAT_EVAL
1529 	case '=':		/* result of expression */
1530 	    *argp = get_expr_line();
1531 	    *allocated = TRUE;
1532 	    return TRUE;
1533 #endif
1534 
1535 	case ':':		/* last command line */
1536 	    if (last_cmdline == NULL && errmsg)
1537 		emsg(_(e_nolastcmd));
1538 	    *argp = last_cmdline;
1539 	    return TRUE;
1540 
1541 	case '/':		/* last search-pattern */
1542 	    if (last_search_pat() == NULL && errmsg)
1543 		emsg(_(e_noprevre));
1544 	    *argp = last_search_pat();
1545 	    return TRUE;
1546 
1547 	case '.':		/* last inserted text */
1548 	    *argp = get_last_insert_save();
1549 	    *allocated = TRUE;
1550 	    if (*argp == NULL && errmsg)
1551 		emsg(_(e_noinstext));
1552 	    return TRUE;
1553 
1554 #ifdef FEAT_SEARCHPATH
1555 	case Ctrl_F:		/* Filename under cursor */
1556 	case Ctrl_P:		/* Path under cursor, expand via "path" */
1557 	    if (!errmsg)
1558 		return FALSE;
1559 	    *argp = file_name_at_cursor(FNAME_MESS | FNAME_HYP
1560 			    | (regname == Ctrl_P ? FNAME_EXP : 0), 1L, NULL);
1561 	    *allocated = TRUE;
1562 	    return TRUE;
1563 #endif
1564 
1565 	case Ctrl_W:		/* word under cursor */
1566 	case Ctrl_A:		/* WORD (mnemonic All) under cursor */
1567 	    if (!errmsg)
1568 		return FALSE;
1569 	    cnt = find_ident_under_cursor(argp, regname == Ctrl_W
1570 				   ?  (FIND_IDENT|FIND_STRING) : FIND_STRING);
1571 	    *argp = cnt ? vim_strnsave(*argp, cnt) : NULL;
1572 	    *allocated = TRUE;
1573 	    return TRUE;
1574 
1575 	case Ctrl_L:		/* Line under cursor */
1576 	    if (!errmsg)
1577 		return FALSE;
1578 
1579 	    *argp = ml_get_buf(curwin->w_buffer,
1580 			curwin->w_cursor.lnum, FALSE);
1581 	    return TRUE;
1582 
1583 	case '_':		/* black hole: always empty */
1584 	    *argp = (char_u *)"";
1585 	    return TRUE;
1586     }
1587 
1588     return FALSE;
1589 }
1590 
1591 /*
1592  * Paste a yank register into the command line.
1593  * Only for non-special registers.
1594  * Used by CTRL-R command in command-line mode
1595  * insert_reg() can't be used here, because special characters from the
1596  * register contents will be interpreted as commands.
1597  *
1598  * return FAIL for failure, OK otherwise
1599  */
1600     int
1601 cmdline_paste_reg(
1602     int regname,
1603     int literally_arg,	/* Insert text literally instead of "as typed" */
1604     int remcr)		/* don't add CR characters */
1605 {
1606     long	i;
1607     int		literally = literally_arg;
1608 
1609     if (get_yank_register(regname, FALSE))
1610 	literally = TRUE;
1611     if (y_current->y_array == NULL)
1612 	return FAIL;
1613 
1614     for (i = 0; i < y_current->y_size; ++i)
1615     {
1616 	cmdline_paste_str(y_current->y_array[i], literally);
1617 
1618 	/* Insert ^M between lines and after last line if type is MLINE.
1619 	 * Don't do this when "remcr" is TRUE. */
1620 	if ((y_current->y_type == MLINE || i < y_current->y_size - 1) && !remcr)
1621 	    cmdline_paste_str((char_u *)"\r", literally);
1622 
1623 	/* Check for CTRL-C, in case someone tries to paste a few thousand
1624 	 * lines and gets bored. */
1625 	ui_breakcheck();
1626 	if (got_int)
1627 	    return FAIL;
1628     }
1629     return OK;
1630 }
1631 
1632 #if defined(FEAT_CLIPBOARD) || defined(PROTO)
1633 /*
1634  * Adjust the register name pointed to with "rp" for the clipboard being
1635  * used always and the clipboard being available.
1636  */
1637     void
1638 adjust_clip_reg(int *rp)
1639 {
1640     /* If no reg. specified, and "unnamed" or "unnamedplus" is in 'clipboard',
1641      * use '*' or '+' reg, respectively. "unnamedplus" prevails. */
1642     if (*rp == 0 && (clip_unnamed != 0 || clip_unnamed_saved != 0))
1643     {
1644 	if (clip_unnamed != 0)
1645 	    *rp = ((clip_unnamed & CLIP_UNNAMED_PLUS) && clip_plus.available)
1646 								  ? '+' : '*';
1647 	else
1648 	    *rp = ((clip_unnamed_saved & CLIP_UNNAMED_PLUS) && clip_plus.available)
1649 								  ? '+' : '*';
1650     }
1651     if (!clip_star.available && *rp == '*')
1652 	*rp = 0;
1653     if (!clip_plus.available && *rp == '+')
1654 	*rp = 0;
1655 }
1656 #endif
1657 
1658 /*
1659  * Shift the delete registers: "9 is cleared, "8 becomes "9, etc.
1660  */
1661     void
1662 shift_delete_registers()
1663 {
1664     int		n;
1665 
1666     y_current = &y_regs[9];
1667     free_yank_all();			/* free register nine */
1668     for (n = 9; n > 1; --n)
1669 	y_regs[n] = y_regs[n - 1];
1670     y_current = &y_regs[1];
1671     if (!y_append)
1672 	y_previous = y_current;
1673     y_regs[1].y_array = NULL;		/* set register one to empty */
1674 }
1675 
1676 #if defined(FEAT_EVAL)
1677     static void
1678 yank_do_autocmd(oparg_T *oap, yankreg_T *reg)
1679 {
1680     static int	recursive = FALSE;
1681     dict_T	*v_event;
1682     list_T	*list;
1683     int		n;
1684     char_u	buf[NUMBUFLEN + 2];
1685     long	reglen = 0;
1686 
1687     if (recursive)
1688 	return;
1689 
1690     v_event = get_vim_var_dict(VV_EVENT);
1691 
1692     list = list_alloc();
1693     if (list == NULL)
1694 	return;
1695     for (n = 0; n < reg->y_size; n++)
1696 	list_append_string(list, reg->y_array[n], -1);
1697     list->lv_lock = VAR_FIXED;
1698     dict_add_list(v_event, "regcontents", list);
1699 
1700     buf[0] = (char_u)oap->regname;
1701     buf[1] = NUL;
1702     dict_add_string(v_event, "regname", buf);
1703 
1704     buf[0] = get_op_char(oap->op_type);
1705     buf[1] = get_extra_op_char(oap->op_type);
1706     buf[2] = NUL;
1707     dict_add_string(v_event, "operator", buf);
1708 
1709     buf[0] = NUL;
1710     buf[1] = NUL;
1711     switch (get_reg_type(oap->regname, &reglen))
1712     {
1713 	case MLINE: buf[0] = 'V'; break;
1714 	case MCHAR: buf[0] = 'v'; break;
1715 	case MBLOCK:
1716 		vim_snprintf((char *)buf, sizeof(buf), "%c%ld", Ctrl_V,
1717 			     reglen + 1);
1718 		break;
1719     }
1720     dict_add_string(v_event, "regtype", buf);
1721 
1722     /* Lock the dictionary and its keys */
1723     dict_set_items_ro(v_event);
1724 
1725     recursive = TRUE;
1726     textlock++;
1727     apply_autocmds(EVENT_TEXTYANKPOST, NULL, NULL, FALSE, curbuf);
1728     textlock--;
1729     recursive = FALSE;
1730 
1731     /* Empty the dictionary, v:event is still valid */
1732     dict_free_contents(v_event);
1733     hash_init(&v_event->dv_hashtab);
1734 }
1735 #endif
1736 
1737 /*
1738  * Handle a delete operation.
1739  *
1740  * Return FAIL if undo failed, OK otherwise.
1741  */
1742     int
1743 op_delete(oparg_T *oap)
1744 {
1745     int			n;
1746     linenr_T		lnum;
1747     char_u		*ptr;
1748     char_u		*newp, *oldp;
1749     struct block_def	bd;
1750     linenr_T		old_lcount = curbuf->b_ml.ml_line_count;
1751     int			did_yank = FALSE;
1752 
1753     if (curbuf->b_ml.ml_flags & ML_EMPTY)	    /* nothing to do */
1754 	return OK;
1755 
1756     /* Nothing to delete, return here.	Do prepare undo, for op_change(). */
1757     if (oap->empty)
1758 	return u_save_cursor();
1759 
1760     if (!curbuf->b_p_ma)
1761     {
1762 	emsg(_(e_modifiable));
1763 	return FAIL;
1764     }
1765 
1766 #ifdef FEAT_CLIPBOARD
1767     adjust_clip_reg(&oap->regname);
1768 #endif
1769 
1770     if (has_mbyte)
1771 	mb_adjust_opend(oap);
1772 
1773     /*
1774      * Imitate the strange Vi behaviour: If the delete spans more than one
1775      * line and motion_type == MCHAR and the result is a blank line, make the
1776      * delete linewise.  Don't do this for the change command or Visual mode.
1777      */
1778     if (       oap->motion_type == MCHAR
1779 	    && !oap->is_VIsual
1780 	    && !oap->block_mode
1781 	    && oap->line_count > 1
1782 	    && oap->motion_force == NUL
1783 	    && oap->op_type == OP_DELETE)
1784     {
1785 	ptr = ml_get(oap->end.lnum) + oap->end.col;
1786 	if (*ptr != NUL)
1787 	    ptr += oap->inclusive;
1788 	ptr = skipwhite(ptr);
1789 	if (*ptr == NUL && inindent(0))
1790 	    oap->motion_type = MLINE;
1791     }
1792 
1793     /*
1794      * Check for trying to delete (e.g. "D") in an empty line.
1795      * Note: For the change operator it is ok.
1796      */
1797     if (       oap->motion_type == MCHAR
1798 	    && oap->line_count == 1
1799 	    && oap->op_type == OP_DELETE
1800 	    && *ml_get(oap->start.lnum) == NUL)
1801     {
1802 	/*
1803 	 * It's an error to operate on an empty region, when 'E' included in
1804 	 * 'cpoptions' (Vi compatible).
1805 	 */
1806 	if (virtual_op)
1807 	    /* Virtual editing: Nothing gets deleted, but we set the '[ and ']
1808 	     * marks as if it happened. */
1809 	    goto setmarks;
1810 	if (vim_strchr(p_cpo, CPO_EMPTYREGION) != NULL)
1811 	    beep_flush();
1812 	return OK;
1813     }
1814 
1815     /*
1816      * Do a yank of whatever we're about to delete.
1817      * If a yank register was specified, put the deleted text into that
1818      * register.  For the black hole register '_' don't yank anything.
1819      */
1820     if (oap->regname != '_')
1821     {
1822 	if (oap->regname != 0)
1823 	{
1824 	    /* check for read-only register */
1825 	    if (!valid_yank_reg(oap->regname, TRUE))
1826 	    {
1827 		beep_flush();
1828 		return OK;
1829 	    }
1830 	    get_yank_register(oap->regname, TRUE); /* yank into specif'd reg. */
1831 	    if (op_yank(oap, TRUE, FALSE) == OK)   /* yank without message */
1832 		did_yank = TRUE;
1833 	}
1834 
1835 	/*
1836 	 * Put deleted text into register 1 and shift number registers if the
1837 	 * delete contains a line break, or when using a specific operator (Vi
1838 	 * compatible)
1839 	 * Use the register name from before adjust_clip_reg() may have
1840 	 * changed it.
1841 	 */
1842 	if (oap->motion_type == MLINE || oap->line_count > 1
1843 							   || oap->use_reg_one)
1844 	{
1845 	    shift_delete_registers();
1846 	    if (op_yank(oap, TRUE, FALSE) == OK)
1847 		did_yank = TRUE;
1848 	}
1849 
1850 	/* Yank into small delete register when no named register specified
1851 	 * and the delete is within one line. */
1852 	if ((
1853 #ifdef FEAT_CLIPBOARD
1854 	    ((clip_unnamed & CLIP_UNNAMED) && oap->regname == '*') ||
1855 	    ((clip_unnamed & CLIP_UNNAMED_PLUS) && oap->regname == '+') ||
1856 #endif
1857 	    oap->regname == 0) && oap->motion_type != MLINE
1858 						      && oap->line_count == 1)
1859 	{
1860 	    oap->regname = '-';
1861 	    get_yank_register(oap->regname, TRUE);
1862 	    if (op_yank(oap, TRUE, FALSE) == OK)
1863 		did_yank = TRUE;
1864 	    oap->regname = 0;
1865 	}
1866 
1867 	/*
1868 	 * If there's too much stuff to fit in the yank register, then get a
1869 	 * confirmation before doing the delete. This is crude, but simple.
1870 	 * And it avoids doing a delete of something we can't put back if we
1871 	 * want.
1872 	 */
1873 	if (!did_yank)
1874 	{
1875 	    int msg_silent_save = msg_silent;
1876 
1877 	    msg_silent = 0;	/* must display the prompt */
1878 	    n = ask_yesno((char_u *)_("cannot yank; delete anyway"), TRUE);
1879 	    msg_silent = msg_silent_save;
1880 	    if (n != 'y')
1881 	    {
1882 		emsg(_(e_abort));
1883 		return FAIL;
1884 	    }
1885 	}
1886 
1887 #if defined(FEAT_EVAL)
1888 	if (did_yank && has_textyankpost())
1889 	    yank_do_autocmd(oap, y_current);
1890 #endif
1891     }
1892 
1893     /*
1894      * block mode delete
1895      */
1896     if (oap->block_mode)
1897     {
1898 	if (u_save((linenr_T)(oap->start.lnum - 1),
1899 			       (linenr_T)(oap->end.lnum + 1)) == FAIL)
1900 	    return FAIL;
1901 
1902 	for (lnum = curwin->w_cursor.lnum; lnum <= oap->end.lnum; ++lnum)
1903 	{
1904 	    block_prep(oap, &bd, lnum, TRUE);
1905 	    if (bd.textlen == 0)	/* nothing to delete */
1906 		continue;
1907 
1908 	    /* Adjust cursor position for tab replaced by spaces and 'lbr'. */
1909 	    if (lnum == curwin->w_cursor.lnum)
1910 	    {
1911 		curwin->w_cursor.col = bd.textcol + bd.startspaces;
1912 		curwin->w_cursor.coladd = 0;
1913 	    }
1914 
1915 	    // "n" == number of chars deleted
1916 	    // If we delete a TAB, it may be replaced by several characters.
1917 	    // Thus the number of characters may increase!
1918 	    n = bd.textlen - bd.startspaces - bd.endspaces;
1919 	    oldp = ml_get(lnum);
1920 	    newp = alloc(STRLEN(oldp) + 1 - n);
1921 	    if (newp == NULL)
1922 		continue;
1923 	    /* copy up to deleted part */
1924 	    mch_memmove(newp, oldp, (size_t)bd.textcol);
1925 	    /* insert spaces */
1926 	    vim_memset(newp + bd.textcol, ' ',
1927 				     (size_t)(bd.startspaces + bd.endspaces));
1928 	    /* copy the part after the deleted part */
1929 	    oldp += bd.textcol + bd.textlen;
1930 	    STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp);
1931 	    /* replace the line */
1932 	    ml_replace(lnum, newp, FALSE);
1933 
1934 #ifdef FEAT_TEXT_PROP
1935 	    if (curbuf->b_has_textprop && n != 0)
1936 		adjust_prop_columns(lnum, bd.textcol, -n, 0);
1937 #endif
1938 	}
1939 
1940 	check_cursor_col();
1941 	changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
1942 						       oap->end.lnum + 1, 0L);
1943 	oap->line_count = 0;	    /* no lines deleted */
1944     }
1945     else if (oap->motion_type == MLINE)
1946     {
1947 	if (oap->op_type == OP_CHANGE)
1948 	{
1949 	    /* Delete the lines except the first one.  Temporarily move the
1950 	     * cursor to the next line.  Save the current line number, if the
1951 	     * last line is deleted it may be changed.
1952 	     */
1953 	    if (oap->line_count > 1)
1954 	    {
1955 		lnum = curwin->w_cursor.lnum;
1956 		++curwin->w_cursor.lnum;
1957 		del_lines((long)(oap->line_count - 1), TRUE);
1958 		curwin->w_cursor.lnum = lnum;
1959 	    }
1960 	    if (u_save_cursor() == FAIL)
1961 		return FAIL;
1962 	    if (curbuf->b_p_ai)		    /* don't delete indent */
1963 	    {
1964 		beginline(BL_WHITE);	    /* cursor on first non-white */
1965 		did_ai = TRUE;		    /* delete the indent when ESC hit */
1966 		ai_col = curwin->w_cursor.col;
1967 	    }
1968 	    else
1969 		beginline(0);		    /* cursor in column 0 */
1970 	    truncate_line(FALSE);   /* delete the rest of the line */
1971 				    /* leave cursor past last char in line */
1972 	    if (oap->line_count > 1)
1973 		u_clearline();	    /* "U" command not possible after "2cc" */
1974 	}
1975 	else
1976 	{
1977 	    del_lines(oap->line_count, TRUE);
1978 	    beginline(BL_WHITE | BL_FIX);
1979 	    u_clearline();	/* "U" command not possible after "dd" */
1980 	}
1981     }
1982     else
1983     {
1984 	if (virtual_op)
1985 	{
1986 	    int		endcol = 0;
1987 
1988 	    /* For virtualedit: break the tabs that are partly included. */
1989 	    if (gchar_pos(&oap->start) == '\t')
1990 	    {
1991 		if (u_save_cursor() == FAIL)	/* save first line for undo */
1992 		    return FAIL;
1993 		if (oap->line_count == 1)
1994 		    endcol = getviscol2(oap->end.col, oap->end.coladd);
1995 		coladvance_force(getviscol2(oap->start.col, oap->start.coladd));
1996 		oap->start = curwin->w_cursor;
1997 		if (oap->line_count == 1)
1998 		{
1999 		    coladvance(endcol);
2000 		    oap->end.col = curwin->w_cursor.col;
2001 		    oap->end.coladd = curwin->w_cursor.coladd;
2002 		    curwin->w_cursor = oap->start;
2003 		}
2004 	    }
2005 
2006 	    /* Break a tab only when it's included in the area. */
2007 	    if (gchar_pos(&oap->end) == '\t'
2008 				     && (int)oap->end.coladd < oap->inclusive)
2009 	    {
2010 		/* save last line for undo */
2011 		if (u_save((linenr_T)(oap->end.lnum - 1),
2012 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
2013 		    return FAIL;
2014 		curwin->w_cursor = oap->end;
2015 		coladvance_force(getviscol2(oap->end.col, oap->end.coladd));
2016 		oap->end = curwin->w_cursor;
2017 		curwin->w_cursor = oap->start;
2018 	    }
2019 	}
2020 
2021 	if (oap->line_count == 1)	/* delete characters within one line */
2022 	{
2023 	    if (u_save_cursor() == FAIL)	/* save line for undo */
2024 		return FAIL;
2025 
2026 	    /* if 'cpoptions' contains '$', display '$' at end of change */
2027 	    if (       vim_strchr(p_cpo, CPO_DOLLAR) != NULL
2028 		    && oap->op_type == OP_CHANGE
2029 		    && oap->end.lnum == curwin->w_cursor.lnum
2030 		    && !oap->is_VIsual)
2031 		display_dollar(oap->end.col - !oap->inclusive);
2032 
2033 	    n = oap->end.col - oap->start.col + 1 - !oap->inclusive;
2034 
2035 	    if (virtual_op)
2036 	    {
2037 		/* fix up things for virtualedit-delete:
2038 		 * break the tabs which are going to get in our way
2039 		 */
2040 		char_u		*curline = ml_get_curline();
2041 		int		len = (int)STRLEN(curline);
2042 
2043 		if (oap->end.coladd != 0
2044 			&& (int)oap->end.col >= len - 1
2045 			&& !(oap->start.coladd && (int)oap->end.col >= len - 1))
2046 		    n++;
2047 		/* Delete at least one char (e.g, when on a control char). */
2048 		if (n == 0 && oap->start.coladd != oap->end.coladd)
2049 		    n = 1;
2050 
2051 		/* When deleted a char in the line, reset coladd. */
2052 		if (gchar_cursor() != NUL)
2053 		    curwin->w_cursor.coladd = 0;
2054 	    }
2055 	    (void)del_bytes((long)n, !virtual_op,
2056 			    oap->op_type == OP_DELETE && !oap->is_VIsual);
2057 	}
2058 	else				/* delete characters between lines */
2059 	{
2060 	    pos_T   curpos;
2061 
2062 	    /* save deleted and changed lines for undo */
2063 	    if (u_save((linenr_T)(curwin->w_cursor.lnum - 1),
2064 		 (linenr_T)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
2065 		return FAIL;
2066 
2067 	    truncate_line(TRUE);	/* delete from cursor to end of line */
2068 
2069 	    curpos = curwin->w_cursor;	/* remember curwin->w_cursor */
2070 	    ++curwin->w_cursor.lnum;
2071 	    del_lines((long)(oap->line_count - 2), FALSE);
2072 
2073 	    /* delete from start of line until op_end */
2074 	    n = (oap->end.col + 1 - !oap->inclusive);
2075 	    curwin->w_cursor.col = 0;
2076 	    (void)del_bytes((long)n, !virtual_op,
2077 			    oap->op_type == OP_DELETE && !oap->is_VIsual);
2078 	    curwin->w_cursor = curpos;	/* restore curwin->w_cursor */
2079 	    (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
2080 	}
2081     }
2082 
2083     msgmore(curbuf->b_ml.ml_line_count - old_lcount);
2084 
2085 setmarks:
2086     if (oap->block_mode)
2087     {
2088 	curbuf->b_op_end.lnum = oap->end.lnum;
2089 	curbuf->b_op_end.col = oap->start.col;
2090     }
2091     else
2092 	curbuf->b_op_end = oap->start;
2093     curbuf->b_op_start = oap->start;
2094 
2095     return OK;
2096 }
2097 
2098 /*
2099  * Adjust end of operating area for ending on a multi-byte character.
2100  * Used for deletion.
2101  */
2102     static void
2103 mb_adjust_opend(oparg_T *oap)
2104 {
2105     char_u	*p;
2106 
2107     if (oap->inclusive)
2108     {
2109 	p = ml_get(oap->end.lnum);
2110 	oap->end.col += mb_tail_off(p, p + oap->end.col);
2111     }
2112 }
2113 
2114 /*
2115  * Replace the character under the cursor with "c".
2116  * This takes care of multi-byte characters.
2117  */
2118     static void
2119 replace_character(int c)
2120 {
2121     int n = State;
2122 
2123     State = REPLACE;
2124     ins_char(c);
2125     State = n;
2126     /* Backup to the replaced character. */
2127     dec_cursor();
2128 }
2129 
2130 /*
2131  * Replace a whole area with one character.
2132  */
2133     int
2134 op_replace(oparg_T *oap, int c)
2135 {
2136     int			n, numc;
2137     int			num_chars;
2138     char_u		*newp, *oldp;
2139     size_t		oldlen;
2140     struct block_def	bd;
2141     char_u		*after_p = NULL;
2142     int			had_ctrl_v_cr = FALSE;
2143 
2144     if ((curbuf->b_ml.ml_flags & ML_EMPTY ) || oap->empty)
2145 	return OK;	    /* nothing to do */
2146 
2147     if (c == REPLACE_CR_NCHAR)
2148     {
2149 	had_ctrl_v_cr = TRUE;
2150 	c = CAR;
2151     }
2152     else if (c == REPLACE_NL_NCHAR)
2153     {
2154 	had_ctrl_v_cr = TRUE;
2155 	c = NL;
2156     }
2157 
2158     if (has_mbyte)
2159 	mb_adjust_opend(oap);
2160 
2161     if (u_save((linenr_T)(oap->start.lnum - 1),
2162 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
2163 	return FAIL;
2164 
2165     /*
2166      * block mode replace
2167      */
2168     if (oap->block_mode)
2169     {
2170 	bd.is_MAX = (curwin->w_curswant == MAXCOL);
2171 	for ( ; curwin->w_cursor.lnum <= oap->end.lnum; ++curwin->w_cursor.lnum)
2172 	{
2173 	    curwin->w_cursor.col = 0;  /* make sure cursor position is valid */
2174 	    block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);
2175 	    if (bd.textlen == 0 && (!virtual_op || bd.is_MAX))
2176 		continue;	    /* nothing to replace */
2177 
2178 	    /* n == number of extra chars required
2179 	     * If we split a TAB, it may be replaced by several characters.
2180 	     * Thus the number of characters may increase!
2181 	     */
2182 	    /* If the range starts in virtual space, count the initial
2183 	     * coladd offset as part of "startspaces" */
2184 	    if (virtual_op && bd.is_short && *bd.textstart == NUL)
2185 	    {
2186 		pos_T vpos;
2187 
2188 		vpos.lnum = curwin->w_cursor.lnum;
2189 		getvpos(&vpos, oap->start_vcol);
2190 		bd.startspaces += vpos.coladd;
2191 		n = bd.startspaces;
2192 	    }
2193 	    else
2194 		/* allow for pre spaces */
2195 		n = (bd.startspaces ? bd.start_char_vcols - 1 : 0);
2196 
2197 	    /* allow for post spp */
2198 	    n += (bd.endspaces
2199 		    && !bd.is_oneChar
2200 		    && bd.end_char_vcols > 0) ? bd.end_char_vcols - 1 : 0;
2201 	    /* Figure out how many characters to replace. */
2202 	    numc = oap->end_vcol - oap->start_vcol + 1;
2203 	    if (bd.is_short && (!virtual_op || bd.is_MAX))
2204 		numc -= (oap->end_vcol - bd.end_vcol) + 1;
2205 
2206 	    /* A double-wide character can be replaced only up to half the
2207 	     * times. */
2208 	    if ((*mb_char2cells)(c) > 1)
2209 	    {
2210 		if ((numc & 1) && !bd.is_short)
2211 		{
2212 		    ++bd.endspaces;
2213 		    ++n;
2214 		}
2215 		numc = numc / 2;
2216 	    }
2217 
2218 	    /* Compute bytes needed, move character count to num_chars. */
2219 	    num_chars = numc;
2220 	    numc *= (*mb_char2len)(c);
2221 	    /* oldlen includes textlen, so don't double count */
2222 	    n += numc - bd.textlen;
2223 
2224 	    oldp = ml_get_curline();
2225 	    oldlen = STRLEN(oldp);
2226 	    newp = alloc(oldlen + 1 + n);
2227 	    if (newp == NULL)
2228 		continue;
2229 	    vim_memset(newp, NUL, (size_t)(oldlen + 1 + n));
2230 	    /* copy up to deleted part */
2231 	    mch_memmove(newp, oldp, (size_t)bd.textcol);
2232 	    oldp += bd.textcol + bd.textlen;
2233 	    /* insert pre-spaces */
2234 	    vim_memset(newp + bd.textcol, ' ', (size_t)bd.startspaces);
2235 	    /* insert replacement chars CHECK FOR ALLOCATED SPACE */
2236 	    /* REPLACE_CR_NCHAR/REPLACE_NL_NCHAR is used for entering CR
2237 	     * literally. */
2238 	    if (had_ctrl_v_cr || (c != '\r' && c != '\n'))
2239 	    {
2240 		if (has_mbyte)
2241 		{
2242 		    n = (int)STRLEN(newp);
2243 		    while (--num_chars >= 0)
2244 			n += (*mb_char2bytes)(c, newp + n);
2245 		}
2246 		else
2247 		    vim_memset(newp + STRLEN(newp), c, (size_t)numc);
2248 		if (!bd.is_short)
2249 		{
2250 		    /* insert post-spaces */
2251 		    vim_memset(newp + STRLEN(newp), ' ', (size_t)bd.endspaces);
2252 		    /* copy the part after the changed part */
2253 		    STRMOVE(newp + STRLEN(newp), oldp);
2254 		}
2255 	    }
2256 	    else
2257 	    {
2258 		/* Replacing with \r or \n means splitting the line. */
2259 		after_p = alloc(oldlen + 1 + n - STRLEN(newp));
2260 		if (after_p != NULL)
2261 		    STRMOVE(after_p, oldp);
2262 	    }
2263 	    /* replace the line */
2264 	    ml_replace(curwin->w_cursor.lnum, newp, FALSE);
2265 	    if (after_p != NULL)
2266 	    {
2267 		ml_append(curwin->w_cursor.lnum++, after_p, 0, FALSE);
2268 		appended_lines_mark(curwin->w_cursor.lnum, 1L);
2269 		oap->end.lnum++;
2270 		vim_free(after_p);
2271 	    }
2272 	}
2273     }
2274     else
2275     {
2276 	/*
2277 	 * MCHAR and MLINE motion replace.
2278 	 */
2279 	if (oap->motion_type == MLINE)
2280 	{
2281 	    oap->start.col = 0;
2282 	    curwin->w_cursor.col = 0;
2283 	    oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
2284 	    if (oap->end.col)
2285 		--oap->end.col;
2286 	}
2287 	else if (!oap->inclusive)
2288 	    dec(&(oap->end));
2289 
2290 	while (LTOREQ_POS(curwin->w_cursor, oap->end))
2291 	{
2292 	    n = gchar_cursor();
2293 	    if (n != NUL)
2294 	    {
2295 		if ((*mb_char2len)(c) > 1 || (*mb_char2len)(n) > 1)
2296 		{
2297 		    /* This is slow, but it handles replacing a single-byte
2298 		     * with a multi-byte and the other way around. */
2299 		    if (curwin->w_cursor.lnum == oap->end.lnum)
2300 			oap->end.col += (*mb_char2len)(c) - (*mb_char2len)(n);
2301 		    replace_character(c);
2302 		}
2303 		else
2304 		{
2305 		    if (n == TAB)
2306 		    {
2307 			int end_vcol = 0;
2308 
2309 			if (curwin->w_cursor.lnum == oap->end.lnum)
2310 			{
2311 			    /* oap->end has to be recalculated when
2312 			     * the tab breaks */
2313 			    end_vcol = getviscol2(oap->end.col,
2314 							     oap->end.coladd);
2315 			}
2316 			coladvance_force(getviscol());
2317 			if (curwin->w_cursor.lnum == oap->end.lnum)
2318 			    getvpos(&oap->end, end_vcol);
2319 		    }
2320 		    PBYTE(curwin->w_cursor, c);
2321 		}
2322 	    }
2323 	    else if (virtual_op && curwin->w_cursor.lnum == oap->end.lnum)
2324 	    {
2325 		int virtcols = oap->end.coladd;
2326 
2327 		if (curwin->w_cursor.lnum == oap->start.lnum
2328 			&& oap->start.col == oap->end.col && oap->start.coladd)
2329 		    virtcols -= oap->start.coladd;
2330 
2331 		/* oap->end has been trimmed so it's effectively inclusive;
2332 		 * as a result an extra +1 must be counted so we don't
2333 		 * trample the NUL byte. */
2334 		coladvance_force(getviscol2(oap->end.col, oap->end.coladd) + 1);
2335 		curwin->w_cursor.col -= (virtcols + 1);
2336 		for (; virtcols >= 0; virtcols--)
2337 		{
2338                    if ((*mb_char2len)(c) > 1)
2339 		       replace_character(c);
2340                    else
2341 			PBYTE(curwin->w_cursor, c);
2342 		   if (inc(&curwin->w_cursor) == -1)
2343 		       break;
2344 		}
2345 	    }
2346 
2347 	    /* Advance to next character, stop at the end of the file. */
2348 	    if (inc_cursor() == -1)
2349 		break;
2350 	}
2351     }
2352 
2353     curwin->w_cursor = oap->start;
2354     check_cursor();
2355     changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L);
2356 
2357     /* Set "'[" and "']" marks. */
2358     curbuf->b_op_start = oap->start;
2359     curbuf->b_op_end = oap->end;
2360 
2361     return OK;
2362 }
2363 
2364 static int swapchars(int op_type, pos_T *pos, int length);
2365 
2366 /*
2367  * Handle the (non-standard vi) tilde operator.  Also for "gu", "gU" and "g?".
2368  */
2369     void
2370 op_tilde(oparg_T *oap)
2371 {
2372     pos_T		pos;
2373     struct block_def	bd;
2374     int			did_change = FALSE;
2375 
2376     if (u_save((linenr_T)(oap->start.lnum - 1),
2377 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
2378 	return;
2379 
2380     pos = oap->start;
2381     if (oap->block_mode)		    /* Visual block mode */
2382     {
2383 	for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
2384 	{
2385 	    int one_change;
2386 
2387 	    block_prep(oap, &bd, pos.lnum, FALSE);
2388 	    pos.col = bd.textcol;
2389 	    one_change = swapchars(oap->op_type, &pos, bd.textlen);
2390 	    did_change |= one_change;
2391 
2392 #ifdef FEAT_NETBEANS_INTG
2393 	    if (netbeans_active() && one_change)
2394 	    {
2395 		char_u *ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
2396 
2397 		netbeans_removed(curbuf, pos.lnum, bd.textcol,
2398 							    (long)bd.textlen);
2399 		netbeans_inserted(curbuf, pos.lnum, bd.textcol,
2400 						&ptr[bd.textcol], bd.textlen);
2401 	    }
2402 #endif
2403 	}
2404 	if (did_change)
2405 	    changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
2406     }
2407     else				    /* not block mode */
2408     {
2409 	if (oap->motion_type == MLINE)
2410 	{
2411 	    oap->start.col = 0;
2412 	    pos.col = 0;
2413 	    oap->end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));
2414 	    if (oap->end.col)
2415 		--oap->end.col;
2416 	}
2417 	else if (!oap->inclusive)
2418 	    dec(&(oap->end));
2419 
2420 	if (pos.lnum == oap->end.lnum)
2421 	    did_change = swapchars(oap->op_type, &pos,
2422 						  oap->end.col - pos.col + 1);
2423 	else
2424 	    for (;;)
2425 	    {
2426 		did_change |= swapchars(oap->op_type, &pos,
2427 				pos.lnum == oap->end.lnum ? oap->end.col + 1:
2428 					   (int)STRLEN(ml_get_pos(&pos)));
2429 		if (LTOREQ_POS(oap->end, pos) || inc(&pos) == -1)
2430 		    break;
2431 	    }
2432 	if (did_change)
2433 	{
2434 	    changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1,
2435 									  0L);
2436 #ifdef FEAT_NETBEANS_INTG
2437 	    if (netbeans_active() && did_change)
2438 	    {
2439 		char_u *ptr;
2440 		int count;
2441 
2442 		pos = oap->start;
2443 		while (pos.lnum < oap->end.lnum)
2444 		{
2445 		    ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
2446 		    count = (int)STRLEN(ptr) - pos.col;
2447 		    netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
2448 		    netbeans_inserted(curbuf, pos.lnum, pos.col,
2449 							&ptr[pos.col], count);
2450 		    pos.col = 0;
2451 		    pos.lnum++;
2452 		}
2453 		ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
2454 		count = oap->end.col - pos.col + 1;
2455 		netbeans_removed(curbuf, pos.lnum, pos.col, (long)count);
2456 		netbeans_inserted(curbuf, pos.lnum, pos.col,
2457 							&ptr[pos.col], count);
2458 	    }
2459 #endif
2460 	}
2461     }
2462 
2463     if (!did_change && oap->is_VIsual)
2464 	/* No change: need to remove the Visual selection */
2465 	redraw_curbuf_later(INVERTED);
2466 
2467     /*
2468      * Set '[ and '] marks.
2469      */
2470     curbuf->b_op_start = oap->start;
2471     curbuf->b_op_end = oap->end;
2472 
2473     if (oap->line_count > p_report)
2474 	smsg(NGETTEXT("%ld line changed", "%ld lines changed",
2475 					    oap->line_count), oap->line_count);
2476 }
2477 
2478 /*
2479  * Invoke swapchar() on "length" bytes at position "pos".
2480  * "pos" is advanced to just after the changed characters.
2481  * "length" is rounded up to include the whole last multi-byte character.
2482  * Also works correctly when the number of bytes changes.
2483  * Returns TRUE if some character was changed.
2484  */
2485     static int
2486 swapchars(int op_type, pos_T *pos, int length)
2487 {
2488     int todo;
2489     int	did_change = 0;
2490 
2491     for (todo = length; todo > 0; --todo)
2492     {
2493 	if (has_mbyte)
2494 	{
2495 	    int len = (*mb_ptr2len)(ml_get_pos(pos));
2496 
2497 	    /* we're counting bytes, not characters */
2498 	    if (len > 0)
2499 		todo -= len - 1;
2500 	}
2501 	did_change |= swapchar(op_type, pos);
2502 	if (inc(pos) == -1)    /* at end of file */
2503 	    break;
2504     }
2505     return did_change;
2506 }
2507 
2508 /*
2509  * If op_type == OP_UPPER: make uppercase,
2510  * if op_type == OP_LOWER: make lowercase,
2511  * if op_type == OP_ROT13: do rot13 encoding,
2512  * else swap case of character at 'pos'
2513  * returns TRUE when something actually changed.
2514  */
2515     int
2516 swapchar(int op_type, pos_T *pos)
2517 {
2518     int	    c;
2519     int	    nc;
2520 
2521     c = gchar_pos(pos);
2522 
2523     /* Only do rot13 encoding for ASCII characters. */
2524     if (c >= 0x80 && op_type == OP_ROT13)
2525 	return FALSE;
2526 
2527     if (op_type == OP_UPPER && c == 0xdf
2528 		      && (enc_latin1like || STRCMP(p_enc, "iso-8859-2") == 0))
2529     {
2530 	pos_T   sp = curwin->w_cursor;
2531 
2532 	/* Special handling of German sharp s: change to "SS". */
2533 	curwin->w_cursor = *pos;
2534 	del_char(FALSE);
2535 	ins_char('S');
2536 	ins_char('S');
2537 	curwin->w_cursor = sp;
2538 	inc(pos);
2539     }
2540 
2541     if (enc_dbcs != 0 && c >= 0x100)	/* No lower/uppercase letter */
2542 	return FALSE;
2543     nc = c;
2544     if (MB_ISLOWER(c))
2545     {
2546 	if (op_type == OP_ROT13)
2547 	    nc = ROT13(c, 'a');
2548 	else if (op_type != OP_LOWER)
2549 	    nc = MB_TOUPPER(c);
2550     }
2551     else if (MB_ISUPPER(c))
2552     {
2553 	if (op_type == OP_ROT13)
2554 	    nc = ROT13(c, 'A');
2555 	else if (op_type != OP_UPPER)
2556 	    nc = MB_TOLOWER(c);
2557     }
2558     if (nc != c)
2559     {
2560 	if (enc_utf8 && (c >= 0x80 || nc >= 0x80))
2561 	{
2562 	    pos_T   sp = curwin->w_cursor;
2563 
2564 	    curwin->w_cursor = *pos;
2565 	    /* don't use del_char(), it also removes composing chars */
2566 	    del_bytes(utf_ptr2len(ml_get_cursor()), FALSE, FALSE);
2567 	    ins_char(nc);
2568 	    curwin->w_cursor = sp;
2569 	}
2570 	else
2571 	    PBYTE(*pos, nc);
2572 	return TRUE;
2573     }
2574     return FALSE;
2575 }
2576 
2577 /*
2578  * op_insert - Insert and append operators for Visual mode.
2579  */
2580     void
2581 op_insert(oparg_T *oap, long count1)
2582 {
2583     long		ins_len, pre_textlen = 0;
2584     char_u		*firstline, *ins_text;
2585     colnr_T		ind_pre = 0, ind_post;
2586     struct block_def	bd;
2587     int			i;
2588     pos_T		t1;
2589 
2590     /* edit() changes this - record it for OP_APPEND */
2591     bd.is_MAX = (curwin->w_curswant == MAXCOL);
2592 
2593     /* vis block is still marked. Get rid of it now. */
2594     curwin->w_cursor.lnum = oap->start.lnum;
2595     update_screen(INVERTED);
2596 
2597     if (oap->block_mode)
2598     {
2599 	/* When 'virtualedit' is used, need to insert the extra spaces before
2600 	 * doing block_prep().  When only "block" is used, virtual edit is
2601 	 * already disabled, but still need it when calling
2602 	 * coladvance_force(). */
2603 	if (curwin->w_cursor.coladd > 0)
2604 	{
2605 	    int		old_ve_flags = ve_flags;
2606 
2607 	    ve_flags = VE_ALL;
2608 	    if (u_save_cursor() == FAIL)
2609 		return;
2610 	    coladvance_force(oap->op_type == OP_APPEND
2611 					   ? oap->end_vcol + 1 : getviscol());
2612 	    if (oap->op_type == OP_APPEND)
2613 		--curwin->w_cursor.col;
2614 	    ve_flags = old_ve_flags;
2615 	}
2616 	/* Get the info about the block before entering the text */
2617 	block_prep(oap, &bd, oap->start.lnum, TRUE);
2618 	/* Get indent information */
2619 	ind_pre = (colnr_T)getwhitecols_curline();
2620 	firstline = ml_get(oap->start.lnum) + bd.textcol;
2621 
2622 	if (oap->op_type == OP_APPEND)
2623 	    firstline += bd.textlen;
2624 	pre_textlen = (long)STRLEN(firstline);
2625     }
2626 
2627     if (oap->op_type == OP_APPEND)
2628     {
2629 	if (oap->block_mode && curwin->w_cursor.coladd == 0)
2630 	{
2631 	    /* Move the cursor to the character right of the block. */
2632 	    curwin->w_set_curswant = TRUE;
2633 	    while (*ml_get_cursor() != NUL
2634 		    && (curwin->w_cursor.col < bd.textcol + bd.textlen))
2635 		++curwin->w_cursor.col;
2636 	    if (bd.is_short && !bd.is_MAX)
2637 	    {
2638 		/* First line was too short, make it longer and adjust the
2639 		 * values in "bd". */
2640 		if (u_save_cursor() == FAIL)
2641 		    return;
2642 		for (i = 0; i < bd.endspaces; ++i)
2643 		    ins_char(' ');
2644 		bd.textlen += bd.endspaces;
2645 	    }
2646 	}
2647 	else
2648 	{
2649 	    curwin->w_cursor = oap->end;
2650 	    check_cursor_col();
2651 
2652 	    /* Works just like an 'i'nsert on the next character. */
2653 	    if (!LINEEMPTY(curwin->w_cursor.lnum)
2654 		    && oap->start_vcol != oap->end_vcol)
2655 		inc_cursor();
2656 	}
2657     }
2658 
2659     t1 = oap->start;
2660     (void)edit(NUL, FALSE, (linenr_T)count1);
2661 
2662     /* When a tab was inserted, and the characters in front of the tab
2663      * have been converted to a tab as well, the column of the cursor
2664      * might have actually been reduced, so need to adjust here. */
2665     if (t1.lnum == curbuf->b_op_start_orig.lnum
2666 	    && LT_POS(curbuf->b_op_start_orig, t1))
2667 	oap->start = curbuf->b_op_start_orig;
2668 
2669     /* If user has moved off this line, we don't know what to do, so do
2670      * nothing.
2671      * Also don't repeat the insert when Insert mode ended with CTRL-C. */
2672     if (curwin->w_cursor.lnum != oap->start.lnum || got_int)
2673 	return;
2674 
2675     if (oap->block_mode)
2676     {
2677 	struct block_def	bd2;
2678 	int			did_indent = FALSE;
2679 	size_t			len;
2680 	int			add;
2681 
2682 	/* If indent kicked in, the firstline might have changed
2683 	 * but only do that, if the indent actually increased. */
2684 	ind_post = (colnr_T)getwhitecols_curline();
2685 	if (curbuf->b_op_start.col > ind_pre && ind_post > ind_pre)
2686 	{
2687 	    bd.textcol += ind_post - ind_pre;
2688 	    bd.start_vcol += ind_post - ind_pre;
2689 	    did_indent = TRUE;
2690 	}
2691 
2692 	/* The user may have moved the cursor before inserting something, try
2693 	 * to adjust the block for that.  But only do it, if the difference
2694 	 * does not come from indent kicking in. */
2695 	if (oap->start.lnum == curbuf->b_op_start_orig.lnum
2696 						  && !bd.is_MAX && !did_indent)
2697 	{
2698 	    if (oap->op_type == OP_INSERT
2699 		    && oap->start.col + oap->start.coladd
2700 			!= curbuf->b_op_start_orig.col
2701 					      + curbuf->b_op_start_orig.coladd)
2702 	    {
2703 		int t = getviscol2(curbuf->b_op_start_orig.col,
2704 					      curbuf->b_op_start_orig.coladd);
2705 		oap->start.col = curbuf->b_op_start_orig.col;
2706 		pre_textlen -= t - oap->start_vcol;
2707 		oap->start_vcol = t;
2708 	    }
2709 	    else if (oap->op_type == OP_APPEND
2710 		      && oap->end.col + oap->end.coladd
2711 			>= curbuf->b_op_start_orig.col
2712 					      + curbuf->b_op_start_orig.coladd)
2713 	    {
2714 		int t = getviscol2(curbuf->b_op_start_orig.col,
2715 					      curbuf->b_op_start_orig.coladd);
2716 		oap->start.col = curbuf->b_op_start_orig.col;
2717 		/* reset pre_textlen to the value of OP_INSERT */
2718 		pre_textlen += bd.textlen;
2719 		pre_textlen -= t - oap->start_vcol;
2720 		oap->start_vcol = t;
2721 		oap->op_type = OP_INSERT;
2722 	    }
2723 	}
2724 
2725 	/*
2726 	 * Spaces and tabs in the indent may have changed to other spaces and
2727 	 * tabs.  Get the starting column again and correct the length.
2728 	 * Don't do this when "$" used, end-of-line will have changed.
2729 	 */
2730 	block_prep(oap, &bd2, oap->start.lnum, TRUE);
2731 	if (!bd.is_MAX || bd2.textlen < bd.textlen)
2732 	{
2733 	    if (oap->op_type == OP_APPEND)
2734 	    {
2735 		pre_textlen += bd2.textlen - bd.textlen;
2736 		if (bd2.endspaces)
2737 		    --bd2.textlen;
2738 	    }
2739 	    bd.textcol = bd2.textcol;
2740 	    bd.textlen = bd2.textlen;
2741 	}
2742 
2743 	/*
2744 	 * Subsequent calls to ml_get() flush the firstline data - take a
2745 	 * copy of the required string.
2746 	 */
2747 	firstline = ml_get(oap->start.lnum);
2748 	len = STRLEN(firstline);
2749 	add = bd.textcol;
2750 	if (oap->op_type == OP_APPEND)
2751 	    add += bd.textlen;
2752 	if ((size_t)add > len)
2753 	    firstline += len;  // short line, point to the NUL
2754 	else
2755 	    firstline += add;
2756 	if (pre_textlen >= 0
2757 		     && (ins_len = (long)STRLEN(firstline) - pre_textlen) > 0)
2758 	{
2759 	    ins_text = vim_strnsave(firstline, (int)ins_len);
2760 	    if (ins_text != NULL)
2761 	    {
2762 		/* block handled here */
2763 		if (u_save(oap->start.lnum,
2764 					 (linenr_T)(oap->end.lnum + 1)) == OK)
2765 		    block_insert(oap, ins_text, (oap->op_type == OP_INSERT),
2766 									 &bd);
2767 
2768 		curwin->w_cursor.col = oap->start.col;
2769 		check_cursor();
2770 		vim_free(ins_text);
2771 	    }
2772 	}
2773     }
2774 }
2775 
2776 /*
2777  * op_change - handle a change operation
2778  *
2779  * return TRUE if edit() returns because of a CTRL-O command
2780  */
2781     int
2782 op_change(oparg_T *oap)
2783 {
2784     colnr_T		l;
2785     int			retval;
2786     long		offset;
2787     linenr_T		linenr;
2788     long		ins_len;
2789     long		pre_textlen = 0;
2790     long		pre_indent = 0;
2791     char_u		*firstline;
2792     char_u		*ins_text, *newp, *oldp;
2793     struct block_def	bd;
2794 
2795     l = oap->start.col;
2796     if (oap->motion_type == MLINE)
2797     {
2798 	l = 0;
2799 #ifdef FEAT_SMARTINDENT
2800 	if (!p_paste && curbuf->b_p_si
2801 # ifdef FEAT_CINDENT
2802 		&& !curbuf->b_p_cin
2803 # endif
2804 		)
2805 	    can_si = TRUE;	/* It's like opening a new line, do si */
2806 #endif
2807     }
2808 
2809     /* First delete the text in the region.  In an empty buffer only need to
2810      * save for undo */
2811     if (curbuf->b_ml.ml_flags & ML_EMPTY)
2812     {
2813 	if (u_save_cursor() == FAIL)
2814 	    return FALSE;
2815     }
2816     else if (op_delete(oap) == FAIL)
2817 	return FALSE;
2818 
2819     if ((l > curwin->w_cursor.col) && !LINEEMPTY(curwin->w_cursor.lnum)
2820 							 && !virtual_op)
2821 	inc_cursor();
2822 
2823     /* check for still on same line (<CR> in inserted text meaningless) */
2824     /* skip blank lines too */
2825     if (oap->block_mode)
2826     {
2827 	/* Add spaces before getting the current line length. */
2828 	if (virtual_op && (curwin->w_cursor.coladd > 0
2829 						    || gchar_cursor() == NUL))
2830 	    coladvance_force(getviscol());
2831 	firstline = ml_get(oap->start.lnum);
2832 	pre_textlen = (long)STRLEN(firstline);
2833 	pre_indent = (long)getwhitecols(firstline);
2834 	bd.textcol = curwin->w_cursor.col;
2835     }
2836 
2837 #if defined(FEAT_LISP) || defined(FEAT_CINDENT)
2838     if (oap->motion_type == MLINE)
2839 	fix_indent();
2840 #endif
2841 
2842     retval = edit(NUL, FALSE, (linenr_T)1);
2843 
2844     /*
2845      * In Visual block mode, handle copying the new text to all lines of the
2846      * block.
2847      * Don't repeat the insert when Insert mode ended with CTRL-C.
2848      */
2849     if (oap->block_mode && oap->start.lnum != oap->end.lnum && !got_int)
2850     {
2851 	/* Auto-indenting may have changed the indent.  If the cursor was past
2852 	 * the indent, exclude that indent change from the inserted text. */
2853 	firstline = ml_get(oap->start.lnum);
2854 	if (bd.textcol > (colnr_T)pre_indent)
2855 	{
2856 	    long new_indent = (long)getwhitecols(firstline);
2857 
2858 	    pre_textlen += new_indent - pre_indent;
2859 	    bd.textcol += new_indent - pre_indent;
2860 	}
2861 
2862 	ins_len = (long)STRLEN(firstline) - pre_textlen;
2863 	if (ins_len > 0)
2864 	{
2865 	    /* Subsequent calls to ml_get() flush the firstline data - take a
2866 	     * copy of the inserted text.  */
2867 	    if ((ins_text = alloc(ins_len + 1)) != NULL)
2868 	    {
2869 		vim_strncpy(ins_text, firstline + bd.textcol, (size_t)ins_len);
2870 		for (linenr = oap->start.lnum + 1; linenr <= oap->end.lnum;
2871 								     linenr++)
2872 		{
2873 		    block_prep(oap, &bd, linenr, TRUE);
2874 		    if (!bd.is_short || virtual_op)
2875 		    {
2876 			pos_T vpos;
2877 
2878 			/* If the block starts in virtual space, count the
2879 			 * initial coladd offset as part of "startspaces" */
2880 			if (bd.is_short)
2881 			{
2882 			    vpos.lnum = linenr;
2883 			    (void)getvpos(&vpos, oap->start_vcol);
2884 			}
2885 			else
2886 			    vpos.coladd = 0;
2887 			oldp = ml_get(linenr);
2888 			newp = alloc(STRLEN(oldp) + vpos.coladd + ins_len + 1);
2889 			if (newp == NULL)
2890 			    continue;
2891 			/* copy up to block start */
2892 			mch_memmove(newp, oldp, (size_t)bd.textcol);
2893 			offset = bd.textcol;
2894 			vim_memset(newp + offset, ' ', (size_t)vpos.coladd);
2895 			offset += vpos.coladd;
2896 			mch_memmove(newp + offset, ins_text, (size_t)ins_len);
2897 			offset += ins_len;
2898 			oldp += bd.textcol;
2899 			STRMOVE(newp + offset, oldp);
2900 			ml_replace(linenr, newp, FALSE);
2901 		    }
2902 		}
2903 		check_cursor();
2904 
2905 		changed_lines(oap->start.lnum + 1, 0, oap->end.lnum + 1, 0L);
2906 	    }
2907 	    vim_free(ins_text);
2908 	}
2909     }
2910 
2911     return retval;
2912 }
2913 
2914 /*
2915  * set all the yank registers to empty (called from main())
2916  */
2917     void
2918 init_yank(void)
2919 {
2920     int		i;
2921 
2922     for (i = 0; i < NUM_REGISTERS; ++i)
2923 	y_regs[i].y_array = NULL;
2924 }
2925 
2926 #if defined(EXITFREE) || defined(PROTO)
2927     void
2928 clear_registers(void)
2929 {
2930     int		i;
2931 
2932     for (i = 0; i < NUM_REGISTERS; ++i)
2933     {
2934 	y_current = &y_regs[i];
2935 	if (y_current->y_array != NULL)
2936 	    free_yank_all();
2937     }
2938 }
2939 #endif
2940 
2941 /*
2942  * Free "n" lines from the current yank register.
2943  * Called for normal freeing and in case of error.
2944  */
2945     static void
2946 free_yank(long n)
2947 {
2948     if (y_current->y_array != NULL)
2949     {
2950 	long	    i;
2951 
2952 	for (i = n; --i >= 0; )
2953 	{
2954 #ifdef AMIGA	    /* only for very slow machines */
2955 	    if ((i & 1023) == 1023)  /* this may take a while */
2956 	    {
2957 		/*
2958 		 * This message should never cause a hit-return message.
2959 		 * Overwrite this message with any next message.
2960 		 */
2961 		++no_wait_return;
2962 		smsg(_("freeing %ld lines"), i + 1);
2963 		--no_wait_return;
2964 		msg_didout = FALSE;
2965 		msg_col = 0;
2966 	    }
2967 #endif
2968 	    vim_free(y_current->y_array[i]);
2969 	}
2970 	VIM_CLEAR(y_current->y_array);
2971 #ifdef AMIGA
2972 	if (n >= 1000)
2973 	    msg("");
2974 #endif
2975     }
2976 }
2977 
2978     static void
2979 free_yank_all(void)
2980 {
2981     free_yank(y_current->y_size);
2982 }
2983 
2984 /*
2985  * Yank the text between "oap->start" and "oap->end" into a yank register.
2986  * If we are to append (uppercase register), we first yank into a new yank
2987  * register and then concatenate the old and the new one (so we keep the old
2988  * one in case of out-of-memory).
2989  *
2990  * Return FAIL for failure, OK otherwise.
2991  */
2992     int
2993 op_yank(oparg_T *oap, int deleting, int mess)
2994 {
2995     long		y_idx;		/* index in y_array[] */
2996     yankreg_T		*curr;		/* copy of y_current */
2997     yankreg_T		newreg;		/* new yank register when appending */
2998     char_u		**new_ptr;
2999     linenr_T		lnum;		/* current line number */
3000     long		j;
3001     int			yanktype = oap->motion_type;
3002     long		yanklines = oap->line_count;
3003     linenr_T		yankendlnum = oap->end.lnum;
3004     char_u		*p;
3005     char_u		*pnew;
3006     struct block_def	bd;
3007 #if defined(FEAT_CLIPBOARD) && defined(FEAT_X11)
3008     int			did_star = FALSE;
3009 #endif
3010 
3011 				    /* check for read-only register */
3012     if (oap->regname != 0 && !valid_yank_reg(oap->regname, TRUE))
3013     {
3014 	beep_flush();
3015 	return FAIL;
3016     }
3017     if (oap->regname == '_')	    /* black hole: nothing to do */
3018 	return OK;
3019 
3020 #ifdef FEAT_CLIPBOARD
3021     if (!clip_star.available && oap->regname == '*')
3022 	oap->regname = 0;
3023     else if (!clip_plus.available && oap->regname == '+')
3024 	oap->regname = 0;
3025 #endif
3026 
3027     if (!deleting)		    /* op_delete() already set y_current */
3028 	get_yank_register(oap->regname, TRUE);
3029 
3030     curr = y_current;
3031 				    /* append to existing contents */
3032     if (y_append && y_current->y_array != NULL)
3033 	y_current = &newreg;
3034     else
3035 	free_yank_all();	    /* free previously yanked lines */
3036 
3037     /*
3038      * If the cursor was in column 1 before and after the movement, and the
3039      * operator is not inclusive, the yank is always linewise.
3040      */
3041     if (       oap->motion_type == MCHAR
3042 	    && oap->start.col == 0
3043 	    && !oap->inclusive
3044 	    && (!oap->is_VIsual || *p_sel == 'o')
3045 	    && !oap->block_mode
3046 	    && oap->end.col == 0
3047 	    && yanklines > 1)
3048     {
3049 	yanktype = MLINE;
3050 	--yankendlnum;
3051 	--yanklines;
3052     }
3053 
3054     y_current->y_size = yanklines;
3055     y_current->y_type = yanktype;   /* set the yank register type */
3056     y_current->y_width = 0;
3057     y_current->y_array = lalloc_clear(sizeof(char_u *) * yanklines, TRUE);
3058     if (y_current->y_array == NULL)
3059     {
3060 	y_current = curr;
3061 	return FAIL;
3062     }
3063 #ifdef FEAT_VIMINFO
3064     y_current->y_time_set = vim_time();
3065 #endif
3066 
3067     y_idx = 0;
3068     lnum = oap->start.lnum;
3069 
3070     if (oap->block_mode)
3071     {
3072 	/* Visual block mode */
3073 	y_current->y_type = MBLOCK;	    /* set the yank register type */
3074 	y_current->y_width = oap->end_vcol - oap->start_vcol;
3075 
3076 	if (curwin->w_curswant == MAXCOL && y_current->y_width > 0)
3077 	    y_current->y_width--;
3078     }
3079 
3080     for ( ; lnum <= yankendlnum; lnum++, y_idx++)
3081     {
3082 	switch (y_current->y_type)
3083 	{
3084 	    case MBLOCK:
3085 		block_prep(oap, &bd, lnum, FALSE);
3086 		if (yank_copy_line(&bd, y_idx) == FAIL)
3087 		    goto fail;
3088 		break;
3089 
3090 	    case MLINE:
3091 		if ((y_current->y_array[y_idx] =
3092 			    vim_strsave(ml_get(lnum))) == NULL)
3093 		    goto fail;
3094 		break;
3095 
3096 	    case MCHAR:
3097 		{
3098 		    colnr_T startcol = 0, endcol = MAXCOL;
3099 		    int is_oneChar = FALSE;
3100 		    colnr_T cs, ce;
3101 
3102 		    p = ml_get(lnum);
3103 		    bd.startspaces = 0;
3104 		    bd.endspaces = 0;
3105 
3106 		    if (lnum == oap->start.lnum)
3107 		    {
3108 			startcol = oap->start.col;
3109 			if (virtual_op)
3110 			{
3111 			    getvcol(curwin, &oap->start, &cs, NULL, &ce);
3112 			    if (ce != cs && oap->start.coladd > 0)
3113 			    {
3114 				/* Part of a tab selected -- but don't
3115 				 * double-count it. */
3116 				bd.startspaces = (ce - cs + 1)
3117 							  - oap->start.coladd;
3118 				startcol++;
3119 			    }
3120 			}
3121 		    }
3122 
3123 		    if (lnum == oap->end.lnum)
3124 		    {
3125 			endcol = oap->end.col;
3126 			if (virtual_op)
3127 			{
3128 			    getvcol(curwin, &oap->end, &cs, NULL, &ce);
3129 			    if (p[endcol] == NUL || (cs + oap->end.coladd < ce
3130 					/* Don't add space for double-wide
3131 					 * char; endcol will be on last byte
3132 					 * of multi-byte char. */
3133 					&& (*mb_head_off)(p, p + endcol) == 0))
3134 			    {
3135 				if (oap->start.lnum == oap->end.lnum
3136 					    && oap->start.col == oap->end.col)
3137 				{
3138 				    /* Special case: inside a single char */
3139 				    is_oneChar = TRUE;
3140 				    bd.startspaces = oap->end.coladd
3141 					 - oap->start.coladd + oap->inclusive;
3142 				    endcol = startcol;
3143 				}
3144 				else
3145 				{
3146 				    bd.endspaces = oap->end.coladd
3147 							     + oap->inclusive;
3148 				    endcol -= oap->inclusive;
3149 				}
3150 			    }
3151 			}
3152 		    }
3153 		    if (endcol == MAXCOL)
3154 			endcol = (colnr_T)STRLEN(p);
3155 		    if (startcol > endcol || is_oneChar)
3156 			bd.textlen = 0;
3157 		    else
3158 			bd.textlen = endcol - startcol + oap->inclusive;
3159 		    bd.textstart = p + startcol;
3160 		    if (yank_copy_line(&bd, y_idx) == FAIL)
3161 			goto fail;
3162 		    break;
3163 		}
3164 		/* NOTREACHED */
3165 	}
3166     }
3167 
3168     if (curr != y_current)	/* append the new block to the old block */
3169     {
3170 	new_ptr = ALLOC_MULT(char_u *, curr->y_size + y_current->y_size);
3171 	if (new_ptr == NULL)
3172 	    goto fail;
3173 	for (j = 0; j < curr->y_size; ++j)
3174 	    new_ptr[j] = curr->y_array[j];
3175 	vim_free(curr->y_array);
3176 	curr->y_array = new_ptr;
3177 #ifdef FEAT_VIMINFO
3178 	curr->y_time_set = vim_time();
3179 #endif
3180 
3181 	if (yanktype == MLINE)	/* MLINE overrides MCHAR and MBLOCK */
3182 	    curr->y_type = MLINE;
3183 
3184 	/* Concatenate the last line of the old block with the first line of
3185 	 * the new block, unless being Vi compatible. */
3186 	if (curr->y_type == MCHAR && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL)
3187 	{
3188 	    pnew = alloc(STRLEN(curr->y_array[curr->y_size - 1])
3189 					  + STRLEN(y_current->y_array[0]) + 1);
3190 	    if (pnew == NULL)
3191 	    {
3192 		y_idx = y_current->y_size - 1;
3193 		goto fail;
3194 	    }
3195 	    STRCPY(pnew, curr->y_array[--j]);
3196 	    STRCAT(pnew, y_current->y_array[0]);
3197 	    vim_free(curr->y_array[j]);
3198 	    vim_free(y_current->y_array[0]);
3199 	    curr->y_array[j++] = pnew;
3200 	    y_idx = 1;
3201 	}
3202 	else
3203 	    y_idx = 0;
3204 	while (y_idx < y_current->y_size)
3205 	    curr->y_array[j++] = y_current->y_array[y_idx++];
3206 	curr->y_size = j;
3207 	vim_free(y_current->y_array);
3208 	y_current = curr;
3209     }
3210     if (curwin->w_p_rnu)
3211 	redraw_later(SOME_VALID);	/* cursor moved to start */
3212     if (mess)			/* Display message about yank? */
3213     {
3214 	if (yanktype == MCHAR
3215 		&& !oap->block_mode
3216 		&& yanklines == 1)
3217 	    yanklines = 0;
3218 	/* Some versions of Vi use ">=" here, some don't...  */
3219 	if (yanklines > p_report)
3220 	{
3221 	    char namebuf[100];
3222 
3223 	    if (oap->regname == NUL)
3224 		*namebuf = NUL;
3225 	    else
3226 		vim_snprintf(namebuf, sizeof(namebuf),
3227 						_(" into \"%c"), oap->regname);
3228 
3229 	    /* redisplay now, so message is not deleted */
3230 	    update_topline_redraw();
3231 	    if (oap->block_mode)
3232 	    {
3233 		smsg(NGETTEXT("block of %ld line yanked%s",
3234 				     "block of %ld lines yanked%s", yanklines),
3235 			yanklines, namebuf);
3236 	    }
3237 	    else
3238 	    {
3239 		smsg(NGETTEXT("%ld line yanked%s",
3240 					      "%ld lines yanked%s", yanklines),
3241 			yanklines, namebuf);
3242 	    }
3243 	}
3244     }
3245 
3246     /*
3247      * Set "'[" and "']" marks.
3248      */
3249     curbuf->b_op_start = oap->start;
3250     curbuf->b_op_end = oap->end;
3251     if (yanktype == MLINE && !oap->block_mode)
3252     {
3253 	curbuf->b_op_start.col = 0;
3254 	curbuf->b_op_end.col = MAXCOL;
3255     }
3256 
3257 #ifdef FEAT_CLIPBOARD
3258     /*
3259      * If we were yanking to the '*' register, send result to clipboard.
3260      * If no register was specified, and "unnamed" in 'clipboard', make a copy
3261      * to the '*' register.
3262      */
3263     if (clip_star.available
3264 	    && (curr == &(y_regs[STAR_REGISTER])
3265 		|| (!deleting && oap->regname == 0
3266 		   && ((clip_unnamed | clip_unnamed_saved) & CLIP_UNNAMED))))
3267     {
3268 	if (curr != &(y_regs[STAR_REGISTER]))
3269 	    /* Copy the text from register 0 to the clipboard register. */
3270 	    copy_yank_reg(&(y_regs[STAR_REGISTER]));
3271 
3272 	clip_own_selection(&clip_star);
3273 	clip_gen_set_selection(&clip_star);
3274 # ifdef FEAT_X11
3275 	did_star = TRUE;
3276 # endif
3277     }
3278 
3279 # ifdef FEAT_X11
3280     /*
3281      * If we were yanking to the '+' register, send result to selection.
3282      * Also copy to the '*' register, in case auto-select is off.
3283      */
3284     if (clip_plus.available
3285 	    && (curr == &(y_regs[PLUS_REGISTER])
3286 		|| (!deleting && oap->regname == 0
3287 		  && ((clip_unnamed | clip_unnamed_saved) &
3288 		      CLIP_UNNAMED_PLUS))))
3289     {
3290 	if (curr != &(y_regs[PLUS_REGISTER]))
3291 	    /* Copy the text from register 0 to the clipboard register. */
3292 	    copy_yank_reg(&(y_regs[PLUS_REGISTER]));
3293 
3294 	clip_own_selection(&clip_plus);
3295 	clip_gen_set_selection(&clip_plus);
3296 	if (!clip_isautosel_star() && !clip_isautosel_plus()
3297 		&& !did_star && curr == &(y_regs[PLUS_REGISTER]))
3298 	{
3299 	    copy_yank_reg(&(y_regs[STAR_REGISTER]));
3300 	    clip_own_selection(&clip_star);
3301 	    clip_gen_set_selection(&clip_star);
3302 	}
3303     }
3304 # endif
3305 #endif
3306 
3307 #if defined(FEAT_EVAL)
3308     if (!deleting && has_textyankpost())
3309 	yank_do_autocmd(oap, y_current);
3310 #endif
3311 
3312     return OK;
3313 
3314 fail:		/* free the allocated lines */
3315     free_yank(y_idx + 1);
3316     y_current = curr;
3317     return FAIL;
3318 }
3319 
3320     static int
3321 yank_copy_line(struct block_def *bd, long y_idx)
3322 {
3323     char_u	*pnew;
3324 
3325     if ((pnew = alloc(bd->startspaces + bd->endspaces + bd->textlen + 1))
3326 								      == NULL)
3327 	return FAIL;
3328     y_current->y_array[y_idx] = pnew;
3329     vim_memset(pnew, ' ', (size_t)bd->startspaces);
3330     pnew += bd->startspaces;
3331     mch_memmove(pnew, bd->textstart, (size_t)bd->textlen);
3332     pnew += bd->textlen;
3333     vim_memset(pnew, ' ', (size_t)bd->endspaces);
3334     pnew += bd->endspaces;
3335     *pnew = NUL;
3336     return OK;
3337 }
3338 
3339 #ifdef FEAT_CLIPBOARD
3340 /*
3341  * Make a copy of the y_current register to register "reg".
3342  */
3343     static void
3344 copy_yank_reg(yankreg_T *reg)
3345 {
3346     yankreg_T	*curr = y_current;
3347     long	j;
3348 
3349     y_current = reg;
3350     free_yank_all();
3351     *y_current = *curr;
3352     y_current->y_array = lalloc_clear(
3353 				    sizeof(char_u *) * y_current->y_size, TRUE);
3354     if (y_current->y_array == NULL)
3355 	y_current->y_size = 0;
3356     else
3357 	for (j = 0; j < y_current->y_size; ++j)
3358 	    if ((y_current->y_array[j] = vim_strsave(curr->y_array[j])) == NULL)
3359 	    {
3360 		free_yank(j);
3361 		y_current->y_size = 0;
3362 		break;
3363 	    }
3364     y_current = curr;
3365 }
3366 #endif
3367 
3368 /*
3369  * Put contents of register "regname" into the text.
3370  * Caller must check "regname" to be valid!
3371  * "flags": PUT_FIXINDENT	make indent look nice
3372  *	    PUT_CURSEND		leave cursor after end of new text
3373  *	    PUT_LINE		force linewise put (":put")
3374  */
3375     void
3376 do_put(
3377     int		regname,
3378     int		dir,		/* BACKWARD for 'P', FORWARD for 'p' */
3379     long	count,
3380     int		flags)
3381 {
3382     char_u	*ptr;
3383     char_u	*newp, *oldp;
3384     int		yanklen;
3385     int		totlen = 0;		/* init for gcc */
3386     linenr_T	lnum;
3387     colnr_T	col;
3388     long	i;			/* index in y_array[] */
3389     int		y_type;
3390     long	y_size;
3391     int		oldlen;
3392     long	y_width = 0;
3393     colnr_T	vcol;
3394     int		delcount;
3395     int		incr = 0;
3396     long	j;
3397     struct block_def bd;
3398     char_u	**y_array = NULL;
3399     long	nr_lines = 0;
3400     pos_T	new_cursor;
3401     int		indent;
3402     int		orig_indent = 0;	/* init for gcc */
3403     int		indent_diff = 0;	/* init for gcc */
3404     int		first_indent = TRUE;
3405     int		lendiff = 0;
3406     pos_T	old_pos;
3407     char_u	*insert_string = NULL;
3408     int		allocated = FALSE;
3409     long	cnt;
3410 
3411 #ifdef FEAT_CLIPBOARD
3412     /* Adjust register name for "unnamed" in 'clipboard'. */
3413     adjust_clip_reg(&regname);
3414     (void)may_get_selection(regname);
3415 #endif
3416 
3417     if (flags & PUT_FIXINDENT)
3418 	orig_indent = get_indent();
3419 
3420     curbuf->b_op_start = curwin->w_cursor;	/* default for '[ mark */
3421     curbuf->b_op_end = curwin->w_cursor;	/* default for '] mark */
3422 
3423     /*
3424      * Using inserted text works differently, because the register includes
3425      * special characters (newlines, etc.).
3426      */
3427     if (regname == '.')
3428     {
3429 	if (VIsual_active)
3430 	    stuffcharReadbuff(VIsual_mode);
3431 	(void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
3432 				    (count == -1 ? 'O' : 'i')), count, FALSE);
3433 	/* Putting the text is done later, so can't really move the cursor to
3434 	 * the next character.  Use "l" to simulate it. */
3435 	if ((flags & PUT_CURSEND) && gchar_cursor() != NUL)
3436 	    stuffcharReadbuff('l');
3437 	return;
3438     }
3439 
3440     /*
3441      * For special registers '%' (file name), '#' (alternate file name) and
3442      * ':' (last command line), etc. we have to create a fake yank register.
3443      */
3444     if (get_spec_reg(regname, &insert_string, &allocated, TRUE))
3445     {
3446 	if (insert_string == NULL)
3447 	    return;
3448     }
3449 
3450     /* Autocommands may be executed when saving lines for undo.  This might
3451      * make "y_array" invalid, so we start undo now to avoid that. */
3452     if (u_save(curwin->w_cursor.lnum, curwin->w_cursor.lnum + 1) == FAIL)
3453 	goto end;
3454 
3455     if (insert_string != NULL)
3456     {
3457 	y_type = MCHAR;
3458 #ifdef FEAT_EVAL
3459 	if (regname == '=')
3460 	{
3461 	    /* For the = register we need to split the string at NL
3462 	     * characters.
3463 	     * Loop twice: count the number of lines and save them. */
3464 	    for (;;)
3465 	    {
3466 		y_size = 0;
3467 		ptr = insert_string;
3468 		while (ptr != NULL)
3469 		{
3470 		    if (y_array != NULL)
3471 			y_array[y_size] = ptr;
3472 		    ++y_size;
3473 		    ptr = vim_strchr(ptr, '\n');
3474 		    if (ptr != NULL)
3475 		    {
3476 			if (y_array != NULL)
3477 			    *ptr = NUL;
3478 			++ptr;
3479 			/* A trailing '\n' makes the register linewise. */
3480 			if (*ptr == NUL)
3481 			{
3482 			    y_type = MLINE;
3483 			    break;
3484 			}
3485 		    }
3486 		}
3487 		if (y_array != NULL)
3488 		    break;
3489 		y_array = ALLOC_MULT(char_u *, y_size);
3490 		if (y_array == NULL)
3491 		    goto end;
3492 	    }
3493 	}
3494 	else
3495 #endif
3496 	{
3497 	    y_size = 1;		/* use fake one-line yank register */
3498 	    y_array = &insert_string;
3499 	}
3500     }
3501     else
3502     {
3503 	get_yank_register(regname, FALSE);
3504 
3505 	y_type = y_current->y_type;
3506 	y_width = y_current->y_width;
3507 	y_size = y_current->y_size;
3508 	y_array = y_current->y_array;
3509     }
3510 
3511     if (y_type == MLINE)
3512     {
3513 	if (flags & PUT_LINE_SPLIT)
3514 	{
3515 	    char_u *p;
3516 
3517 	    /* "p" or "P" in Visual mode: split the lines to put the text in
3518 	     * between. */
3519 	    if (u_save_cursor() == FAIL)
3520 		goto end;
3521 	    p = ml_get_cursor();
3522 	    if (dir == FORWARD && *p != NUL)
3523 		MB_PTR_ADV(p);
3524 	    ptr = vim_strsave(p);
3525 	    if (ptr == NULL)
3526 		goto end;
3527 	    ml_append(curwin->w_cursor.lnum, ptr, (colnr_T)0, FALSE);
3528 	    vim_free(ptr);
3529 
3530 	    oldp = ml_get_curline();
3531 	    p = oldp + curwin->w_cursor.col;
3532 	    if (dir == FORWARD && *p != NUL)
3533 		MB_PTR_ADV(p);
3534 	    ptr = vim_strnsave(oldp, p - oldp);
3535 	    if (ptr == NULL)
3536 		goto end;
3537 	    ml_replace(curwin->w_cursor.lnum, ptr, FALSE);
3538 	    ++nr_lines;
3539 	    dir = FORWARD;
3540 	}
3541 	if (flags & PUT_LINE_FORWARD)
3542 	{
3543 	    /* Must be "p" for a Visual block, put lines below the block. */
3544 	    curwin->w_cursor = curbuf->b_visual.vi_end;
3545 	    dir = FORWARD;
3546 	}
3547 	curbuf->b_op_start = curwin->w_cursor;	/* default for '[ mark */
3548 	curbuf->b_op_end = curwin->w_cursor;	/* default for '] mark */
3549     }
3550 
3551     if (flags & PUT_LINE)	/* :put command or "p" in Visual line mode. */
3552 	y_type = MLINE;
3553 
3554     if (y_size == 0 || y_array == NULL)
3555     {
3556 	semsg(_("E353: Nothing in register %s"),
3557 		  regname == 0 ? (char_u *)"\"" : transchar(regname));
3558 	goto end;
3559     }
3560 
3561     if (y_type == MBLOCK)
3562     {
3563 	lnum = curwin->w_cursor.lnum + y_size + 1;
3564 	if (lnum > curbuf->b_ml.ml_line_count)
3565 	    lnum = curbuf->b_ml.ml_line_count + 1;
3566 	if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
3567 	    goto end;
3568     }
3569     else if (y_type == MLINE)
3570     {
3571 	lnum = curwin->w_cursor.lnum;
3572 #ifdef FEAT_FOLDING
3573 	/* Correct line number for closed fold.  Don't move the cursor yet,
3574 	 * u_save() uses it. */
3575 	if (dir == BACKWARD)
3576 	    (void)hasFolding(lnum, &lnum, NULL);
3577 	else
3578 	    (void)hasFolding(lnum, NULL, &lnum);
3579 #endif
3580 	if (dir == FORWARD)
3581 	    ++lnum;
3582 	/* In an empty buffer the empty line is going to be replaced, include
3583 	 * it in the saved lines. */
3584 	if ((BUFEMPTY() ? u_save(0, 2) : u_save(lnum - 1, lnum)) == FAIL)
3585 	    goto end;
3586 #ifdef FEAT_FOLDING
3587 	if (dir == FORWARD)
3588 	    curwin->w_cursor.lnum = lnum - 1;
3589 	else
3590 	    curwin->w_cursor.lnum = lnum;
3591 	curbuf->b_op_start = curwin->w_cursor;	/* for mark_adjust() */
3592 #endif
3593     }
3594     else if (u_save_cursor() == FAIL)
3595 	goto end;
3596 
3597     yanklen = (int)STRLEN(y_array[0]);
3598 
3599     if (ve_flags == VE_ALL && y_type == MCHAR)
3600     {
3601 	if (gchar_cursor() == TAB)
3602 	{
3603 	    /* Don't need to insert spaces when "p" on the last position of a
3604 	     * tab or "P" on the first position. */
3605 #ifdef FEAT_VARTABS
3606 	    int viscol = getviscol();
3607 	    if (dir == FORWARD
3608 		    ? tabstop_padding(viscol, curbuf->b_p_ts,
3609 						    curbuf->b_p_vts_array) != 1
3610 		    : curwin->w_cursor.coladd > 0)
3611 		coladvance_force(viscol);
3612 #else
3613 	    if (dir == FORWARD
3614 		    ? (int)curwin->w_cursor.coladd < curbuf->b_p_ts - 1
3615 						: curwin->w_cursor.coladd > 0)
3616 		coladvance_force(getviscol());
3617 #endif
3618 	    else
3619 		curwin->w_cursor.coladd = 0;
3620 	}
3621 	else if (curwin->w_cursor.coladd > 0 || gchar_cursor() == NUL)
3622 	    coladvance_force(getviscol() + (dir == FORWARD));
3623     }
3624 
3625     lnum = curwin->w_cursor.lnum;
3626     col = curwin->w_cursor.col;
3627 
3628     /*
3629      * Block mode
3630      */
3631     if (y_type == MBLOCK)
3632     {
3633 	int	c = gchar_cursor();
3634 	colnr_T	endcol2 = 0;
3635 
3636 	if (dir == FORWARD && c != NUL)
3637 	{
3638 	    if (ve_flags == VE_ALL)
3639 		getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
3640 	    else
3641 		getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
3642 
3643 	    if (has_mbyte)
3644 		/* move to start of next multi-byte character */
3645 		curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
3646 	    else
3647 	    if (c != TAB || ve_flags != VE_ALL)
3648 		++curwin->w_cursor.col;
3649 	    ++col;
3650 	}
3651 	else
3652 	    getvcol(curwin, &curwin->w_cursor, &col, NULL, &endcol2);
3653 
3654 	col += curwin->w_cursor.coladd;
3655 	if (ve_flags == VE_ALL
3656 		&& (curwin->w_cursor.coladd > 0
3657 		    || endcol2 == curwin->w_cursor.col))
3658 	{
3659 	    if (dir == FORWARD && c == NUL)
3660 		++col;
3661 	    if (dir != FORWARD && c != NUL)
3662 		++curwin->w_cursor.col;
3663 	    if (c == TAB)
3664 	    {
3665 		if (dir == BACKWARD && curwin->w_cursor.col)
3666 		    curwin->w_cursor.col--;
3667 		if (dir == FORWARD && col - 1 == endcol2)
3668 		    curwin->w_cursor.col++;
3669 	    }
3670 	}
3671 	curwin->w_cursor.coladd = 0;
3672 	bd.textcol = 0;
3673 	for (i = 0; i < y_size; ++i)
3674 	{
3675 	    int spaces;
3676 	    char shortline;
3677 
3678 	    bd.startspaces = 0;
3679 	    bd.endspaces = 0;
3680 	    vcol = 0;
3681 	    delcount = 0;
3682 
3683 	    /* add a new line */
3684 	    if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
3685 	    {
3686 		if (ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
3687 						   (colnr_T)1, FALSE) == FAIL)
3688 		    break;
3689 		++nr_lines;
3690 	    }
3691 	    /* get the old line and advance to the position to insert at */
3692 	    oldp = ml_get_curline();
3693 	    oldlen = (int)STRLEN(oldp);
3694 	    for (ptr = oldp; vcol < col && *ptr; )
3695 	    {
3696 		/* Count a tab for what it's worth (if list mode not on) */
3697 		incr = lbr_chartabsize_adv(oldp, &ptr, (colnr_T)vcol);
3698 		vcol += incr;
3699 	    }
3700 	    bd.textcol = (colnr_T)(ptr - oldp);
3701 
3702 	    shortline = (vcol < col) || (vcol == col && !*ptr) ;
3703 
3704 	    if (vcol < col) /* line too short, padd with spaces */
3705 		bd.startspaces = col - vcol;
3706 	    else if (vcol > col)
3707 	    {
3708 		bd.endspaces = vcol - col;
3709 		bd.startspaces = incr - bd.endspaces;
3710 		--bd.textcol;
3711 		delcount = 1;
3712 		if (has_mbyte)
3713 		    bd.textcol -= (*mb_head_off)(oldp, oldp + bd.textcol);
3714 		if (oldp[bd.textcol] != TAB)
3715 		{
3716 		    /* Only a Tab can be split into spaces.  Other
3717 		     * characters will have to be moved to after the
3718 		     * block, causing misalignment. */
3719 		    delcount = 0;
3720 		    bd.endspaces = 0;
3721 		}
3722 	    }
3723 
3724 	    yanklen = (int)STRLEN(y_array[i]);
3725 
3726 	    /* calculate number of spaces required to fill right side of block*/
3727 	    spaces = y_width + 1;
3728 	    for (j = 0; j < yanklen; j++)
3729 		spaces -= lbr_chartabsize(NULL, &y_array[i][j], 0);
3730 	    if (spaces < 0)
3731 		spaces = 0;
3732 
3733 	    /* insert the new text */
3734 	    totlen = count * (yanklen + spaces) + bd.startspaces + bd.endspaces;
3735 	    newp = alloc(totlen + oldlen + 1);
3736 	    if (newp == NULL)
3737 		break;
3738 	    /* copy part up to cursor to new line */
3739 	    ptr = newp;
3740 	    mch_memmove(ptr, oldp, (size_t)bd.textcol);
3741 	    ptr += bd.textcol;
3742 	    /* may insert some spaces before the new text */
3743 	    vim_memset(ptr, ' ', (size_t)bd.startspaces);
3744 	    ptr += bd.startspaces;
3745 	    /* insert the new text */
3746 	    for (j = 0; j < count; ++j)
3747 	    {
3748 		mch_memmove(ptr, y_array[i], (size_t)yanklen);
3749 		ptr += yanklen;
3750 
3751 		/* insert block's trailing spaces only if there's text behind */
3752 		if ((j < count - 1 || !shortline) && spaces)
3753 		{
3754 		    vim_memset(ptr, ' ', (size_t)spaces);
3755 		    ptr += spaces;
3756 		}
3757 	    }
3758 	    /* may insert some spaces after the new text */
3759 	    vim_memset(ptr, ' ', (size_t)bd.endspaces);
3760 	    ptr += bd.endspaces;
3761 	    /* move the text after the cursor to the end of the line. */
3762 	    mch_memmove(ptr, oldp + bd.textcol + delcount,
3763 				(size_t)(oldlen - bd.textcol - delcount + 1));
3764 	    ml_replace(curwin->w_cursor.lnum, newp, FALSE);
3765 
3766 	    ++curwin->w_cursor.lnum;
3767 	    if (i == 0)
3768 		curwin->w_cursor.col += bd.startspaces;
3769 	}
3770 
3771 	changed_lines(lnum, 0, curwin->w_cursor.lnum, nr_lines);
3772 
3773 	/* Set '[ mark. */
3774 	curbuf->b_op_start = curwin->w_cursor;
3775 	curbuf->b_op_start.lnum = lnum;
3776 
3777 	/* adjust '] mark */
3778 	curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
3779 	curbuf->b_op_end.col = bd.textcol + totlen - 1;
3780 	curbuf->b_op_end.coladd = 0;
3781 	if (flags & PUT_CURSEND)
3782 	{
3783 	    colnr_T len;
3784 
3785 	    curwin->w_cursor = curbuf->b_op_end;
3786 	    curwin->w_cursor.col++;
3787 
3788 	    /* in Insert mode we might be after the NUL, correct for that */
3789 	    len = (colnr_T)STRLEN(ml_get_curline());
3790 	    if (curwin->w_cursor.col > len)
3791 		curwin->w_cursor.col = len;
3792 	}
3793 	else
3794 	    curwin->w_cursor.lnum = lnum;
3795     }
3796     else
3797     {
3798 	/*
3799 	 * Character or Line mode
3800 	 */
3801 	if (y_type == MCHAR)
3802 	{
3803 	    /* if type is MCHAR, FORWARD is the same as BACKWARD on the next
3804 	     * char */
3805 	    if (dir == FORWARD && gchar_cursor() != NUL)
3806 	    {
3807 		if (has_mbyte)
3808 		{
3809 		    int bytelen = (*mb_ptr2len)(ml_get_cursor());
3810 
3811 		    /* put it on the next of the multi-byte character. */
3812 		    col += bytelen;
3813 		    if (yanklen)
3814 		    {
3815 			curwin->w_cursor.col += bytelen;
3816 			curbuf->b_op_end.col += bytelen;
3817 		    }
3818 		}
3819 		else
3820 		{
3821 		    ++col;
3822 		    if (yanklen)
3823 		    {
3824 			++curwin->w_cursor.col;
3825 			++curbuf->b_op_end.col;
3826 		    }
3827 		}
3828 	    }
3829 	    curbuf->b_op_start = curwin->w_cursor;
3830 	}
3831 	/*
3832 	 * Line mode: BACKWARD is the same as FORWARD on the previous line
3833 	 */
3834 	else if (dir == BACKWARD)
3835 	    --lnum;
3836 	new_cursor = curwin->w_cursor;
3837 
3838 	/*
3839 	 * simple case: insert into current line
3840 	 */
3841 	if (y_type == MCHAR && y_size == 1)
3842 	{
3843 	    linenr_T end_lnum = 0; /* init for gcc */
3844 
3845 	    if (VIsual_active)
3846 	    {
3847 		end_lnum = curbuf->b_visual.vi_end.lnum;
3848 		if (end_lnum < curbuf->b_visual.vi_start.lnum)
3849 		    end_lnum = curbuf->b_visual.vi_start.lnum;
3850 	    }
3851 
3852 	    do {
3853 		totlen = count * yanklen;
3854 		if (totlen > 0)
3855 		{
3856 		    oldp = ml_get(lnum);
3857 		    if (VIsual_active && col > (int)STRLEN(oldp))
3858 		    {
3859 			lnum++;
3860 			continue;
3861 		    }
3862 		    newp = alloc(STRLEN(oldp) + totlen + 1);
3863 		    if (newp == NULL)
3864 			goto end;	/* alloc() gave an error message */
3865 		    mch_memmove(newp, oldp, (size_t)col);
3866 		    ptr = newp + col;
3867 		    for (i = 0; i < count; ++i)
3868 		    {
3869 			mch_memmove(ptr, y_array[0], (size_t)yanklen);
3870 			ptr += yanklen;
3871 		    }
3872 		    STRMOVE(ptr, oldp + col);
3873 		    ml_replace(lnum, newp, FALSE);
3874 		    /* Place cursor on last putted char. */
3875 		    if (lnum == curwin->w_cursor.lnum)
3876 		    {
3877 			/* make sure curwin->w_virtcol is updated */
3878 			changed_cline_bef_curs();
3879 			curwin->w_cursor.col += (colnr_T)(totlen - 1);
3880 		    }
3881 		}
3882 		if (VIsual_active)
3883 		    lnum++;
3884 	    } while (VIsual_active && lnum <= end_lnum);
3885 
3886 	    if (VIsual_active) /* reset lnum to the last visual line */
3887 		lnum--;
3888 
3889 	    curbuf->b_op_end = curwin->w_cursor;
3890 	    /* For "CTRL-O p" in Insert mode, put cursor after last char */
3891 	    if (totlen && (restart_edit != 0 || (flags & PUT_CURSEND)))
3892 		++curwin->w_cursor.col;
3893 	    changed_bytes(lnum, col);
3894 	}
3895 	else
3896 	{
3897 	    /*
3898 	     * Insert at least one line.  When y_type is MCHAR, break the first
3899 	     * line in two.
3900 	     */
3901 	    for (cnt = 1; cnt <= count; ++cnt)
3902 	    {
3903 		i = 0;
3904 		if (y_type == MCHAR)
3905 		{
3906 		    /*
3907 		     * Split the current line in two at the insert position.
3908 		     * First insert y_array[size - 1] in front of second line.
3909 		     * Then append y_array[0] to first line.
3910 		     */
3911 		    lnum = new_cursor.lnum;
3912 		    ptr = ml_get(lnum) + col;
3913 		    totlen = (int)STRLEN(y_array[y_size - 1]);
3914 		    newp = alloc(STRLEN(ptr) + totlen + 1);
3915 		    if (newp == NULL)
3916 			goto error;
3917 		    STRCPY(newp, y_array[y_size - 1]);
3918 		    STRCAT(newp, ptr);
3919 		    /* insert second line */
3920 		    ml_append(lnum, newp, (colnr_T)0, FALSE);
3921 		    vim_free(newp);
3922 
3923 		    oldp = ml_get(lnum);
3924 		    newp = alloc(col + yanklen + 1);
3925 		    if (newp == NULL)
3926 			goto error;
3927 					    /* copy first part of line */
3928 		    mch_memmove(newp, oldp, (size_t)col);
3929 					    /* append to first line */
3930 		    mch_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
3931 		    ml_replace(lnum, newp, FALSE);
3932 
3933 		    curwin->w_cursor.lnum = lnum;
3934 		    i = 1;
3935 		}
3936 
3937 		for (; i < y_size; ++i)
3938 		{
3939 		    if ((y_type != MCHAR || i < y_size - 1)
3940 			    && ml_append(lnum, y_array[i], (colnr_T)0, FALSE)
3941 								      == FAIL)
3942 			    goto error;
3943 		    lnum++;
3944 		    ++nr_lines;
3945 		    if (flags & PUT_FIXINDENT)
3946 		    {
3947 			old_pos = curwin->w_cursor;
3948 			curwin->w_cursor.lnum = lnum;
3949 			ptr = ml_get(lnum);
3950 			if (cnt == count && i == y_size - 1)
3951 			    lendiff = (int)STRLEN(ptr);
3952 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)
3953 			if (*ptr == '#' && preprocs_left())
3954 			    indent = 0;     /* Leave # lines at start */
3955 			else
3956 #endif
3957 			     if (*ptr == NUL)
3958 			    indent = 0;     /* Ignore empty lines */
3959 			else if (first_indent)
3960 			{
3961 			    indent_diff = orig_indent - get_indent();
3962 			    indent = orig_indent;
3963 			    first_indent = FALSE;
3964 			}
3965 			else if ((indent = get_indent() + indent_diff) < 0)
3966 			    indent = 0;
3967 			(void)set_indent(indent, 0);
3968 			curwin->w_cursor = old_pos;
3969 			/* remember how many chars were removed */
3970 			if (cnt == count && i == y_size - 1)
3971 			    lendiff -= (int)STRLEN(ml_get(lnum));
3972 		    }
3973 		}
3974 	    }
3975 
3976 error:
3977 	    /* Adjust marks. */
3978 	    if (y_type == MLINE)
3979 	    {
3980 		curbuf->b_op_start.col = 0;
3981 		if (dir == FORWARD)
3982 		    curbuf->b_op_start.lnum++;
3983 	    }
3984 	    /* Skip mark_adjust when adding lines after the last one, there
3985 	     * can't be marks there. But still needed in diff mode. */
3986 	    if (curbuf->b_op_start.lnum + (y_type == MCHAR) - 1 + nr_lines
3987 						 < curbuf->b_ml.ml_line_count
3988 #ifdef FEAT_DIFF
3989 						 || curwin->w_p_diff
3990 #endif
3991 						 )
3992 		mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
3993 					     (linenr_T)MAXLNUM, nr_lines, 0L);
3994 
3995 	    /* note changed text for displaying and folding */
3996 	    if (y_type == MCHAR)
3997 		changed_lines(curwin->w_cursor.lnum, col,
3998 					 curwin->w_cursor.lnum + 1, nr_lines);
3999 	    else
4000 		changed_lines(curbuf->b_op_start.lnum, 0,
4001 					   curbuf->b_op_start.lnum, nr_lines);
4002 
4003 	    /* put '] mark at last inserted character */
4004 	    curbuf->b_op_end.lnum = lnum;
4005 	    /* correct length for change in indent */
4006 	    col = (colnr_T)STRLEN(y_array[y_size - 1]) - lendiff;
4007 	    if (col > 1)
4008 		curbuf->b_op_end.col = col - 1;
4009 	    else
4010 		curbuf->b_op_end.col = 0;
4011 
4012 	    if (flags & PUT_CURSLINE)
4013 	    {
4014 		/* ":put": put cursor on last inserted line */
4015 		curwin->w_cursor.lnum = lnum;
4016 		beginline(BL_WHITE | BL_FIX);
4017 	    }
4018 	    else if (flags & PUT_CURSEND)
4019 	    {
4020 		/* put cursor after inserted text */
4021 		if (y_type == MLINE)
4022 		{
4023 		    if (lnum >= curbuf->b_ml.ml_line_count)
4024 			curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
4025 		    else
4026 			curwin->w_cursor.lnum = lnum + 1;
4027 		    curwin->w_cursor.col = 0;
4028 		}
4029 		else
4030 		{
4031 		    curwin->w_cursor.lnum = lnum;
4032 		    curwin->w_cursor.col = col;
4033 		}
4034 	    }
4035 	    else if (y_type == MLINE)
4036 	    {
4037 		/* put cursor on first non-blank in first inserted line */
4038 		curwin->w_cursor.col = 0;
4039 		if (dir == FORWARD)
4040 		    ++curwin->w_cursor.lnum;
4041 		beginline(BL_WHITE | BL_FIX);
4042 	    }
4043 	    else	/* put cursor on first inserted character */
4044 		curwin->w_cursor = new_cursor;
4045 	}
4046     }
4047 
4048     msgmore(nr_lines);
4049     curwin->w_set_curswant = TRUE;
4050 
4051 end:
4052     if (allocated)
4053 	vim_free(insert_string);
4054     if (regname == '=')
4055 	vim_free(y_array);
4056 
4057     VIsual_active = FALSE;
4058 
4059     /* If the cursor is past the end of the line put it at the end. */
4060     adjust_cursor_eol();
4061 }
4062 
4063 /*
4064  * When the cursor is on the NUL past the end of the line and it should not be
4065  * there move it left.
4066  */
4067     void
4068 adjust_cursor_eol(void)
4069 {
4070     if (curwin->w_cursor.col > 0
4071 	    && gchar_cursor() == NUL
4072 	    && (ve_flags & VE_ONEMORE) == 0
4073 	    && !(restart_edit || (State & INSERT)))
4074     {
4075 	/* Put the cursor on the last character in the line. */
4076 	dec_cursor();
4077 
4078 	if (ve_flags == VE_ALL)
4079 	{
4080 	    colnr_T	    scol, ecol;
4081 
4082 	    /* Coladd is set to the width of the last character. */
4083 	    getvcol(curwin, &curwin->w_cursor, &scol, NULL, &ecol);
4084 	    curwin->w_cursor.coladd = ecol - scol + 1;
4085 	}
4086     }
4087 }
4088 
4089 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) || defined(PROTO)
4090 /*
4091  * Return TRUE if lines starting with '#' should be left aligned.
4092  */
4093     int
4094 preprocs_left(void)
4095 {
4096     return
4097 # ifdef FEAT_SMARTINDENT
4098 #  ifdef FEAT_CINDENT
4099 	(curbuf->b_p_si && !curbuf->b_p_cin) ||
4100 #  else
4101 	curbuf->b_p_si
4102 #  endif
4103 # endif
4104 # ifdef FEAT_CINDENT
4105 	(curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
4106 					   && curbuf->b_ind_hash_comment == 0)
4107 # endif
4108 	;
4109 }
4110 #endif
4111 
4112 /*
4113  * Return the character name of the register with the given number.
4114  */
4115     int
4116 get_register_name(int num)
4117 {
4118     if (num == -1)
4119 	return '"';
4120     else if (num < 10)
4121 	return num + '0';
4122     else if (num == DELETION_REGISTER)
4123 	return '-';
4124 #ifdef FEAT_CLIPBOARD
4125     else if (num == STAR_REGISTER)
4126 	return '*';
4127     else if (num == PLUS_REGISTER)
4128 	return '+';
4129 #endif
4130     else
4131     {
4132 #ifdef EBCDIC
4133 	int i;
4134 
4135 	/* EBCDIC is really braindead ... */
4136 	i = 'a' + (num - 10);
4137 	if (i > 'i')
4138 	    i += 7;
4139 	if (i > 'r')
4140 	    i += 8;
4141 	return i;
4142 #else
4143 	return num + 'a' - 10;
4144 #endif
4145     }
4146 }
4147 
4148 /*
4149  * ":dis" and ":registers": Display the contents of the yank registers.
4150  */
4151     void
4152 ex_display(exarg_T *eap)
4153 {
4154     int		i, n;
4155     long	j;
4156     char_u	*p;
4157     yankreg_T	*yb;
4158     int		name;
4159     int		attr;
4160     char_u	*arg = eap->arg;
4161     int		clen;
4162 
4163     if (arg != NULL && *arg == NUL)
4164 	arg = NULL;
4165     attr = HL_ATTR(HLF_8);
4166 
4167     /* Highlight title */
4168     msg_puts_title(_("\n--- Registers ---"));
4169     for (i = -1; i < NUM_REGISTERS && !got_int; ++i)
4170     {
4171 	name = get_register_name(i);
4172 	if (arg != NULL && vim_strchr(arg, name) == NULL
4173 #ifdef ONE_CLIPBOARD
4174 	    /* Star register and plus register contain the same thing. */
4175 		&& (name != '*' || vim_strchr(arg, '+') == NULL)
4176 #endif
4177 		)
4178 	    continue;	    /* did not ask for this register */
4179 
4180 #ifdef FEAT_CLIPBOARD
4181 	/* Adjust register name for "unnamed" in 'clipboard'.
4182 	 * When it's a clipboard register, fill it with the current contents
4183 	 * of the clipboard.  */
4184 	adjust_clip_reg(&name);
4185 	(void)may_get_selection(name);
4186 #endif
4187 
4188 	if (i == -1)
4189 	{
4190 	    if (y_previous != NULL)
4191 		yb = y_previous;
4192 	    else
4193 		yb = &(y_regs[0]);
4194 	}
4195 	else
4196 	    yb = &(y_regs[i]);
4197 
4198 #ifdef FEAT_EVAL
4199 	if (name == MB_TOLOWER(redir_reg)
4200 		|| (redir_reg == '"' && yb == y_previous))
4201 	    continue;	    /* do not list register being written to, the
4202 			     * pointer can be freed */
4203 #endif
4204 
4205 	if (yb->y_array != NULL)
4206 	{
4207 	    msg_putchar('\n');
4208 	    msg_putchar('"');
4209 	    msg_putchar(name);
4210 	    msg_puts("   ");
4211 
4212 	    n = (int)Columns - 6;
4213 	    for (j = 0; j < yb->y_size && n > 1; ++j)
4214 	    {
4215 		if (j)
4216 		{
4217 		    msg_puts_attr("^J", attr);
4218 		    n -= 2;
4219 		}
4220 		for (p = yb->y_array[j]; *p && (n -= ptr2cells(p)) >= 0; ++p)
4221 		{
4222 		    clen = (*mb_ptr2len)(p);
4223 		    msg_outtrans_len(p, clen);
4224 		    p += clen - 1;
4225 		}
4226 	    }
4227 	    if (n > 1 && yb->y_type == MLINE)
4228 		msg_puts_attr("^J", attr);
4229 	    out_flush();		    /* show one line at a time */
4230 	}
4231 	ui_breakcheck();
4232     }
4233 
4234     /*
4235      * display last inserted text
4236      */
4237     if ((p = get_last_insert()) != NULL
4238 		 && (arg == NULL || vim_strchr(arg, '.') != NULL) && !got_int)
4239     {
4240 	msg_puts("\n\".   ");
4241 	dis_msg(p, TRUE);
4242     }
4243 
4244     /*
4245      * display last command line
4246      */
4247     if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL)
4248 								  && !got_int)
4249     {
4250 	msg_puts("\n\":   ");
4251 	dis_msg(last_cmdline, FALSE);
4252     }
4253 
4254     /*
4255      * display current file name
4256      */
4257     if (curbuf->b_fname != NULL
4258 	    && (arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
4259     {
4260 	msg_puts("\n\"%   ");
4261 	dis_msg(curbuf->b_fname, FALSE);
4262     }
4263 
4264     /*
4265      * display alternate file name
4266      */
4267     if ((arg == NULL || vim_strchr(arg, '%') != NULL) && !got_int)
4268     {
4269 	char_u	    *fname;
4270 	linenr_T    dummy;
4271 
4272 	if (buflist_name_nr(0, &fname, &dummy) != FAIL)
4273 	{
4274 	    msg_puts("\n\"#   ");
4275 	    dis_msg(fname, FALSE);
4276 	}
4277     }
4278 
4279     /*
4280      * display last search pattern
4281      */
4282     if (last_search_pat() != NULL
4283 		 && (arg == NULL || vim_strchr(arg, '/') != NULL) && !got_int)
4284     {
4285 	msg_puts("\n\"/   ");
4286 	dis_msg(last_search_pat(), FALSE);
4287     }
4288 
4289 #ifdef FEAT_EVAL
4290     /*
4291      * display last used expression
4292      */
4293     if (expr_line != NULL && (arg == NULL || vim_strchr(arg, '=') != NULL)
4294 								  && !got_int)
4295     {
4296 	msg_puts("\n\"=   ");
4297 	dis_msg(expr_line, FALSE);
4298     }
4299 #endif
4300 }
4301 
4302 /*
4303  * display a string for do_dis()
4304  * truncate at end of screen line
4305  */
4306     static void
4307 dis_msg(
4308     char_u	*p,
4309     int		skip_esc)	    /* if TRUE, ignore trailing ESC */
4310 {
4311     int		n;
4312     int		l;
4313 
4314     n = (int)Columns - 6;
4315     while (*p != NUL
4316 	    && !(*p == ESC && skip_esc && *(p + 1) == NUL)
4317 	    && (n -= ptr2cells(p)) >= 0)
4318     {
4319 	if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1)
4320 	{
4321 	    msg_outtrans_len(p, l);
4322 	    p += l;
4323 	}
4324 	else
4325 	    msg_outtrans_len(p++, 1);
4326     }
4327     ui_breakcheck();
4328 }
4329 
4330 #if defined(FEAT_COMMENTS) || defined(PROTO)
4331 /*
4332  * If "process" is TRUE and the line begins with a comment leader (possibly
4333  * after some white space), return a pointer to the text after it. Put a boolean
4334  * value indicating whether the line ends with an unclosed comment in
4335  * "is_comment".
4336  * line - line to be processed,
4337  * process - if FALSE, will only check whether the line ends with an unclosed
4338  *	     comment,
4339  * include_space - whether to also skip space following the comment leader,
4340  * is_comment - will indicate whether the current line ends with an unclosed
4341  *		comment.
4342  */
4343     char_u *
4344 skip_comment(
4345     char_u   *line,
4346     int      process,
4347     int	     include_space,
4348     int      *is_comment)
4349 {
4350     char_u *comment_flags = NULL;
4351     int    lead_len;
4352     int    leader_offset = get_last_leader_offset(line, &comment_flags);
4353 
4354     *is_comment = FALSE;
4355     if (leader_offset != -1)
4356     {
4357 	/* Let's check whether the line ends with an unclosed comment.
4358 	 * If the last comment leader has COM_END in flags, there's no comment.
4359 	 */
4360 	while (*comment_flags)
4361 	{
4362 	    if (*comment_flags == COM_END
4363 		    || *comment_flags == ':')
4364 		break;
4365 	    ++comment_flags;
4366 	}
4367 	if (*comment_flags != COM_END)
4368 	    *is_comment = TRUE;
4369     }
4370 
4371     if (process == FALSE)
4372 	return line;
4373 
4374     lead_len = get_leader_len(line, &comment_flags, FALSE, include_space);
4375 
4376     if (lead_len == 0)
4377 	return line;
4378 
4379     /* Find:
4380      * - COM_END,
4381      * - colon,
4382      * whichever comes first.
4383      */
4384     while (*comment_flags)
4385     {
4386 	if (*comment_flags == COM_END
4387 		|| *comment_flags == ':')
4388 	    break;
4389 	++comment_flags;
4390     }
4391 
4392     /* If we found a colon, it means that we are not processing a line
4393      * starting with a closing part of a three-part comment. That's good,
4394      * because we don't want to remove those as this would be annoying.
4395      */
4396     if (*comment_flags == ':' || *comment_flags == NUL)
4397 	line += lead_len;
4398 
4399     return line;
4400 }
4401 #endif
4402 
4403 /*
4404  * Join 'count' lines (minimal 2) at cursor position.
4405  * When "save_undo" is TRUE save lines for undo first.
4406  * Set "use_formatoptions" to FALSE when e.g. processing backspace and comment
4407  * leaders should not be removed.
4408  * When setmark is TRUE, sets the '[ and '] mark, else, the caller is expected
4409  * to set those marks.
4410  *
4411  * return FAIL for failure, OK otherwise
4412  */
4413     int
4414 do_join(
4415     long    count,
4416     int	    insert_space,
4417     int	    save_undo,
4418     int	    use_formatoptions UNUSED,
4419     int	    setmark)
4420 {
4421     char_u	*curr = NULL;
4422     char_u      *curr_start = NULL;
4423     char_u	*cend;
4424     char_u	*newp;
4425     char_u	*spaces;	/* number of spaces inserted before a line */
4426     int		endcurr1 = NUL;
4427     int		endcurr2 = NUL;
4428     int		currsize = 0;	/* size of the current line */
4429     int		sumsize = 0;	/* size of the long new line */
4430     linenr_T	t;
4431     colnr_T	col = 0;
4432     int		ret = OK;
4433 #if defined(FEAT_COMMENTS) || defined(PROTO)
4434     int		*comments = NULL;
4435     int		remove_comments = (use_formatoptions == TRUE)
4436 				  && has_format_option(FO_REMOVE_COMS);
4437     int		prev_was_comment;
4438 #endif
4439 #ifdef FEAT_TEXT_PROP
4440     textprop_T	**prop_lines = NULL;
4441     int		*prop_lengths = NULL;
4442 #endif
4443 
4444     if (save_undo && u_save((linenr_T)(curwin->w_cursor.lnum - 1),
4445 			    (linenr_T)(curwin->w_cursor.lnum + count)) == FAIL)
4446 	return FAIL;
4447 
4448     /* Allocate an array to store the number of spaces inserted before each
4449      * line.  We will use it to pre-compute the length of the new line and the
4450      * proper placement of each original line in the new one. */
4451     spaces = lalloc_clear(count, TRUE);
4452     if (spaces == NULL)
4453 	return FAIL;
4454 #if defined(FEAT_COMMENTS) || defined(PROTO)
4455     if (remove_comments)
4456     {
4457 	comments = lalloc_clear(count * sizeof(int), TRUE);
4458 	if (comments == NULL)
4459 	{
4460 	    vim_free(spaces);
4461 	    return FAIL;
4462 	}
4463     }
4464 #endif
4465 
4466     /*
4467      * Don't move anything yet, just compute the final line length
4468      * and setup the array of space strings lengths
4469      * This loops forward over the joined lines.
4470      */
4471     for (t = 0; t < count; ++t)
4472     {
4473 	curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t));
4474 	if (t == 0 && setmark)
4475 	{
4476 	    /* Set the '[ mark. */
4477 	    curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum;
4478 	    curwin->w_buffer->b_op_start.col  = (colnr_T)STRLEN(curr);
4479 	}
4480 #if defined(FEAT_COMMENTS) || defined(PROTO)
4481 	if (remove_comments)
4482 	{
4483 	    /* We don't want to remove the comment leader if the
4484 	     * previous line is not a comment. */
4485 	    if (t > 0 && prev_was_comment)
4486 	    {
4487 
4488 		char_u *new_curr = skip_comment(curr, TRUE, insert_space,
4489 							   &prev_was_comment);
4490 		comments[t] = (int)(new_curr - curr);
4491 		curr = new_curr;
4492 	    }
4493 	    else
4494 		curr = skip_comment(curr, FALSE, insert_space,
4495 							   &prev_was_comment);
4496 	}
4497 #endif
4498 
4499 	if (insert_space && t > 0)
4500 	{
4501 	    curr = skipwhite(curr);
4502 	    if (*curr != ')' && currsize != 0 && endcurr1 != TAB
4503 		    && (!has_format_option(FO_MBYTE_JOIN)
4504 			|| (mb_ptr2char(curr) < 0x100 && endcurr1 < 0x100))
4505 		    && (!has_format_option(FO_MBYTE_JOIN2)
4506 			|| mb_ptr2char(curr) < 0x100 || endcurr1 < 0x100)
4507 	       )
4508 	    {
4509 		/* don't add a space if the line is ending in a space */
4510 		if (endcurr1 == ' ')
4511 		    endcurr1 = endcurr2;
4512 		else
4513 		    ++spaces[t];
4514 		/* extra space when 'joinspaces' set and line ends in '.' */
4515 		if (       p_js
4516 			&& (endcurr1 == '.'
4517 			    || (vim_strchr(p_cpo, CPO_JOINSP) == NULL
4518 				&& (endcurr1 == '?' || endcurr1 == '!'))))
4519 		    ++spaces[t];
4520 	    }
4521 	}
4522 	currsize = (int)STRLEN(curr);
4523 	sumsize += currsize + spaces[t];
4524 	endcurr1 = endcurr2 = NUL;
4525 	if (insert_space && currsize > 0)
4526 	{
4527 	    if (has_mbyte)
4528 	    {
4529 		cend = curr + currsize;
4530 		MB_PTR_BACK(curr, cend);
4531 		endcurr1 = (*mb_ptr2char)(cend);
4532 		if (cend > curr)
4533 		{
4534 		    MB_PTR_BACK(curr, cend);
4535 		    endcurr2 = (*mb_ptr2char)(cend);
4536 		}
4537 	    }
4538 	    else
4539 	    {
4540 		endcurr1 = *(curr + currsize - 1);
4541 		if (currsize > 1)
4542 		    endcurr2 = *(curr + currsize - 2);
4543 	    }
4544 	}
4545 	line_breakcheck();
4546 	if (got_int)
4547 	{
4548 	    ret = FAIL;
4549 	    goto theend;
4550 	}
4551     }
4552 
4553     /* store the column position before last line */
4554     col = sumsize - currsize - spaces[count - 1];
4555 
4556     /* allocate the space for the new line */
4557     newp = alloc(sumsize + 1);
4558     cend = newp + sumsize;
4559     *cend = 0;
4560 
4561 #ifdef FEAT_TEXT_PROP
4562     // We need to move properties of the lines that are going to be deleted to
4563     // the new long one.
4564     if (curbuf->b_has_textprop && !text_prop_frozen)
4565     {
4566 	// Allocate an array to copy the text properties of joined lines into.
4567 	// And another array to store the number of properties in each line.
4568 	prop_lines = ALLOC_CLEAR_MULT(textprop_T *, count - 1);
4569 	prop_lengths = ALLOC_CLEAR_MULT(int, count - 1);
4570 	if (prop_lengths == NULL)
4571 	    VIM_CLEAR(prop_lines);
4572     }
4573 #endif
4574 
4575     /*
4576      * Move affected lines to the new long one.
4577      * This loops backwards over the joined lines, including the original line.
4578      *
4579      * Move marks from each deleted line to the joined line, adjusting the
4580      * column.  This is not Vi compatible, but Vi deletes the marks, thus that
4581      * should not really be a problem.
4582      */
4583     for (t = count - 1; ; --t)
4584     {
4585 	int spaces_removed;
4586 
4587 	cend -= currsize;
4588 	mch_memmove(cend, curr, (size_t)currsize);
4589 	if (spaces[t] > 0)
4590 	{
4591 	    cend -= spaces[t];
4592 	    vim_memset(cend, ' ', (size_t)(spaces[t]));
4593 	}
4594 
4595 	// If deleting more spaces than adding, the cursor moves no more than
4596 	// what is added if it is inside these spaces.
4597 	spaces_removed = (curr - curr_start) - spaces[t];
4598 
4599 	mark_col_adjust(curwin->w_cursor.lnum + t, (colnr_T)0, (linenr_T)-t,
4600 			 (long)(cend - newp - spaces_removed), spaces_removed);
4601 	if (t == 0)
4602 	    break;
4603 #ifdef FEAT_TEXT_PROP
4604 	if (prop_lines != NULL)
4605 	    adjust_props_for_join(curwin->w_cursor.lnum + t,
4606 				      prop_lines + t - 1, prop_lengths + t - 1,
4607 			 (long)(cend - newp - spaces_removed), spaces_removed);
4608 #endif
4609 
4610 	curr = curr_start = ml_get((linenr_T)(curwin->w_cursor.lnum + t - 1));
4611 #if defined(FEAT_COMMENTS)
4612 	if (remove_comments)
4613 	    curr += comments[t - 1];
4614 #endif
4615 	if (insert_space && t > 1)
4616 	    curr = skipwhite(curr);
4617 	currsize = (int)STRLEN(curr);
4618     }
4619 
4620 #ifdef FEAT_TEXT_PROP
4621     if (prop_lines != NULL)
4622 	join_prop_lines(curwin->w_cursor.lnum, newp,
4623 					      prop_lines, prop_lengths, count);
4624     else
4625 #endif
4626 	ml_replace(curwin->w_cursor.lnum, newp, FALSE);
4627 
4628     if (setmark)
4629     {
4630 	/* Set the '] mark. */
4631 	curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum;
4632 	curwin->w_buffer->b_op_end.col  = (colnr_T)sumsize;
4633     }
4634 
4635     /* Only report the change in the first line here, del_lines() will report
4636      * the deleted line. */
4637     changed_lines(curwin->w_cursor.lnum, currsize,
4638 					       curwin->w_cursor.lnum + 1, 0L);
4639     /*
4640      * Delete following lines. To do this we move the cursor there
4641      * briefly, and then move it back. After del_lines() the cursor may
4642      * have moved up (last line deleted), so the current lnum is kept in t.
4643      */
4644     t = curwin->w_cursor.lnum;
4645     ++curwin->w_cursor.lnum;
4646     del_lines(count - 1, FALSE);
4647     curwin->w_cursor.lnum = t;
4648 
4649     /*
4650      * Set the cursor column:
4651      * Vi compatible: use the column of the first join
4652      * vim:	      use the column of the last join
4653      */
4654     curwin->w_cursor.col =
4655 		    (vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col);
4656     check_cursor_col();
4657 
4658     curwin->w_cursor.coladd = 0;
4659     curwin->w_set_curswant = TRUE;
4660 
4661 theend:
4662     vim_free(spaces);
4663 #if defined(FEAT_COMMENTS) || defined(PROTO)
4664     if (remove_comments)
4665 	vim_free(comments);
4666 #endif
4667     return ret;
4668 }
4669 
4670 #ifdef FEAT_COMMENTS
4671 /*
4672  * Return TRUE if the two comment leaders given are the same.  "lnum" is
4673  * the first line.  White-space is ignored.  Note that the whole of
4674  * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
4675  */
4676     static int
4677 same_leader(
4678     linenr_T lnum,
4679     int	    leader1_len,
4680     char_u  *leader1_flags,
4681     int	    leader2_len,
4682     char_u  *leader2_flags)
4683 {
4684     int	    idx1 = 0, idx2 = 0;
4685     char_u  *p;
4686     char_u  *line1;
4687     char_u  *line2;
4688 
4689     if (leader1_len == 0)
4690 	return (leader2_len == 0);
4691 
4692     /*
4693      * If first leader has 'f' flag, the lines can be joined only if the
4694      * second line does not have a leader.
4695      * If first leader has 'e' flag, the lines can never be joined.
4696      * If fist leader has 's' flag, the lines can only be joined if there is
4697      * some text after it and the second line has the 'm' flag.
4698      */
4699     if (leader1_flags != NULL)
4700     {
4701 	for (p = leader1_flags; *p && *p != ':'; ++p)
4702 	{
4703 	    if (*p == COM_FIRST)
4704 		return (leader2_len == 0);
4705 	    if (*p == COM_END)
4706 		return FALSE;
4707 	    if (*p == COM_START)
4708 	    {
4709 		if (*(ml_get(lnum) + leader1_len) == NUL)
4710 		    return FALSE;
4711 		if (leader2_flags == NULL || leader2_len == 0)
4712 		    return FALSE;
4713 		for (p = leader2_flags; *p && *p != ':'; ++p)
4714 		    if (*p == COM_MIDDLE)
4715 			return TRUE;
4716 		return FALSE;
4717 	    }
4718 	}
4719     }
4720 
4721     /*
4722      * Get current line and next line, compare the leaders.
4723      * The first line has to be saved, only one line can be locked at a time.
4724      */
4725     line1 = vim_strsave(ml_get(lnum));
4726     if (line1 != NULL)
4727     {
4728 	for (idx1 = 0; VIM_ISWHITE(line1[idx1]); ++idx1)
4729 	    ;
4730 	line2 = ml_get(lnum + 1);
4731 	for (idx2 = 0; idx2 < leader2_len; ++idx2)
4732 	{
4733 	    if (!VIM_ISWHITE(line2[idx2]))
4734 	    {
4735 		if (line1[idx1++] != line2[idx2])
4736 		    break;
4737 	    }
4738 	    else
4739 		while (VIM_ISWHITE(line1[idx1]))
4740 		    ++idx1;
4741 	}
4742 	vim_free(line1);
4743     }
4744     return (idx2 == leader2_len && idx1 == leader1_len);
4745 }
4746 #endif
4747 
4748 /*
4749  * Implementation of the format operator 'gq'.
4750  */
4751     void
4752 op_format(
4753     oparg_T	*oap,
4754     int		keep_cursor)		/* keep cursor on same text char */
4755 {
4756     long	old_line_count = curbuf->b_ml.ml_line_count;
4757 
4758     /* Place the cursor where the "gq" or "gw" command was given, so that "u"
4759      * can put it back there. */
4760     curwin->w_cursor = oap->cursor_start;
4761 
4762     if (u_save((linenr_T)(oap->start.lnum - 1),
4763 				       (linenr_T)(oap->end.lnum + 1)) == FAIL)
4764 	return;
4765     curwin->w_cursor = oap->start;
4766 
4767     if (oap->is_VIsual)
4768 	/* When there is no change: need to remove the Visual selection */
4769 	redraw_curbuf_later(INVERTED);
4770 
4771     /* Set '[ mark at the start of the formatted area */
4772     curbuf->b_op_start = oap->start;
4773 
4774     /* For "gw" remember the cursor position and put it back below (adjusted
4775      * for joined and split lines). */
4776     if (keep_cursor)
4777 	saved_cursor = oap->cursor_start;
4778 
4779     format_lines(oap->line_count, keep_cursor);
4780 
4781     /*
4782      * Leave the cursor at the first non-blank of the last formatted line.
4783      * If the cursor was moved one line back (e.g. with "Q}") go to the next
4784      * line, so "." will do the next lines.
4785      */
4786     if (oap->end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
4787 	++curwin->w_cursor.lnum;
4788     beginline(BL_WHITE | BL_FIX);
4789     old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
4790     msgmore(old_line_count);
4791 
4792     /* put '] mark on the end of the formatted area */
4793     curbuf->b_op_end = curwin->w_cursor;
4794 
4795     if (keep_cursor)
4796     {
4797 	curwin->w_cursor = saved_cursor;
4798 	saved_cursor.lnum = 0;
4799     }
4800 
4801     if (oap->is_VIsual)
4802     {
4803 	win_T	*wp;
4804 
4805 	FOR_ALL_WINDOWS(wp)
4806 	{
4807 	    if (wp->w_old_cursor_lnum != 0)
4808 	    {
4809 		/* When lines have been inserted or deleted, adjust the end of
4810 		 * the Visual area to be redrawn. */
4811 		if (wp->w_old_cursor_lnum > wp->w_old_visual_lnum)
4812 		    wp->w_old_cursor_lnum += old_line_count;
4813 		else
4814 		    wp->w_old_visual_lnum += old_line_count;
4815 	    }
4816 	}
4817     }
4818 }
4819 
4820 #if defined(FEAT_EVAL) || defined(PROTO)
4821 /*
4822  * Implementation of the format operator 'gq' for when using 'formatexpr'.
4823  */
4824     void
4825 op_formatexpr(oparg_T *oap)
4826 {
4827     if (oap->is_VIsual)
4828 	/* When there is no change: need to remove the Visual selection */
4829 	redraw_curbuf_later(INVERTED);
4830 
4831     if (fex_format(oap->start.lnum, oap->line_count, NUL) != 0)
4832 	/* As documented: when 'formatexpr' returns non-zero fall back to
4833 	 * internal formatting. */
4834 	op_format(oap, FALSE);
4835 }
4836 
4837     int
4838 fex_format(
4839     linenr_T	lnum,
4840     long	count,
4841     int		c)	/* character to be inserted */
4842 {
4843     int		use_sandbox = was_set_insecurely((char_u *)"formatexpr",
4844 								   OPT_LOCAL);
4845     int		r;
4846     char_u	*fex;
4847 
4848     /*
4849      * Set v:lnum to the first line number and v:count to the number of lines.
4850      * Set v:char to the character to be inserted (can be NUL).
4851      */
4852     set_vim_var_nr(VV_LNUM, lnum);
4853     set_vim_var_nr(VV_COUNT, count);
4854     set_vim_var_char(c);
4855 
4856     /* Make a copy, the option could be changed while calling it. */
4857     fex = vim_strsave(curbuf->b_p_fex);
4858     if (fex == NULL)
4859 	return 0;
4860 
4861     /*
4862      * Evaluate the function.
4863      */
4864     if (use_sandbox)
4865 	++sandbox;
4866     r = (int)eval_to_number(fex);
4867     if (use_sandbox)
4868 	--sandbox;
4869 
4870     set_vim_var_string(VV_CHAR, NULL, -1);
4871     vim_free(fex);
4872 
4873     return r;
4874 }
4875 #endif
4876 
4877 /*
4878  * Format "line_count" lines, starting at the cursor position.
4879  * When "line_count" is negative, format until the end of the paragraph.
4880  * Lines after the cursor line are saved for undo, caller must have saved the
4881  * first line.
4882  */
4883     void
4884 format_lines(
4885     linenr_T	line_count,
4886     int		avoid_fex)		/* don't use 'formatexpr' */
4887 {
4888     int		max_len;
4889     int		is_not_par;		/* current line not part of parag. */
4890     int		next_is_not_par;	/* next line not part of paragraph */
4891     int		is_end_par;		/* at end of paragraph */
4892     int		prev_is_end_par = FALSE;/* prev. line not part of parag. */
4893     int		next_is_start_par = FALSE;
4894 #ifdef FEAT_COMMENTS
4895     int		leader_len = 0;		/* leader len of current line */
4896     int		next_leader_len;	/* leader len of next line */
4897     char_u	*leader_flags = NULL;	/* flags for leader of current line */
4898     char_u	*next_leader_flags;	/* flags for leader of next line */
4899     int		do_comments;		/* format comments */
4900     int		do_comments_list = 0;	/* format comments with 'n' or '2' */
4901 #endif
4902     int		advance = TRUE;
4903     int		second_indent = -1;	/* indent for second line (comment
4904 					 * aware) */
4905     int		do_second_indent;
4906     int		do_number_indent;
4907     int		do_trail_white;
4908     int		first_par_line = TRUE;
4909     int		smd_save;
4910     long	count;
4911     int		need_set_indent = TRUE;	/* set indent of next paragraph */
4912     int		force_format = FALSE;
4913     int		old_State = State;
4914 
4915     /* length of a line to force formatting: 3 * 'tw' */
4916     max_len = comp_textwidth(TRUE) * 3;
4917 
4918     /* check for 'q', '2' and '1' in 'formatoptions' */
4919 #ifdef FEAT_COMMENTS
4920     do_comments = has_format_option(FO_Q_COMS);
4921 #endif
4922     do_second_indent = has_format_option(FO_Q_SECOND);
4923     do_number_indent = has_format_option(FO_Q_NUMBER);
4924     do_trail_white = has_format_option(FO_WHITE_PAR);
4925 
4926     /*
4927      * Get info about the previous and current line.
4928      */
4929     if (curwin->w_cursor.lnum > 1)
4930 	is_not_par = fmt_check_par(curwin->w_cursor.lnum - 1
4931 #ifdef FEAT_COMMENTS
4932 				, &leader_len, &leader_flags, do_comments
4933 #endif
4934 				);
4935     else
4936 	is_not_par = TRUE;
4937     next_is_not_par = fmt_check_par(curwin->w_cursor.lnum
4938 #ifdef FEAT_COMMENTS
4939 			   , &next_leader_len, &next_leader_flags, do_comments
4940 #endif
4941 				);
4942     is_end_par = (is_not_par || next_is_not_par);
4943     if (!is_end_par && do_trail_white)
4944 	is_end_par = !ends_in_white(curwin->w_cursor.lnum - 1);
4945 
4946     curwin->w_cursor.lnum--;
4947     for (count = line_count; count != 0 && !got_int; --count)
4948     {
4949 	/*
4950 	 * Advance to next paragraph.
4951 	 */
4952 	if (advance)
4953 	{
4954 	    curwin->w_cursor.lnum++;
4955 	    prev_is_end_par = is_end_par;
4956 	    is_not_par = next_is_not_par;
4957 #ifdef FEAT_COMMENTS
4958 	    leader_len = next_leader_len;
4959 	    leader_flags = next_leader_flags;
4960 #endif
4961 	}
4962 
4963 	/*
4964 	 * The last line to be formatted.
4965 	 */
4966 	if (count == 1 || curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
4967 	{
4968 	    next_is_not_par = TRUE;
4969 #ifdef FEAT_COMMENTS
4970 	    next_leader_len = 0;
4971 	    next_leader_flags = NULL;
4972 #endif
4973 	}
4974 	else
4975 	{
4976 	    next_is_not_par = fmt_check_par(curwin->w_cursor.lnum + 1
4977 #ifdef FEAT_COMMENTS
4978 			   , &next_leader_len, &next_leader_flags, do_comments
4979 #endif
4980 					);
4981 	    if (do_number_indent)
4982 		next_is_start_par =
4983 			   (get_number_indent(curwin->w_cursor.lnum + 1) > 0);
4984 	}
4985 	advance = TRUE;
4986 	is_end_par = (is_not_par || next_is_not_par || next_is_start_par);
4987 	if (!is_end_par && do_trail_white)
4988 	    is_end_par = !ends_in_white(curwin->w_cursor.lnum);
4989 
4990 	/*
4991 	 * Skip lines that are not in a paragraph.
4992 	 */
4993 	if (is_not_par)
4994 	{
4995 	    if (line_count < 0)
4996 		break;
4997 	}
4998 	else
4999 	{
5000 	    /*
5001 	     * For the first line of a paragraph, check indent of second line.
5002 	     * Don't do this for comments and empty lines.
5003 	     */
5004 	    if (first_par_line
5005 		    && (do_second_indent || do_number_indent)
5006 		    && prev_is_end_par
5007 		    && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
5008 	    {
5009 		if (do_second_indent && !LINEEMPTY(curwin->w_cursor.lnum + 1))
5010 		{
5011 #ifdef FEAT_COMMENTS
5012 		    if (leader_len == 0 && next_leader_len == 0)
5013 		    {
5014 			/* no comment found */
5015 #endif
5016 			second_indent =
5017 				   get_indent_lnum(curwin->w_cursor.lnum + 1);
5018 #ifdef FEAT_COMMENTS
5019 		    }
5020 		    else
5021 		    {
5022 			second_indent = next_leader_len;
5023 			do_comments_list = 1;
5024 		    }
5025 #endif
5026 		}
5027 		else if (do_number_indent)
5028 		{
5029 #ifdef FEAT_COMMENTS
5030 		    if (leader_len == 0 && next_leader_len == 0)
5031 		    {
5032 			/* no comment found */
5033 #endif
5034 			second_indent =
5035 				     get_number_indent(curwin->w_cursor.lnum);
5036 #ifdef FEAT_COMMENTS
5037 		    }
5038 		    else
5039 		    {
5040 			/* get_number_indent() is now "comment aware"... */
5041 			second_indent =
5042 				     get_number_indent(curwin->w_cursor.lnum);
5043 			do_comments_list = 1;
5044 		    }
5045 #endif
5046 		}
5047 	    }
5048 
5049 	    /*
5050 	     * When the comment leader changes, it's the end of the paragraph.
5051 	     */
5052 	    if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count
5053 #ifdef FEAT_COMMENTS
5054 		    || !same_leader(curwin->w_cursor.lnum,
5055 					leader_len, leader_flags,
5056 					  next_leader_len, next_leader_flags)
5057 #endif
5058 		    )
5059 		is_end_par = TRUE;
5060 
5061 	    /*
5062 	     * If we have got to the end of a paragraph, or the line is
5063 	     * getting long, format it.
5064 	     */
5065 	    if (is_end_par || force_format)
5066 	    {
5067 		if (need_set_indent)
5068 		    /* replace indent in first line with minimal number of
5069 		     * tabs and spaces, according to current options */
5070 		    (void)set_indent(get_indent(), SIN_CHANGED);
5071 
5072 		/* put cursor on last non-space */
5073 		State = NORMAL;	/* don't go past end-of-line */
5074 		coladvance((colnr_T)MAXCOL);
5075 		while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
5076 		    dec_cursor();
5077 
5078 		/* do the formatting, without 'showmode' */
5079 		State = INSERT;	/* for open_line() */
5080 		smd_save = p_smd;
5081 		p_smd = FALSE;
5082 		insertchar(NUL, INSCHAR_FORMAT
5083 #ifdef FEAT_COMMENTS
5084 			+ (do_comments ? INSCHAR_DO_COM : 0)
5085 			+ (do_comments && do_comments_list
5086 						       ? INSCHAR_COM_LIST : 0)
5087 #endif
5088 			+ (avoid_fex ? INSCHAR_NO_FEX : 0), second_indent);
5089 		State = old_State;
5090 		p_smd = smd_save;
5091 		second_indent = -1;
5092 		/* at end of par.: need to set indent of next par. */
5093 		need_set_indent = is_end_par;
5094 		if (is_end_par)
5095 		{
5096 		    /* When called with a negative line count, break at the
5097 		     * end of the paragraph. */
5098 		    if (line_count < 0)
5099 			break;
5100 		    first_par_line = TRUE;
5101 		}
5102 		force_format = FALSE;
5103 	    }
5104 
5105 	    /*
5106 	     * When still in same paragraph, join the lines together.  But
5107 	     * first delete the leader from the second line.
5108 	     */
5109 	    if (!is_end_par)
5110 	    {
5111 		advance = FALSE;
5112 		curwin->w_cursor.lnum++;
5113 		curwin->w_cursor.col = 0;
5114 		if (line_count < 0 && u_save_cursor() == FAIL)
5115 		    break;
5116 #ifdef FEAT_COMMENTS
5117 		if (next_leader_len > 0)
5118 		{
5119 		    (void)del_bytes((long)next_leader_len, FALSE, FALSE);
5120 		    mark_col_adjust(curwin->w_cursor.lnum, (colnr_T)0, 0L,
5121 						      (long)-next_leader_len, 0);
5122 		} else
5123 #endif
5124 		    if (second_indent > 0)  /* the "leader" for FO_Q_SECOND */
5125 		{
5126 		    int indent = getwhitecols_curline();
5127 
5128 		    if (indent > 0)
5129 		    {
5130 			(void)del_bytes(indent, FALSE, FALSE);
5131 			mark_col_adjust(curwin->w_cursor.lnum,
5132 					       (colnr_T)0, 0L, (long)-indent, 0);
5133 		    }
5134 		}
5135 		curwin->w_cursor.lnum--;
5136 		if (do_join(2, TRUE, FALSE, FALSE, FALSE) == FAIL)
5137 		{
5138 		    beep_flush();
5139 		    break;
5140 		}
5141 		first_par_line = FALSE;
5142 		/* If the line is getting long, format it next time */
5143 		if (STRLEN(ml_get_curline()) > (size_t)max_len)
5144 		    force_format = TRUE;
5145 		else
5146 		    force_format = FALSE;
5147 	    }
5148 	}
5149 	line_breakcheck();
5150     }
5151 }
5152 
5153 /*
5154  * Return TRUE if line "lnum" ends in a white character.
5155  */
5156     static int
5157 ends_in_white(linenr_T lnum)
5158 {
5159     char_u	*s = ml_get(lnum);
5160     size_t	l;
5161 
5162     if (*s == NUL)
5163 	return FALSE;
5164     /* Don't use STRLEN() inside VIM_ISWHITE(), SAS/C complains: "macro
5165      * invocation may call function multiple times". */
5166     l = STRLEN(s) - 1;
5167     return VIM_ISWHITE(s[l]);
5168 }
5169 
5170 /*
5171  * Blank lines, and lines containing only the comment leader, are left
5172  * untouched by the formatting.  The function returns TRUE in this
5173  * case.  It also returns TRUE when a line starts with the end of a comment
5174  * ('e' in comment flags), so that this line is skipped, and not joined to the
5175  * previous line.  A new paragraph starts after a blank line, or when the
5176  * comment leader changes -- webb.
5177  */
5178 #ifdef FEAT_COMMENTS
5179     static int
5180 fmt_check_par(
5181     linenr_T	lnum,
5182     int		*leader_len,
5183     char_u	**leader_flags,
5184     int		do_comments)
5185 {
5186     char_u	*flags = NULL;	    /* init for GCC */
5187     char_u	*ptr;
5188 
5189     ptr = ml_get(lnum);
5190     if (do_comments)
5191 	*leader_len = get_leader_len(ptr, leader_flags, FALSE, TRUE);
5192     else
5193 	*leader_len = 0;
5194 
5195     if (*leader_len > 0)
5196     {
5197 	/*
5198 	 * Search for 'e' flag in comment leader flags.
5199 	 */
5200 	flags = *leader_flags;
5201 	while (*flags && *flags != ':' && *flags != COM_END)
5202 	    ++flags;
5203     }
5204 
5205     return (*skipwhite(ptr + *leader_len) == NUL
5206 	    || (*leader_len > 0 && *flags == COM_END)
5207 	    || startPS(lnum, NUL, FALSE));
5208 }
5209 #else
5210     static int
5211 fmt_check_par(linenr_T lnum)
5212 {
5213     return (*skipwhite(ml_get(lnum)) == NUL || startPS(lnum, NUL, FALSE));
5214 }
5215 #endif
5216 
5217 /*
5218  * Return TRUE when a paragraph starts in line "lnum".  Return FALSE when the
5219  * previous line is in the same paragraph.  Used for auto-formatting.
5220  */
5221     int
5222 paragraph_start(linenr_T lnum)
5223 {
5224     char_u	*p;
5225 #ifdef FEAT_COMMENTS
5226     int		leader_len = 0;		/* leader len of current line */
5227     char_u	*leader_flags = NULL;	/* flags for leader of current line */
5228     int		next_leader_len;	/* leader len of next line */
5229     char_u	*next_leader_flags;	/* flags for leader of next line */
5230     int		do_comments;		/* format comments */
5231 #endif
5232 
5233     if (lnum <= 1)
5234 	return TRUE;		/* start of the file */
5235 
5236     p = ml_get(lnum - 1);
5237     if (*p == NUL)
5238 	return TRUE;		/* after empty line */
5239 
5240 #ifdef FEAT_COMMENTS
5241     do_comments = has_format_option(FO_Q_COMS);
5242 #endif
5243     if (fmt_check_par(lnum - 1
5244 #ifdef FEAT_COMMENTS
5245 				, &leader_len, &leader_flags, do_comments
5246 #endif
5247 		))
5248 	return TRUE;		/* after non-paragraph line */
5249 
5250     if (fmt_check_par(lnum
5251 #ifdef FEAT_COMMENTS
5252 			   , &next_leader_len, &next_leader_flags, do_comments
5253 #endif
5254 		))
5255 	return TRUE;		/* "lnum" is not a paragraph line */
5256 
5257     if (has_format_option(FO_WHITE_PAR) && !ends_in_white(lnum - 1))
5258 	return TRUE;		/* missing trailing space in previous line. */
5259 
5260     if (has_format_option(FO_Q_NUMBER) && (get_number_indent(lnum) > 0))
5261 	return TRUE;		/* numbered item starts in "lnum". */
5262 
5263 #ifdef FEAT_COMMENTS
5264     if (!same_leader(lnum - 1, leader_len, leader_flags,
5265 					  next_leader_len, next_leader_flags))
5266 	return TRUE;		/* change of comment leader. */
5267 #endif
5268 
5269     return FALSE;
5270 }
5271 
5272 /*
5273  * prepare a few things for block mode yank/delete/tilde
5274  *
5275  * for delete:
5276  * - textlen includes the first/last char to be (partly) deleted
5277  * - start/endspaces is the number of columns that are taken by the
5278  *   first/last deleted char minus the number of columns that have to be
5279  *   deleted.
5280  * for yank and tilde:
5281  * - textlen includes the first/last char to be wholly yanked
5282  * - start/endspaces is the number of columns of the first/last yanked char
5283  *   that are to be yanked.
5284  */
5285     static void
5286 block_prep(
5287     oparg_T		*oap,
5288     struct block_def	*bdp,
5289     linenr_T		lnum,
5290     int			is_del)
5291 {
5292     int		incr = 0;
5293     char_u	*pend;
5294     char_u	*pstart;
5295     char_u	*line;
5296     char_u	*prev_pstart;
5297     char_u	*prev_pend;
5298 
5299     bdp->startspaces = 0;
5300     bdp->endspaces = 0;
5301     bdp->textlen = 0;
5302     bdp->start_vcol = 0;
5303     bdp->end_vcol = 0;
5304     bdp->is_short = FALSE;
5305     bdp->is_oneChar = FALSE;
5306     bdp->pre_whitesp = 0;
5307     bdp->pre_whitesp_c = 0;
5308     bdp->end_char_vcols = 0;
5309     bdp->start_char_vcols = 0;
5310 
5311     line = ml_get(lnum);
5312     pstart = line;
5313     prev_pstart = line;
5314     while (bdp->start_vcol < oap->start_vcol && *pstart)
5315     {
5316 	/* Count a tab for what it's worth (if list mode not on) */
5317 	incr = lbr_chartabsize(line, pstart, (colnr_T)bdp->start_vcol);
5318 	bdp->start_vcol += incr;
5319 	if (VIM_ISWHITE(*pstart))
5320 	{
5321 	    bdp->pre_whitesp += incr;
5322 	    bdp->pre_whitesp_c++;
5323 	}
5324 	else
5325 	{
5326 	    bdp->pre_whitesp = 0;
5327 	    bdp->pre_whitesp_c = 0;
5328 	}
5329 	prev_pstart = pstart;
5330 	MB_PTR_ADV(pstart);
5331     }
5332     bdp->start_char_vcols = incr;
5333     if (bdp->start_vcol < oap->start_vcol)	/* line too short */
5334     {
5335 	bdp->end_vcol = bdp->start_vcol;
5336 	bdp->is_short = TRUE;
5337 	if (!is_del || oap->op_type == OP_APPEND)
5338 	    bdp->endspaces = oap->end_vcol - oap->start_vcol + 1;
5339     }
5340     else
5341     {
5342 	/* notice: this converts partly selected Multibyte characters to
5343 	 * spaces, too. */
5344 	bdp->startspaces = bdp->start_vcol - oap->start_vcol;
5345 	if (is_del && bdp->startspaces)
5346 	    bdp->startspaces = bdp->start_char_vcols - bdp->startspaces;
5347 	pend = pstart;
5348 	bdp->end_vcol = bdp->start_vcol;
5349 	if (bdp->end_vcol > oap->end_vcol)	/* it's all in one character */
5350 	{
5351 	    bdp->is_oneChar = TRUE;
5352 	    if (oap->op_type == OP_INSERT)
5353 		bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
5354 	    else if (oap->op_type == OP_APPEND)
5355 	    {
5356 		bdp->startspaces += oap->end_vcol - oap->start_vcol + 1;
5357 		bdp->endspaces = bdp->start_char_vcols - bdp->startspaces;
5358 	    }
5359 	    else
5360 	    {
5361 		bdp->startspaces = oap->end_vcol - oap->start_vcol + 1;
5362 		if (is_del && oap->op_type != OP_LSHIFT)
5363 		{
5364 		    /* just putting the sum of those two into
5365 		     * bdp->startspaces doesn't work for Visual replace,
5366 		     * so we have to split the tab in two */
5367 		    bdp->startspaces = bdp->start_char_vcols
5368 					- (bdp->start_vcol - oap->start_vcol);
5369 		    bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
5370 		}
5371 	    }
5372 	}
5373 	else
5374 	{
5375 	    prev_pend = pend;
5376 	    while (bdp->end_vcol <= oap->end_vcol && *pend != NUL)
5377 	    {
5378 		/* Count a tab for what it's worth (if list mode not on) */
5379 		prev_pend = pend;
5380 		incr = lbr_chartabsize_adv(line, &pend, (colnr_T)bdp->end_vcol);
5381 		bdp->end_vcol += incr;
5382 	    }
5383 	    if (bdp->end_vcol <= oap->end_vcol
5384 		    && (!is_del
5385 			|| oap->op_type == OP_APPEND
5386 			|| oap->op_type == OP_REPLACE)) /* line too short */
5387 	    {
5388 		bdp->is_short = TRUE;
5389 		/* Alternative: include spaces to fill up the block.
5390 		 * Disadvantage: can lead to trailing spaces when the line is
5391 		 * short where the text is put */
5392 		/* if (!is_del || oap->op_type == OP_APPEND) */
5393 		if (oap->op_type == OP_APPEND || virtual_op)
5394 		    bdp->endspaces = oap->end_vcol - bdp->end_vcol
5395 							     + oap->inclusive;
5396 		else
5397 		    bdp->endspaces = 0; /* replace doesn't add characters */
5398 	    }
5399 	    else if (bdp->end_vcol > oap->end_vcol)
5400 	    {
5401 		bdp->endspaces = bdp->end_vcol - oap->end_vcol - 1;
5402 		if (!is_del && bdp->endspaces)
5403 		{
5404 		    bdp->endspaces = incr - bdp->endspaces;
5405 		    if (pend != pstart)
5406 			pend = prev_pend;
5407 		}
5408 	    }
5409 	}
5410 	bdp->end_char_vcols = incr;
5411 	if (is_del && bdp->startspaces)
5412 	    pstart = prev_pstart;
5413 	bdp->textlen = (int)(pend - pstart);
5414     }
5415     bdp->textcol = (colnr_T) (pstart - line);
5416     bdp->textstart = pstart;
5417 }
5418 
5419 /*
5420  * Handle the add/subtract operator.
5421  */
5422     void
5423 op_addsub(
5424     oparg_T	*oap,
5425     linenr_T	Prenum1,	    /* Amount of add/subtract */
5426     int		g_cmd)		    /* was g<c-a>/g<c-x> */
5427 {
5428     pos_T		pos;
5429     struct block_def	bd;
5430     int			change_cnt = 0;
5431     linenr_T		amount = Prenum1;
5432 
5433    // do_addsub() might trigger re-evaluation of 'foldexpr' halfway, when the
5434    // buffer is not completely updated yet. Postpone updating folds until before
5435    // the call to changed_lines().
5436 #ifdef FEAT_FOLDING
5437    disable_fold_update++;
5438 #endif
5439 
5440     if (!VIsual_active)
5441     {
5442 	pos = curwin->w_cursor;
5443 	if (u_save_cursor() == FAIL)
5444 	{
5445 #ifdef FEAT_FOLDING
5446 	    disable_fold_update--;
5447 #endif
5448 	    return;
5449 	}
5450 	change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
5451 #ifdef FEAT_FOLDING
5452 	disable_fold_update--;
5453 #endif
5454 	if (change_cnt)
5455 	    changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
5456     }
5457     else
5458     {
5459 	int	one_change;
5460 	int	length;
5461 	pos_T	startpos;
5462 
5463 	if (u_save((linenr_T)(oap->start.lnum - 1),
5464 					(linenr_T)(oap->end.lnum + 1)) == FAIL)
5465 	{
5466 #ifdef FEAT_FOLDING
5467 	    disable_fold_update--;
5468 #endif
5469 	    return;
5470 	}
5471 
5472 	pos = oap->start;
5473 	for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
5474 	{
5475 	    if (oap->block_mode)		    /* Visual block mode */
5476 	    {
5477 		block_prep(oap, &bd, pos.lnum, FALSE);
5478 		pos.col = bd.textcol;
5479 		length = bd.textlen;
5480 	    }
5481 	    else if (oap->motion_type == MLINE)
5482 	    {
5483 		curwin->w_cursor.col = 0;
5484 		pos.col = 0;
5485 		length = (colnr_T)STRLEN(ml_get(pos.lnum));
5486 	    }
5487 	    else /* oap->motion_type == MCHAR */
5488 	    {
5489 		if (pos.lnum == oap->start.lnum && !oap->inclusive)
5490 		    dec(&(oap->end));
5491 		length = (colnr_T)STRLEN(ml_get(pos.lnum));
5492 		pos.col = 0;
5493 		if (pos.lnum == oap->start.lnum)
5494 		{
5495 		    pos.col += oap->start.col;
5496 		    length -= oap->start.col;
5497 		}
5498 		if (pos.lnum == oap->end.lnum)
5499 		{
5500 		    length = (int)STRLEN(ml_get(oap->end.lnum));
5501 		    if (oap->end.col >= length)
5502 			oap->end.col = length - 1;
5503 		    length = oap->end.col - pos.col + 1;
5504 		}
5505 	    }
5506 	    one_change = do_addsub(oap->op_type, &pos, length, amount);
5507 	    if (one_change)
5508 	    {
5509 		/* Remember the start position of the first change. */
5510 		if (change_cnt == 0)
5511 		    startpos = curbuf->b_op_start;
5512 		++change_cnt;
5513 	    }
5514 
5515 #ifdef FEAT_NETBEANS_INTG
5516 	    if (netbeans_active() && one_change)
5517 	    {
5518 		char_u *ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
5519 
5520 		netbeans_removed(curbuf, pos.lnum, pos.col, (long)length);
5521 		netbeans_inserted(curbuf, pos.lnum, pos.col,
5522 						&ptr[pos.col], length);
5523 	    }
5524 #endif
5525 	    if (g_cmd && one_change)
5526 		amount += Prenum1;
5527 	}
5528 
5529 #ifdef FEAT_FOLDING
5530 	disable_fold_update--;
5531 #endif
5532 	if (change_cnt)
5533 	    changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
5534 
5535 	if (!change_cnt && oap->is_VIsual)
5536 	    /* No change: need to remove the Visual selection */
5537 	    redraw_curbuf_later(INVERTED);
5538 
5539 	/* Set '[ mark if something changed. Keep the last end
5540 	 * position from do_addsub(). */
5541 	if (change_cnt > 0)
5542 	    curbuf->b_op_start = startpos;
5543 
5544 	if (change_cnt > p_report)
5545 	    smsg(NGETTEXT("%ld line changed", "%ld lines changed",
5546 						      change_cnt), change_cnt);
5547     }
5548 }
5549 
5550 /*
5551  * Add or subtract 'Prenum1' from a number in a line
5552  * op_type is OP_NR_ADD or OP_NR_SUB
5553  *
5554  * Returns TRUE if some character was changed.
5555  */
5556     static int
5557 do_addsub(
5558     int		op_type,
5559     pos_T	*pos,
5560     int		length,
5561     linenr_T	Prenum1)
5562 {
5563     int		col;
5564     char_u	*buf1;
5565     char_u	buf2[NUMBUFLEN];
5566     int		pre;		/* 'X'/'x': hex; '0': octal; 'B'/'b': bin */
5567     static int	hexupper = FALSE;	/* 0xABC */
5568     uvarnumber_T	n;
5569     uvarnumber_T	oldn;
5570     char_u	*ptr;
5571     int		c;
5572     int		todel;
5573     int		dohex;
5574     int		dooct;
5575     int		dobin;
5576     int		doalp;
5577     int		firstdigit;
5578     int		subtract;
5579     int		negative = FALSE;
5580     int		was_positive = TRUE;
5581     int		visual = VIsual_active;
5582     int		did_change = FALSE;
5583     pos_T	save_cursor = curwin->w_cursor;
5584     int		maxlen = 0;
5585     pos_T	startpos;
5586     pos_T	endpos;
5587 
5588     dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL);	/* "heX" */
5589     dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL);	/* "Octal" */
5590     dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL);	/* "Bin" */
5591     doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL);	/* "alPha" */
5592 
5593     curwin->w_cursor = *pos;
5594     ptr = ml_get(pos->lnum);
5595     col = pos->col;
5596 
5597     if (*ptr == NUL)
5598 	goto theend;
5599 
5600     /*
5601      * First check if we are on a hexadecimal number, after the "0x".
5602      */
5603     if (!VIsual_active)
5604     {
5605 	if (dobin)
5606 	    while (col > 0 && vim_isbdigit(ptr[col]))
5607 	    {
5608 		--col;
5609 		if (has_mbyte)
5610 		    col -= (*mb_head_off)(ptr, ptr + col);
5611 	    }
5612 
5613 	if (dohex)
5614 	    while (col > 0 && vim_isxdigit(ptr[col]))
5615 	    {
5616 		--col;
5617 		if (has_mbyte)
5618 		    col -= (*mb_head_off)(ptr, ptr + col);
5619 	    }
5620 
5621 	if (       dobin
5622 		&& dohex
5623 		&& ! ((col > 0
5624 		    && (ptr[col] == 'X'
5625 			|| ptr[col] == 'x')
5626 		    && ptr[col - 1] == '0'
5627 		    && (!has_mbyte ||
5628 			!(*mb_head_off)(ptr, ptr + col - 1))
5629 		    && vim_isxdigit(ptr[col + 1]))))
5630 	{
5631 
5632 	    /* In case of binary/hexadecimal pattern overlap match, rescan */
5633 
5634 	    col = pos->col;
5635 
5636 	    while (col > 0 && vim_isdigit(ptr[col]))
5637 	    {
5638 		col--;
5639 		if (has_mbyte)
5640 		    col -= (*mb_head_off)(ptr, ptr + col);
5641 	    }
5642 	}
5643 
5644 	if ((       dohex
5645 		&& col > 0
5646 		&& (ptr[col] == 'X'
5647 		    || ptr[col] == 'x')
5648 		&& ptr[col - 1] == '0'
5649 		&& (!has_mbyte ||
5650 		    !(*mb_head_off)(ptr, ptr + col - 1))
5651 		&& vim_isxdigit(ptr[col + 1])) ||
5652 	    (       dobin
5653 		&& col > 0
5654 		&& (ptr[col] == 'B'
5655 		    || ptr[col] == 'b')
5656 		&& ptr[col - 1] == '0'
5657 		&& (!has_mbyte ||
5658 		    !(*mb_head_off)(ptr, ptr + col - 1))
5659 		&& vim_isbdigit(ptr[col + 1])))
5660 	{
5661 	    /* Found hexadecimal or binary number, move to its start. */
5662 	    --col;
5663 	    if (has_mbyte)
5664 		col -= (*mb_head_off)(ptr, ptr + col);
5665 	}
5666 	else
5667 	{
5668 	    /*
5669 	     * Search forward and then backward to find the start of number.
5670 	     */
5671 	    col = pos->col;
5672 
5673 	    while (ptr[col] != NUL
5674 		    && !vim_isdigit(ptr[col])
5675 		    && !(doalp && ASCII_ISALPHA(ptr[col])))
5676 		col += MB_PTR2LEN(ptr + col);
5677 
5678 	    while (col > 0
5679 		    && vim_isdigit(ptr[col - 1])
5680 		    && !(doalp && ASCII_ISALPHA(ptr[col])))
5681 	    {
5682 		--col;
5683 		if (has_mbyte)
5684 		    col -= (*mb_head_off)(ptr, ptr + col);
5685 	    }
5686 	}
5687     }
5688 
5689     if (visual)
5690     {
5691 	while (ptr[col] != NUL && length > 0
5692 		&& !vim_isdigit(ptr[col])
5693 		&& !(doalp && ASCII_ISALPHA(ptr[col])))
5694 	{
5695 	    int mb_len = MB_PTR2LEN(ptr + col);
5696 
5697 	    col += mb_len;
5698 	    length -= mb_len;
5699 	}
5700 
5701 	if (length == 0)
5702 	    goto theend;
5703 
5704 	if (col > pos->col && ptr[col - 1] == '-'
5705 		&& (!has_mbyte || !(*mb_head_off)(ptr, ptr + col - 1)))
5706 	{
5707 	    negative = TRUE;
5708 	    was_positive = FALSE;
5709 	}
5710     }
5711 
5712     /*
5713      * If a number was found, and saving for undo works, replace the number.
5714      */
5715     firstdigit = ptr[col];
5716     if (!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
5717     {
5718 	beep_flush();
5719 	goto theend;
5720     }
5721 
5722     if (doalp && ASCII_ISALPHA(firstdigit))
5723     {
5724 	/* decrement or increment alphabetic character */
5725 	if (op_type == OP_NR_SUB)
5726 	{
5727 	    if (CharOrd(firstdigit) < Prenum1)
5728 	    {
5729 		if (isupper(firstdigit))
5730 		    firstdigit = 'A';
5731 		else
5732 		    firstdigit = 'a';
5733 	    }
5734 	    else
5735 #ifdef EBCDIC
5736 		firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
5737 #else
5738 		firstdigit -= Prenum1;
5739 #endif
5740 	}
5741 	else
5742 	{
5743 	    if (26 - CharOrd(firstdigit) - 1 < Prenum1)
5744 	    {
5745 		if (isupper(firstdigit))
5746 		    firstdigit = 'Z';
5747 		else
5748 		    firstdigit = 'z';
5749 	    }
5750 	    else
5751 #ifdef EBCDIC
5752 		firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
5753 #else
5754 		firstdigit += Prenum1;
5755 #endif
5756 	}
5757 	curwin->w_cursor.col = col;
5758 	if (!did_change)
5759 	    startpos = curwin->w_cursor;
5760 	did_change = TRUE;
5761 	(void)del_char(FALSE);
5762 	ins_char(firstdigit);
5763 	endpos = curwin->w_cursor;
5764 	curwin->w_cursor.col = col;
5765     }
5766     else
5767     {
5768 	if (col > 0 && ptr[col - 1] == '-'
5769 		&& (!has_mbyte ||
5770 		    !(*mb_head_off)(ptr, ptr + col - 1))
5771 		&& !visual)
5772 	{
5773 	    /* negative number */
5774 	    --col;
5775 	    negative = TRUE;
5776 	}
5777 	/* get the number value (unsigned) */
5778 	if (visual && VIsual_mode != 'V')
5779 	    maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
5780 		    ? (int)STRLEN(ptr) - col
5781 		    : length);
5782 
5783 	vim_str2nr(ptr + col, &pre, &length,
5784 		0 + (dobin ? STR2NR_BIN : 0)
5785 		    + (dooct ? STR2NR_OCT : 0)
5786 		    + (dohex ? STR2NR_HEX : 0),
5787 		NULL, &n, maxlen, FALSE);
5788 
5789 	/* ignore leading '-' for hex and octal and bin numbers */
5790 	if (pre && negative)
5791 	{
5792 	    ++col;
5793 	    --length;
5794 	    negative = FALSE;
5795 	}
5796 	/* add or subtract */
5797 	subtract = FALSE;
5798 	if (op_type == OP_NR_SUB)
5799 	    subtract ^= TRUE;
5800 	if (negative)
5801 	    subtract ^= TRUE;
5802 
5803 	oldn = n;
5804 	if (subtract)
5805 	    n -= (uvarnumber_T)Prenum1;
5806 	else
5807 	    n += (uvarnumber_T)Prenum1;
5808 	/* handle wraparound for decimal numbers */
5809 	if (!pre)
5810 	{
5811 	    if (subtract)
5812 	    {
5813 		if (n > oldn)
5814 		{
5815 		    n = 1 + (n ^ (uvarnumber_T)-1);
5816 		    negative ^= TRUE;
5817 		}
5818 	    }
5819 	    else
5820 	    {
5821 		/* add */
5822 		if (n < oldn)
5823 		{
5824 		    n = (n ^ (uvarnumber_T)-1);
5825 		    negative ^= TRUE;
5826 		}
5827 	    }
5828 	    if (n == 0)
5829 		negative = FALSE;
5830 	}
5831 
5832 	if (visual && !was_positive && !negative && col > 0)
5833 	{
5834 	    /* need to remove the '-' */
5835 	    col--;
5836 	    length++;
5837 	}
5838 
5839 	/*
5840 	 * Delete the old number.
5841 	 */
5842 	curwin->w_cursor.col = col;
5843 	if (!did_change)
5844 	    startpos = curwin->w_cursor;
5845 	did_change = TRUE;
5846 	todel = length;
5847 	c = gchar_cursor();
5848 	/*
5849 	 * Don't include the '-' in the length, only the length of the
5850 	 * part after it is kept the same.
5851 	 */
5852 	if (c == '-')
5853 	    --length;
5854 	while (todel-- > 0)
5855 	{
5856 	    if (c < 0x100 && isalpha(c))
5857 	    {
5858 		if (isupper(c))
5859 		    hexupper = TRUE;
5860 		else
5861 		    hexupper = FALSE;
5862 	    }
5863 	    /* del_char() will mark line needing displaying */
5864 	    (void)del_char(FALSE);
5865 	    c = gchar_cursor();
5866 	}
5867 
5868 	/*
5869 	 * Prepare the leading characters in buf1[].
5870 	 * When there are many leading zeros it could be very long.
5871 	 * Allocate a bit too much.
5872 	 */
5873 	buf1 = alloc(length + NUMBUFLEN);
5874 	if (buf1 == NULL)
5875 	    goto theend;
5876 	ptr = buf1;
5877 	if (negative && (!visual || was_positive))
5878 	    *ptr++ = '-';
5879 	if (pre)
5880 	{
5881 	    *ptr++ = '0';
5882 	    --length;
5883 	}
5884 	if (pre == 'b' || pre == 'B' ||
5885 	    pre == 'x' || pre == 'X')
5886 	{
5887 	    *ptr++ = pre;
5888 	    --length;
5889 	}
5890 
5891 	/*
5892 	 * Put the number characters in buf2[].
5893 	 */
5894 	if (pre == 'b' || pre == 'B')
5895 	{
5896 	    int i;
5897 	    int bit = 0;
5898 	    int bits = sizeof(uvarnumber_T) * 8;
5899 
5900 	    /* leading zeros */
5901 	    for (bit = bits; bit > 0; bit--)
5902 		if ((n >> (bit - 1)) & 0x1) break;
5903 
5904 	    for (i = 0; bit > 0; bit--)
5905 		buf2[i++] = ((n >> (bit - 1)) & 0x1) ? '1' : '0';
5906 
5907 	    buf2[i] = '\0';
5908 	}
5909 	else if (pre == 0)
5910 	    vim_snprintf((char *)buf2, NUMBUFLEN, "%llu",
5911 							(long_long_u_T)n);
5912 	else if (pre == '0')
5913 	    vim_snprintf((char *)buf2, NUMBUFLEN, "%llo",
5914 							(long_long_u_T)n);
5915 	else if (pre && hexupper)
5916 	    vim_snprintf((char *)buf2, NUMBUFLEN, "%llX",
5917 							(long_long_u_T)n);
5918 	else
5919 	    vim_snprintf((char *)buf2, NUMBUFLEN, "%llx",
5920 							(long_long_u_T)n);
5921 	length -= (int)STRLEN(buf2);
5922 
5923 	/*
5924 	 * Adjust number of zeros to the new number of digits, so the
5925 	 * total length of the number remains the same.
5926 	 * Don't do this when
5927 	 * the result may look like an octal number.
5928 	 */
5929 	if (firstdigit == '0' && !(dooct && pre == 0))
5930 	    while (length-- > 0)
5931 		*ptr++ = '0';
5932 	*ptr = NUL;
5933 	STRCAT(buf1, buf2);
5934 	ins_str(buf1);		/* insert the new number */
5935 	vim_free(buf1);
5936 	endpos = curwin->w_cursor;
5937 	if (did_change && curwin->w_cursor.col)
5938 	    --curwin->w_cursor.col;
5939     }
5940 
5941     if (did_change)
5942     {
5943 	/* set the '[ and '] marks */
5944 	curbuf->b_op_start = startpos;
5945 	curbuf->b_op_end = endpos;
5946 	if (curbuf->b_op_end.col > 0)
5947 	    --curbuf->b_op_end.col;
5948     }
5949 
5950 theend:
5951     if (visual)
5952 	curwin->w_cursor = save_cursor;
5953     else if (did_change)
5954 	curwin->w_set_curswant = TRUE;
5955 
5956     return did_change;
5957 }
5958 
5959 #if defined(FEAT_CLIPBOARD) || defined(PROTO)
5960 /*
5961  * SELECTION / PRIMARY ('*')
5962  *
5963  * Text selection stuff that uses the GUI selection register '*'.  When using a
5964  * GUI this may be text from another window, otherwise it is the last text we
5965  * had highlighted with VIsual mode.  With mouse support, clicking the middle
5966  * button performs the paste, otherwise you will need to do <"*p>. "
5967  * If not under X, it is synonymous with the clipboard register '+'.
5968  *
5969  * X CLIPBOARD ('+')
5970  *
5971  * Text selection stuff that uses the GUI clipboard register '+'.
5972  * Under X, this matches the standard cut/paste buffer CLIPBOARD selection.
5973  * It will be used for unnamed cut/pasting is 'clipboard' contains "unnamed",
5974  * otherwise you will need to do <"+p>. "
5975  * If not under X, it is synonymous with the selection register '*'.
5976  */
5977 
5978 /*
5979  * Routine to export any final X selection we had to the environment
5980  * so that the text is still available after Vim has exited. X selections
5981  * only exist while the owning application exists, so we write to the
5982  * permanent (while X runs) store CUT_BUFFER0.
5983  * Dump the CLIPBOARD selection if we own it (it's logically the more
5984  * 'permanent' of the two), otherwise the PRIMARY one.
5985  * For now, use a hard-coded sanity limit of 1Mb of data.
5986  */
5987 #if (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
5988     void
5989 x11_export_final_selection(void)
5990 {
5991     Display	*dpy;
5992     char_u	*str = NULL;
5993     long_u	len = 0;
5994     int		motion_type = -1;
5995 
5996 # ifdef FEAT_GUI
5997     if (gui.in_use)
5998 	dpy = X_DISPLAY;
5999     else
6000 # endif
6001 # ifdef FEAT_XCLIPBOARD
6002 	dpy = xterm_dpy;
6003 # else
6004 	return;
6005 # endif
6006 
6007     /* Get selection to export */
6008     if (clip_plus.owned)
6009 	motion_type = clip_convert_selection(&str, &len, &clip_plus);
6010     else if (clip_star.owned)
6011 	motion_type = clip_convert_selection(&str, &len, &clip_star);
6012 
6013     /* Check it's OK */
6014     if (dpy != NULL && str != NULL && motion_type >= 0
6015 					       && len < 1024*1024 && len > 0)
6016     {
6017 	int ok = TRUE;
6018 
6019 	/* The CUT_BUFFER0 is supposed to always contain latin1.  Convert from
6020 	 * 'enc' when it is a multi-byte encoding.  When 'enc' is an 8-bit
6021 	 * encoding conversion usually doesn't work, so keep the text as-is.
6022 	 */
6023 	if (has_mbyte)
6024 	{
6025 	    vimconv_T	vc;
6026 
6027 	    vc.vc_type = CONV_NONE;
6028 	    if (convert_setup(&vc, p_enc, (char_u *)"latin1") == OK)
6029 	    {
6030 		int	intlen = len;
6031 		char_u	*conv_str;
6032 
6033 		vc.vc_fail = TRUE;
6034 		conv_str = string_convert(&vc, str, &intlen);
6035 		len = intlen;
6036 		if (conv_str != NULL)
6037 		{
6038 		    vim_free(str);
6039 		    str = conv_str;
6040 		}
6041 		else
6042 		{
6043 		    ok = FALSE;
6044 		}
6045 		convert_setup(&vc, NULL, NULL);
6046 	    }
6047 	    else
6048 	    {
6049 		ok = FALSE;
6050 	    }
6051 	}
6052 
6053 	/* Do not store the string if conversion failed.  Better to use any
6054 	 * other selection than garbled text. */
6055 	if (ok)
6056 	{
6057 	    XStoreBuffer(dpy, (char *)str, (int)len, 0);
6058 	    XFlush(dpy);
6059 	}
6060     }
6061 
6062     vim_free(str);
6063 }
6064 #endif
6065 
6066     void
6067 clip_free_selection(Clipboard_T *cbd)
6068 {
6069     yankreg_T *y_ptr = y_current;
6070 
6071     if (cbd == &clip_plus)
6072 	y_current = &y_regs[PLUS_REGISTER];
6073     else
6074 	y_current = &y_regs[STAR_REGISTER];
6075     free_yank_all();
6076     y_current->y_size = 0;
6077     y_current = y_ptr;
6078 }
6079 
6080 /*
6081  * Get the selected text and put it in register '*' or '+'.
6082  */
6083     void
6084 clip_get_selection(Clipboard_T *cbd)
6085 {
6086     yankreg_T	*old_y_previous, *old_y_current;
6087     pos_T	old_cursor;
6088     pos_T	old_visual;
6089     int		old_visual_mode;
6090     colnr_T	old_curswant;
6091     int		old_set_curswant;
6092     pos_T	old_op_start, old_op_end;
6093     oparg_T	oa;
6094     cmdarg_T	ca;
6095 
6096     if (cbd->owned)
6097     {
6098 	if ((cbd == &clip_plus && y_regs[PLUS_REGISTER].y_array != NULL)
6099 		|| (cbd == &clip_star && y_regs[STAR_REGISTER].y_array != NULL))
6100 	    return;
6101 
6102 	/* Get the text between clip_star.start & clip_star.end */
6103 	old_y_previous = y_previous;
6104 	old_y_current = y_current;
6105 	old_cursor = curwin->w_cursor;
6106 	old_curswant = curwin->w_curswant;
6107 	old_set_curswant = curwin->w_set_curswant;
6108 	old_op_start = curbuf->b_op_start;
6109 	old_op_end = curbuf->b_op_end;
6110 	old_visual = VIsual;
6111 	old_visual_mode = VIsual_mode;
6112 	clear_oparg(&oa);
6113 	oa.regname = (cbd == &clip_plus ? '+' : '*');
6114 	oa.op_type = OP_YANK;
6115 	vim_memset(&ca, 0, sizeof(ca));
6116 	ca.oap = &oa;
6117 	ca.cmdchar = 'y';
6118 	ca.count1 = 1;
6119 	ca.retval = CA_NO_ADJ_OP_END;
6120 	do_pending_operator(&ca, 0, TRUE);
6121 	y_previous = old_y_previous;
6122 	y_current = old_y_current;
6123 	curwin->w_cursor = old_cursor;
6124 	changed_cline_bef_curs();   /* need to update w_virtcol et al */
6125 	curwin->w_curswant = old_curswant;
6126 	curwin->w_set_curswant = old_set_curswant;
6127 	curbuf->b_op_start = old_op_start;
6128 	curbuf->b_op_end = old_op_end;
6129 	VIsual = old_visual;
6130 	VIsual_mode = old_visual_mode;
6131     }
6132     else if (!is_clipboard_needs_update())
6133     {
6134 	clip_free_selection(cbd);
6135 
6136 	/* Try to get selected text from another window */
6137 	clip_gen_request_selection(cbd);
6138     }
6139 }
6140 
6141 /*
6142  * Convert from the GUI selection string into the '*'/'+' register.
6143  */
6144     void
6145 clip_yank_selection(
6146     int		type,
6147     char_u	*str,
6148     long	len,
6149     Clipboard_T *cbd)
6150 {
6151     yankreg_T *y_ptr;
6152 
6153     if (cbd == &clip_plus)
6154 	y_ptr = &y_regs[PLUS_REGISTER];
6155     else
6156 	y_ptr = &y_regs[STAR_REGISTER];
6157 
6158     clip_free_selection(cbd);
6159 
6160     str_to_reg(y_ptr, type, str, len, 0L, FALSE);
6161 }
6162 
6163 /*
6164  * Convert the '*'/'+' register into a GUI selection string returned in *str
6165  * with length *len.
6166  * Returns the motion type, or -1 for failure.
6167  */
6168     int
6169 clip_convert_selection(char_u **str, long_u *len, Clipboard_T *cbd)
6170 {
6171     char_u	*p;
6172     int		lnum;
6173     int		i, j;
6174     int_u	eolsize;
6175     yankreg_T	*y_ptr;
6176 
6177     if (cbd == &clip_plus)
6178 	y_ptr = &y_regs[PLUS_REGISTER];
6179     else
6180 	y_ptr = &y_regs[STAR_REGISTER];
6181 
6182 #ifdef USE_CRNL
6183     eolsize = 2;
6184 #else
6185     eolsize = 1;
6186 #endif
6187 
6188     *str = NULL;
6189     *len = 0;
6190     if (y_ptr->y_array == NULL)
6191 	return -1;
6192 
6193     for (i = 0; i < y_ptr->y_size; i++)
6194 	*len += (long_u)STRLEN(y_ptr->y_array[i]) + eolsize;
6195 
6196     /*
6197      * Don't want newline character at end of last line if we're in MCHAR mode.
6198      */
6199     if (y_ptr->y_type == MCHAR && *len >= eolsize)
6200 	*len -= eolsize;
6201 
6202     p = *str = alloc(*len + 1);	// add one to avoid zero
6203     if (p == NULL)
6204 	return -1;
6205     lnum = 0;
6206     for (i = 0, j = 0; i < (int)*len; i++, j++)
6207     {
6208 	if (y_ptr->y_array[lnum][j] == '\n')
6209 	    p[i] = NUL;
6210 	else if (y_ptr->y_array[lnum][j] == NUL)
6211 	{
6212 #ifdef USE_CRNL
6213 	    p[i++] = '\r';
6214 #endif
6215 	    p[i] = '\n';
6216 	    lnum++;
6217 	    j = -1;
6218 	}
6219 	else
6220 	    p[i] = y_ptr->y_array[lnum][j];
6221     }
6222     return y_ptr->y_type;
6223 }
6224 
6225 
6226 /*
6227  * If we have written to a clipboard register, send the text to the clipboard.
6228  */
6229     static void
6230 may_set_selection(void)
6231 {
6232     if (y_current == &(y_regs[STAR_REGISTER]) && clip_star.available)
6233     {
6234 	clip_own_selection(&clip_star);
6235 	clip_gen_set_selection(&clip_star);
6236     }
6237     else if (y_current == &(y_regs[PLUS_REGISTER]) && clip_plus.available)
6238     {
6239 	clip_own_selection(&clip_plus);
6240 	clip_gen_set_selection(&clip_plus);
6241     }
6242 }
6243 
6244 #endif /* FEAT_CLIPBOARD || PROTO */
6245 
6246 
6247 #if defined(FEAT_DND) || defined(PROTO)
6248 /*
6249  * Replace the contents of the '~' register with str.
6250  */
6251     void
6252 dnd_yank_drag_data(char_u *str, long len)
6253 {
6254     yankreg_T *curr;
6255 
6256     curr = y_current;
6257     y_current = &y_regs[TILDE_REGISTER];
6258     free_yank_all();
6259     str_to_reg(y_current, MCHAR, str, len, 0L, FALSE);
6260     y_current = curr;
6261 }
6262 #endif
6263 
6264 
6265 #if defined(FEAT_EVAL) || defined(PROTO)
6266 /*
6267  * Return the type of a register.
6268  * Used for getregtype()
6269  * Returns MAUTO for error.
6270  */
6271     char_u
6272 get_reg_type(int regname, long *reglen)
6273 {
6274     switch (regname)
6275     {
6276 	case '%':		/* file name */
6277 	case '#':		/* alternate file name */
6278 	case '=':		/* expression */
6279 	case ':':		/* last command line */
6280 	case '/':		/* last search-pattern */
6281 	case '.':		/* last inserted text */
6282 #ifdef FEAT_SEARCHPATH
6283 	case Ctrl_F:		/* Filename under cursor */
6284 	case Ctrl_P:		/* Path under cursor, expand via "path" */
6285 #endif
6286 	case Ctrl_W:		/* word under cursor */
6287 	case Ctrl_A:		/* WORD (mnemonic All) under cursor */
6288 	case '_':		/* black hole: always empty */
6289 	    return MCHAR;
6290     }
6291 
6292 #ifdef FEAT_CLIPBOARD
6293     regname = may_get_selection(regname);
6294 #endif
6295 
6296     if (regname != NUL && !valid_yank_reg(regname, FALSE))
6297 	return MAUTO;
6298 
6299     get_yank_register(regname, FALSE);
6300 
6301     if (y_current->y_array != NULL)
6302     {
6303 	if (reglen != NULL && y_current->y_type == MBLOCK)
6304 	    *reglen = y_current->y_width;
6305 	return y_current->y_type;
6306     }
6307     return MAUTO;
6308 }
6309 
6310 /*
6311  * When "flags" has GREG_LIST return a list with text "s".
6312  * Otherwise just return "s".
6313  */
6314     static char_u *
6315 getreg_wrap_one_line(char_u *s, int flags)
6316 {
6317     if (flags & GREG_LIST)
6318     {
6319 	list_T *list = list_alloc();
6320 
6321 	if (list != NULL)
6322 	{
6323 	    if (list_append_string(list, NULL, -1) == FAIL)
6324 	    {
6325 		list_free(list);
6326 		return NULL;
6327 	    }
6328 	    list->lv_first->li_tv.vval.v_string = s;
6329 	}
6330 	return (char_u *)list;
6331     }
6332     return s;
6333 }
6334 
6335 /*
6336  * Return the contents of a register as a single allocated string.
6337  * Used for "@r" in expressions and for getreg().
6338  * Returns NULL for error.
6339  * Flags:
6340  *	GREG_NO_EXPR	Do not allow expression register
6341  *	GREG_EXPR_SRC	For the expression register: return expression itself,
6342  *			not the result of its evaluation.
6343  *	GREG_LIST	Return a list of lines in place of a single string.
6344  */
6345     char_u *
6346 get_reg_contents(int regname, int flags)
6347 {
6348     long	i;
6349     char_u	*retval;
6350     int		allocated;
6351     long	len;
6352 
6353     /* Don't allow using an expression register inside an expression */
6354     if (regname == '=')
6355     {
6356 	if (flags & GREG_NO_EXPR)
6357 	    return NULL;
6358 	if (flags & GREG_EXPR_SRC)
6359 	    return getreg_wrap_one_line(get_expr_line_src(), flags);
6360 	return getreg_wrap_one_line(get_expr_line(), flags);
6361     }
6362 
6363     if (regname == '@')	    /* "@@" is used for unnamed register */
6364 	regname = '"';
6365 
6366     /* check for valid regname */
6367     if (regname != NUL && !valid_yank_reg(regname, FALSE))
6368 	return NULL;
6369 
6370 #ifdef FEAT_CLIPBOARD
6371     regname = may_get_selection(regname);
6372 #endif
6373 
6374     if (get_spec_reg(regname, &retval, &allocated, FALSE))
6375     {
6376 	if (retval == NULL)
6377 	    return NULL;
6378 	if (allocated)
6379 	    return getreg_wrap_one_line(retval, flags);
6380 	return getreg_wrap_one_line(vim_strsave(retval), flags);
6381     }
6382 
6383     get_yank_register(regname, FALSE);
6384     if (y_current->y_array == NULL)
6385 	return NULL;
6386 
6387     if (flags & GREG_LIST)
6388     {
6389 	list_T	*list = list_alloc();
6390 	int	error = FALSE;
6391 
6392 	if (list == NULL)
6393 	    return NULL;
6394 	for (i = 0; i < y_current->y_size; ++i)
6395 	    if (list_append_string(list, y_current->y_array[i], -1) == FAIL)
6396 		error = TRUE;
6397 	if (error)
6398 	{
6399 	    list_free(list);
6400 	    return NULL;
6401 	}
6402 	return (char_u *)list;
6403     }
6404 
6405     /*
6406      * Compute length of resulting string.
6407      */
6408     len = 0;
6409     for (i = 0; i < y_current->y_size; ++i)
6410     {
6411 	len += (long)STRLEN(y_current->y_array[i]);
6412 	/*
6413 	 * Insert a newline between lines and after last line if
6414 	 * y_type is MLINE.
6415 	 */
6416 	if (y_current->y_type == MLINE || i < y_current->y_size - 1)
6417 	    ++len;
6418     }
6419 
6420     retval = alloc(len + 1);
6421 
6422     /*
6423      * Copy the lines of the yank register into the string.
6424      */
6425     if (retval != NULL)
6426     {
6427 	len = 0;
6428 	for (i = 0; i < y_current->y_size; ++i)
6429 	{
6430 	    STRCPY(retval + len, y_current->y_array[i]);
6431 	    len += (long)STRLEN(retval + len);
6432 
6433 	    /*
6434 	     * Insert a NL between lines and after the last line if y_type is
6435 	     * MLINE.
6436 	     */
6437 	    if (y_current->y_type == MLINE || i < y_current->y_size - 1)
6438 		retval[len++] = '\n';
6439 	}
6440 	retval[len] = NUL;
6441     }
6442 
6443     return retval;
6444 }
6445 
6446     static int
6447 init_write_reg(
6448     int		name,
6449     yankreg_T	**old_y_previous,
6450     yankreg_T	**old_y_current,
6451     int		must_append,
6452     int		*yank_type UNUSED)
6453 {
6454     if (!valid_yank_reg(name, TRUE))	    /* check for valid reg name */
6455     {
6456 	emsg_invreg(name);
6457 	return FAIL;
6458     }
6459 
6460     /* Don't want to change the current (unnamed) register */
6461     *old_y_previous = y_previous;
6462     *old_y_current = y_current;
6463 
6464     get_yank_register(name, TRUE);
6465     if (!y_append && !must_append)
6466 	free_yank_all();
6467     return OK;
6468 }
6469 
6470     static void
6471 finish_write_reg(
6472     int		name,
6473     yankreg_T	*old_y_previous,
6474     yankreg_T	*old_y_current)
6475 {
6476 # ifdef FEAT_CLIPBOARD
6477     /* Send text of clipboard register to the clipboard. */
6478     may_set_selection();
6479 # endif
6480 
6481     /* ':let @" = "val"' should change the meaning of the "" register */
6482     if (name != '"')
6483 	y_previous = old_y_previous;
6484     y_current = old_y_current;
6485 }
6486 
6487 /*
6488  * Store string "str" in register "name".
6489  * "maxlen" is the maximum number of bytes to use, -1 for all bytes.
6490  * If "must_append" is TRUE, always append to the register.  Otherwise append
6491  * if "name" is an uppercase letter.
6492  * Note: "maxlen" and "must_append" don't work for the "/" register.
6493  * Careful: 'str' is modified, you may have to use a copy!
6494  * If "str" ends in '\n' or '\r', use linewise, otherwise use characterwise.
6495  */
6496     void
6497 write_reg_contents(
6498     int		name,
6499     char_u	*str,
6500     int		maxlen,
6501     int		must_append)
6502 {
6503     write_reg_contents_ex(name, str, maxlen, must_append, MAUTO, 0L);
6504 }
6505 
6506     void
6507 write_reg_contents_lst(
6508     int		name,
6509     char_u	**strings,
6510     int		maxlen UNUSED,
6511     int		must_append,
6512     int		yank_type,
6513     long	block_len)
6514 {
6515     yankreg_T  *old_y_previous, *old_y_current;
6516 
6517     if (name == '/'
6518 #ifdef FEAT_EVAL
6519 	    || name == '='
6520 #endif
6521 	    )
6522     {
6523 	char_u	*s;
6524 
6525 	if (strings[0] == NULL)
6526 	    s = (char_u *)"";
6527 	else if (strings[1] != NULL)
6528 	{
6529 	    emsg(_("E883: search pattern and expression register may not "
6530 			"contain two or more lines"));
6531 	    return;
6532 	}
6533 	else
6534 	    s = strings[0];
6535 	write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
6536 	return;
6537     }
6538 
6539     if (name == '_')	    /* black hole: nothing to do */
6540 	return;
6541 
6542     if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
6543 		&yank_type) == FAIL)
6544 	return;
6545 
6546     str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, TRUE);
6547 
6548     finish_write_reg(name, old_y_previous, old_y_current);
6549 }
6550 
6551     void
6552 write_reg_contents_ex(
6553     int		name,
6554     char_u	*str,
6555     int		maxlen,
6556     int		must_append,
6557     int		yank_type,
6558     long	block_len)
6559 {
6560     yankreg_T	*old_y_previous, *old_y_current;
6561     long	len;
6562 
6563     if (maxlen >= 0)
6564 	len = maxlen;
6565     else
6566 	len = (long)STRLEN(str);
6567 
6568     /* Special case: '/' search pattern */
6569     if (name == '/')
6570     {
6571 	set_last_search_pat(str, RE_SEARCH, TRUE, TRUE);
6572 	return;
6573     }
6574 
6575     if (name == '#')
6576     {
6577 	buf_T	*buf;
6578 
6579 	if (VIM_ISDIGIT(*str))
6580 	{
6581 	    int	num = atoi((char *)str);
6582 
6583 	    buf = buflist_findnr(num);
6584 	    if (buf == NULL)
6585 		semsg(_(e_nobufnr), (long)num);
6586 	}
6587 	else
6588 	    buf = buflist_findnr(buflist_findpat(str, str + STRLEN(str),
6589 							 TRUE, FALSE, FALSE));
6590 	if (buf == NULL)
6591 	    return;
6592 	curwin->w_alt_fnum = buf->b_fnum;
6593 	return;
6594     }
6595 
6596 #ifdef FEAT_EVAL
6597     if (name == '=')
6598     {
6599 	char_u	    *p, *s;
6600 
6601 	p = vim_strnsave(str, (int)len);
6602 	if (p == NULL)
6603 	    return;
6604 	if (must_append)
6605 	{
6606 	    s = concat_str(get_expr_line_src(), p);
6607 	    vim_free(p);
6608 	    p = s;
6609 	}
6610 	set_expr_line(p);
6611 	return;
6612     }
6613 #endif
6614 
6615     if (name == '_')	    /* black hole: nothing to do */
6616 	return;
6617 
6618     if (init_write_reg(name, &old_y_previous, &old_y_current, must_append,
6619 		&yank_type) == FAIL)
6620 	return;
6621 
6622     str_to_reg(y_current, yank_type, str, len, block_len, FALSE);
6623 
6624     finish_write_reg(name, old_y_previous, old_y_current);
6625 }
6626 #endif	/* FEAT_EVAL */
6627 
6628 #if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
6629 /*
6630  * Put a string into a register.  When the register is not empty, the string
6631  * is appended.
6632  */
6633     static void
6634 str_to_reg(
6635     yankreg_T	*y_ptr,		/* pointer to yank register */
6636     int		yank_type,	/* MCHAR, MLINE, MBLOCK, MAUTO */
6637     char_u	*str,		/* string to put in register */
6638     long	len,		/* length of string */
6639     long	blocklen,	/* width of Visual block */
6640     int		str_list)	/* TRUE if str is char_u ** */
6641 {
6642     int		type;			/* MCHAR, MLINE or MBLOCK */
6643     int		lnum;
6644     long	start;
6645     long	i;
6646     int		extra;
6647     int		newlines;		/* number of lines added */
6648     int		extraline = 0;		/* extra line at the end */
6649     int		append = FALSE;		/* append to last line in register */
6650     char_u	*s;
6651     char_u	**ss;
6652     char_u	**pp;
6653     long	maxlen;
6654 
6655     if (y_ptr->y_array == NULL)		/* NULL means empty register */
6656 	y_ptr->y_size = 0;
6657 
6658     if (yank_type == MAUTO)
6659 	type = ((str_list || (len > 0 && (str[len - 1] == NL
6660 					    || str[len - 1] == CAR)))
6661 							     ? MLINE : MCHAR);
6662     else
6663 	type = yank_type;
6664 
6665     /*
6666      * Count the number of lines within the string
6667      */
6668     newlines = 0;
6669     if (str_list)
6670     {
6671 	for (ss = (char_u **) str; *ss != NULL; ++ss)
6672 	    ++newlines;
6673     }
6674     else
6675     {
6676 	for (i = 0; i < len; i++)
6677 	    if (str[i] == '\n')
6678 		++newlines;
6679 	if (type == MCHAR || len == 0 || str[len - 1] != '\n')
6680 	{
6681 	    extraline = 1;
6682 	    ++newlines;	/* count extra newline at the end */
6683 	}
6684 	if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR)
6685 	{
6686 	    append = TRUE;
6687 	    --newlines;	/* uncount newline when appending first line */
6688 	}
6689     }
6690 
6691     /* Without any lines make the register empty. */
6692     if (y_ptr->y_size + newlines == 0)
6693     {
6694 	VIM_CLEAR(y_ptr->y_array);
6695 	return;
6696     }
6697 
6698     /*
6699      * Allocate an array to hold the pointers to the new register lines.
6700      * If the register was not empty, move the existing lines to the new array.
6701      */
6702     pp = lalloc_clear((y_ptr->y_size + newlines) * sizeof(char_u *), TRUE);
6703     if (pp == NULL)	/* out of memory */
6704 	return;
6705     for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
6706 	pp[lnum] = y_ptr->y_array[lnum];
6707     vim_free(y_ptr->y_array);
6708     y_ptr->y_array = pp;
6709     maxlen = 0;
6710 
6711     /*
6712      * Find the end of each line and save it into the array.
6713      */
6714     if (str_list)
6715     {
6716 	for (ss = (char_u **) str; *ss != NULL; ++ss, ++lnum)
6717 	{
6718 	    i = (long)STRLEN(*ss);
6719 	    pp[lnum] = vim_strnsave(*ss, i);
6720 	    if (i > maxlen)
6721 		maxlen = i;
6722 	}
6723     }
6724     else
6725     {
6726 	for (start = 0; start < len + extraline; start += i + 1)
6727 	{
6728 	    for (i = start; i < len; ++i)	/* find the end of the line */
6729 		if (str[i] == '\n')
6730 		    break;
6731 	    i -= start;			/* i is now length of line */
6732 	    if (i > maxlen)
6733 		maxlen = i;
6734 	    if (append)
6735 	    {
6736 		--lnum;
6737 		extra = (int)STRLEN(y_ptr->y_array[lnum]);
6738 	    }
6739 	    else
6740 		extra = 0;
6741 	    s = alloc(i + extra + 1);
6742 	    if (s == NULL)
6743 		break;
6744 	    if (extra)
6745 		mch_memmove(s, y_ptr->y_array[lnum], (size_t)extra);
6746 	    if (append)
6747 		vim_free(y_ptr->y_array[lnum]);
6748 	    if (i)
6749 		mch_memmove(s + extra, str + start, (size_t)i);
6750 	    extra += i;
6751 	    s[extra] = NUL;
6752 	    y_ptr->y_array[lnum++] = s;
6753 	    while (--extra >= 0)
6754 	    {
6755 		if (*s == NUL)
6756 		    *s = '\n';	    /* replace NUL with newline */
6757 		++s;
6758 	    }
6759 	    append = FALSE;		    /* only first line is appended */
6760 	}
6761     }
6762     y_ptr->y_type = type;
6763     y_ptr->y_size = lnum;
6764     if (type == MBLOCK)
6765 	y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
6766     else
6767 	y_ptr->y_width = 0;
6768 #ifdef FEAT_VIMINFO
6769     y_ptr->y_time_set = vim_time();
6770 #endif
6771 }
6772 #endif /* FEAT_CLIPBOARD || FEAT_EVAL || PROTO */
6773 
6774     void
6775 clear_oparg(oparg_T *oap)
6776 {
6777     vim_memset(oap, 0, sizeof(oparg_T));
6778 }
6779 
6780 /*
6781  *  Count the number of bytes, characters and "words" in a line.
6782  *
6783  *  "Words" are counted by looking for boundaries between non-space and
6784  *  space characters.  (it seems to produce results that match 'wc'.)
6785  *
6786  *  Return value is byte count; word count for the line is added to "*wc".
6787  *  Char count is added to "*cc".
6788  *
6789  *  The function will only examine the first "limit" characters in the
6790  *  line, stopping if it encounters an end-of-line (NUL byte).  In that
6791  *  case, eol_size will be added to the character count to account for
6792  *  the size of the EOL character.
6793  */
6794     static varnumber_T
6795 line_count_info(
6796     char_u	*line,
6797     varnumber_T	*wc,
6798     varnumber_T	*cc,
6799     varnumber_T	limit,
6800     int		eol_size)
6801 {
6802     varnumber_T	i;
6803     varnumber_T	words = 0;
6804     varnumber_T	chars = 0;
6805     int		is_word = 0;
6806 
6807     for (i = 0; i < limit && line[i] != NUL; )
6808     {
6809 	if (is_word)
6810 	{
6811 	    if (vim_isspace(line[i]))
6812 	    {
6813 		words++;
6814 		is_word = 0;
6815 	    }
6816 	}
6817 	else if (!vim_isspace(line[i]))
6818 	    is_word = 1;
6819 	++chars;
6820 	i += (*mb_ptr2len)(line + i);
6821     }
6822 
6823     if (is_word)
6824 	words++;
6825     *wc += words;
6826 
6827     /* Add eol_size if the end of line was reached before hitting limit. */
6828     if (i < limit && line[i] == NUL)
6829     {
6830 	i += eol_size;
6831 	chars += eol_size;
6832     }
6833     *cc += chars;
6834     return i;
6835 }
6836 
6837 /*
6838  * Give some info about the position of the cursor (for "g CTRL-G").
6839  * In Visual mode, give some info about the selected region.  (In this case,
6840  * the *_count_cursor variables store running totals for the selection.)
6841  * When "dict" is not NULL store the info there instead of showing it.
6842  */
6843     void
6844 cursor_pos_info(dict_T *dict)
6845 {
6846     char_u	*p;
6847     char_u	buf1[50];
6848     char_u	buf2[40];
6849     linenr_T	lnum;
6850     varnumber_T	byte_count = 0;
6851     varnumber_T	bom_count  = 0;
6852     varnumber_T	byte_count_cursor = 0;
6853     varnumber_T	char_count = 0;
6854     varnumber_T	char_count_cursor = 0;
6855     varnumber_T	word_count = 0;
6856     varnumber_T	word_count_cursor = 0;
6857     int		eol_size;
6858     varnumber_T	last_check = 100000L;
6859     long	line_count_selected = 0;
6860     pos_T	min_pos, max_pos;
6861     oparg_T	oparg;
6862     struct block_def	bd;
6863 
6864     /*
6865      * Compute the length of the file in characters.
6866      */
6867     if (curbuf->b_ml.ml_flags & ML_EMPTY)
6868     {
6869 	if (dict == NULL)
6870 	{
6871 	    msg(_(no_lines_msg));
6872 	    return;
6873 	}
6874     }
6875     else
6876     {
6877 	if (get_fileformat(curbuf) == EOL_DOS)
6878 	    eol_size = 2;
6879 	else
6880 	    eol_size = 1;
6881 
6882 	if (VIsual_active)
6883 	{
6884 	    if (LT_POS(VIsual, curwin->w_cursor))
6885 	    {
6886 		min_pos = VIsual;
6887 		max_pos = curwin->w_cursor;
6888 	    }
6889 	    else
6890 	    {
6891 		min_pos = curwin->w_cursor;
6892 		max_pos = VIsual;
6893 	    }
6894 	    if (*p_sel == 'e' && max_pos.col > 0)
6895 		--max_pos.col;
6896 
6897 	    if (VIsual_mode == Ctrl_V)
6898 	    {
6899 #ifdef FEAT_LINEBREAK
6900 		char_u * saved_sbr = p_sbr;
6901 
6902 		/* Make 'sbr' empty for a moment to get the correct size. */
6903 		p_sbr = empty_option;
6904 #endif
6905 		oparg.is_VIsual = 1;
6906 		oparg.block_mode = TRUE;
6907 		oparg.op_type = OP_NOP;
6908 		getvcols(curwin, &min_pos, &max_pos,
6909 					  &oparg.start_vcol, &oparg.end_vcol);
6910 #ifdef FEAT_LINEBREAK
6911 		p_sbr = saved_sbr;
6912 #endif
6913 		if (curwin->w_curswant == MAXCOL)
6914 		    oparg.end_vcol = MAXCOL;
6915 		/* Swap the start, end vcol if needed */
6916 		if (oparg.end_vcol < oparg.start_vcol)
6917 		{
6918 		    oparg.end_vcol += oparg.start_vcol;
6919 		    oparg.start_vcol = oparg.end_vcol - oparg.start_vcol;
6920 		    oparg.end_vcol -= oparg.start_vcol;
6921 		}
6922 	    }
6923 	    line_count_selected = max_pos.lnum - min_pos.lnum + 1;
6924 	}
6925 
6926 	for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
6927 	{
6928 	    /* Check for a CTRL-C every 100000 characters. */
6929 	    if (byte_count > last_check)
6930 	    {
6931 		ui_breakcheck();
6932 		if (got_int)
6933 		    return;
6934 		last_check = byte_count + 100000L;
6935 	    }
6936 
6937 	    /* Do extra processing for VIsual mode. */
6938 	    if (VIsual_active
6939 		    && lnum >= min_pos.lnum && lnum <= max_pos.lnum)
6940 	    {
6941 		char_u	    *s = NULL;
6942 		long	    len = 0L;
6943 
6944 		switch (VIsual_mode)
6945 		{
6946 		    case Ctrl_V:
6947 			virtual_op = virtual_active();
6948 			block_prep(&oparg, &bd, lnum, 0);
6949 			virtual_op = MAYBE;
6950 			s = bd.textstart;
6951 			len = (long)bd.textlen;
6952 			break;
6953 		    case 'V':
6954 			s = ml_get(lnum);
6955 			len = MAXCOL;
6956 			break;
6957 		    case 'v':
6958 			{
6959 			    colnr_T start_col = (lnum == min_pos.lnum)
6960 							   ? min_pos.col : 0;
6961 			    colnr_T end_col = (lnum == max_pos.lnum)
6962 				      ? max_pos.col - start_col + 1 : MAXCOL;
6963 
6964 			    s = ml_get(lnum) + start_col;
6965 			    len = end_col;
6966 			}
6967 			break;
6968 		}
6969 		if (s != NULL)
6970 		{
6971 		    byte_count_cursor += line_count_info(s, &word_count_cursor,
6972 					   &char_count_cursor, len, eol_size);
6973 		    if (lnum == curbuf->b_ml.ml_line_count
6974 			    && !curbuf->b_p_eol
6975 			    && (curbuf->b_p_bin || !curbuf->b_p_fixeol)
6976 			    && (long)STRLEN(s) < len)
6977 			byte_count_cursor -= eol_size;
6978 		}
6979 	    }
6980 	    else
6981 	    {
6982 		/* In non-visual mode, check for the line the cursor is on */
6983 		if (lnum == curwin->w_cursor.lnum)
6984 		{
6985 		    word_count_cursor += word_count;
6986 		    char_count_cursor += char_count;
6987 		    byte_count_cursor = byte_count +
6988 			line_count_info(ml_get(lnum),
6989 				&word_count_cursor, &char_count_cursor,
6990 				(varnumber_T)(curwin->w_cursor.col + 1),
6991 				eol_size);
6992 		}
6993 	    }
6994 	    /* Add to the running totals */
6995 	    byte_count += line_count_info(ml_get(lnum), &word_count,
6996 					 &char_count, (varnumber_T)MAXCOL,
6997 					 eol_size);
6998 	}
6999 
7000 	/* Correction for when last line doesn't have an EOL. */
7001 	if (!curbuf->b_p_eol && (curbuf->b_p_bin || !curbuf->b_p_fixeol))
7002 	    byte_count -= eol_size;
7003 
7004 	if (dict == NULL)
7005 	{
7006 	    if (VIsual_active)
7007 	    {
7008 		if (VIsual_mode == Ctrl_V && curwin->w_curswant < MAXCOL)
7009 		{
7010 		    getvcols(curwin, &min_pos, &max_pos, &min_pos.col,
7011 								    &max_pos.col);
7012 		    vim_snprintf((char *)buf1, sizeof(buf1), _("%ld Cols; "),
7013 			    (long)(oparg.end_vcol - oparg.start_vcol + 1));
7014 		}
7015 		else
7016 		    buf1[0] = NUL;
7017 
7018 		if (char_count_cursor == byte_count_cursor
7019 						    && char_count == byte_count)
7020 		    vim_snprintf((char *)IObuff, IOSIZE,
7021 			    _("Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes"),
7022 			    buf1, line_count_selected,
7023 			    (long)curbuf->b_ml.ml_line_count,
7024 			    (long_long_T)word_count_cursor,
7025 			    (long_long_T)word_count,
7026 			    (long_long_T)byte_count_cursor,
7027 			    (long_long_T)byte_count);
7028 		else
7029 		    vim_snprintf((char *)IObuff, IOSIZE,
7030 			    _("Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of %lld Bytes"),
7031 			    buf1, line_count_selected,
7032 			    (long)curbuf->b_ml.ml_line_count,
7033 			    (long_long_T)word_count_cursor,
7034 			    (long_long_T)word_count,
7035 			    (long_long_T)char_count_cursor,
7036 			    (long_long_T)char_count,
7037 			    (long_long_T)byte_count_cursor,
7038 			    (long_long_T)byte_count);
7039 	    }
7040 	    else
7041 	    {
7042 		p = ml_get_curline();
7043 		validate_virtcol();
7044 		col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1,
7045 			(int)curwin->w_virtcol + 1);
7046 		col_print(buf2, sizeof(buf2), (int)STRLEN(p),
7047 				    linetabsize(p));
7048 
7049 		if (char_count_cursor == byte_count_cursor
7050 			&& char_count == byte_count)
7051 		    vim_snprintf((char *)IObuff, IOSIZE,
7052 			_("Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld"),
7053 			(char *)buf1, (char *)buf2,
7054 			(long)curwin->w_cursor.lnum,
7055 			(long)curbuf->b_ml.ml_line_count,
7056 			(long_long_T)word_count_cursor, (long_long_T)word_count,
7057 			(long_long_T)byte_count_cursor, (long_long_T)byte_count);
7058 		else
7059 		    vim_snprintf((char *)IObuff, IOSIZE,
7060 			_("Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte %lld of %lld"),
7061 			(char *)buf1, (char *)buf2,
7062 			(long)curwin->w_cursor.lnum,
7063 			(long)curbuf->b_ml.ml_line_count,
7064 			(long_long_T)word_count_cursor, (long_long_T)word_count,
7065 			(long_long_T)char_count_cursor, (long_long_T)char_count,
7066 			(long_long_T)byte_count_cursor, (long_long_T)byte_count);
7067 	    }
7068 	}
7069 
7070 	bom_count = bomb_size();
7071 	if (bom_count > 0)
7072 	    vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE,
7073 				 _("(+%lld for BOM)"), (long_long_T)bom_count);
7074 	if (dict == NULL)
7075 	{
7076 	    /* Don't shorten this message, the user asked for it. */
7077 	    p = p_shm;
7078 	    p_shm = (char_u *)"";
7079 	    msg((char *)IObuff);
7080 	    p_shm = p;
7081 	}
7082     }
7083 #if defined(FEAT_EVAL)
7084     if (dict != NULL)
7085     {
7086 	dict_add_number(dict, "words", word_count);
7087 	dict_add_number(dict, "chars", char_count);
7088 	dict_add_number(dict, "bytes", byte_count + bom_count);
7089 	dict_add_number(dict, VIsual_active ? "visual_bytes" : "cursor_bytes",
7090 		byte_count_cursor);
7091 	dict_add_number(dict, VIsual_active ? "visual_chars" : "cursor_chars",
7092 		char_count_cursor);
7093 	dict_add_number(dict, VIsual_active ? "visual_words" : "cursor_words",
7094 		word_count_cursor);
7095     }
7096 #endif
7097 }
7098