xref: /vim-8.2.3635/src/diff.c (revision 12ee7ff0)
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  * diff.c: code for diff'ing two, three or four buffers.
12  *
13  * There are three ways to diff:
14  * - Shell out to an external diff program, using files.
15  * - Use the compiled-in xdiff library.
16  * - Let 'diffexpr' do the work, using files.
17  */
18 
19 #include "vim.h"
20 #include "xdiff/xdiff.h"
21 
22 #if defined(FEAT_DIFF) || defined(PROTO)
23 
24 static int diff_busy = FALSE;	    // using diff structs, don't change them
25 static int diff_need_update = FALSE; // ex_diffupdate needs to be called
26 
27 /* flags obtained from the 'diffopt' option */
28 #define DIFF_FILLER	0x001	// display filler lines
29 #define DIFF_IBLANK	0x002	// ignore empty lines
30 #define DIFF_ICASE	0x004	// ignore case
31 #define DIFF_IWHITE	0x008	// ignore change in white space
32 #define DIFF_IWHITEALL	0x010	// ignore all white space changes
33 #define DIFF_IWHITEEOL	0x020	// ignore change in white space at EOL
34 #define DIFF_HORIZONTAL	0x040	// horizontal splits
35 #define DIFF_VERTICAL	0x080	// vertical splits
36 #define DIFF_HIDDEN_OFF	0x100	// diffoff when hidden
37 #define DIFF_INTERNAL	0x200	// use internal xdiff algorithm
38 #define ALL_WHITE_DIFF (DIFF_IWHITE | DIFF_IWHITEALL | DIFF_IWHITEEOL)
39 static int	diff_flags = DIFF_INTERNAL | DIFF_FILLER;
40 
41 static long diff_algorithm = 0;
42 
43 #define LBUFLEN 50		/* length of line in diff file */
44 
45 static int diff_a_works = MAYBE; /* TRUE when "diff -a" works, FALSE when it
46 				    doesn't work, MAYBE when not checked yet */
47 #if defined(MSWIN)
48 static int diff_bin_works = MAYBE; /* TRUE when "diff --binary" works, FALSE
49 				      when it doesn't work, MAYBE when not
50 				      checked yet */
51 #endif
52 
53 // used for diff input
54 typedef struct {
55     char_u	*din_fname;  // used for external diff
56     mmfile_t	din_mmfile;  // used for internal diff
57 } diffin_T;
58 
59 // used for diff result
60 typedef struct {
61     char_u	*dout_fname;  // used for external diff
62     garray_T	dout_ga;      // used for internal diff
63 } diffout_T;
64 
65 // two diff inputs and one result
66 typedef struct {
67     diffin_T	dio_orig;     // original file input
68     diffin_T	dio_new;      // new file input
69     diffout_T	dio_diff;     // diff result
70     int		dio_internal; // using internal diff
71 } diffio_T;
72 
73 static int diff_buf_idx(buf_T *buf);
74 static int diff_buf_idx_tp(buf_T *buf, tabpage_T *tp);
75 static void diff_mark_adjust_tp(tabpage_T *tp, int idx, linenr_T line1, linenr_T line2, long amount, long amount_after);
76 static void diff_check_unchanged(tabpage_T *tp, diff_T *dp);
77 static int diff_check_sanity(tabpage_T *tp, diff_T *dp);
78 static void diff_redraw(int dofold);
79 static int check_external_diff(diffio_T *diffio);
80 static int diff_file(diffio_T *diffio);
81 static int diff_equal_entry(diff_T *dp, int idx1, int idx2);
82 static int diff_cmp(char_u *s1, char_u *s2);
83 #ifdef FEAT_FOLDING
84 static void diff_fold_update(diff_T *dp, int skip_idx);
85 #endif
86 static void diff_read(int idx_orig, int idx_new, diffout_T *fname);
87 static void diff_copy_entry(diff_T *dprev, diff_T *dp, int idx_orig, int idx_new);
88 static diff_T *diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp);
89 static int parse_diff_ed(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new, long *count_new);
90 static int parse_diff_unified(char_u *line, linenr_T *lnum_orig, long *count_orig, linenr_T *lnum_new, long *count_new);
91 static int xdiff_out(void *priv, mmbuffer_t *mb, int nbuf);
92 
93 /*
94  * Called when deleting or unloading a buffer: No longer make a diff with it.
95  */
96     void
97 diff_buf_delete(buf_T *buf)
98 {
99     int		i;
100     tabpage_T	*tp;
101 
102     FOR_ALL_TABPAGES(tp)
103     {
104 	i = diff_buf_idx_tp(buf, tp);
105 	if (i != DB_COUNT)
106 	{
107 	    tp->tp_diffbuf[i] = NULL;
108 	    tp->tp_diff_invalid = TRUE;
109 	    if (tp == curtab)
110 		diff_redraw(TRUE);
111 	}
112     }
113 }
114 
115 /*
116  * Check if the current buffer should be added to or removed from the list of
117  * diff buffers.
118  */
119     void
120 diff_buf_adjust(win_T *win)
121 {
122     win_T	*wp;
123     int		i;
124 
125     if (!win->w_p_diff)
126     {
127 	/* When there is no window showing a diff for this buffer, remove
128 	 * it from the diffs. */
129 	FOR_ALL_WINDOWS(wp)
130 	    if (wp->w_buffer == win->w_buffer && wp->w_p_diff)
131 		break;
132 	if (wp == NULL)
133 	{
134 	    i = diff_buf_idx(win->w_buffer);
135 	    if (i != DB_COUNT)
136 	    {
137 		curtab->tp_diffbuf[i] = NULL;
138 		curtab->tp_diff_invalid = TRUE;
139 		diff_redraw(TRUE);
140 	    }
141 	}
142     }
143     else
144 	diff_buf_add(win->w_buffer);
145 }
146 
147 /*
148  * Add a buffer to make diffs for.
149  * Call this when a new buffer is being edited in the current window where
150  * 'diff' is set.
151  * Marks the current buffer as being part of the diff and requiring updating.
152  * This must be done before any autocmd, because a command may use info
153  * about the screen contents.
154  */
155     void
156 diff_buf_add(buf_T *buf)
157 {
158     int		i;
159 
160     if (diff_buf_idx(buf) != DB_COUNT)
161 	return;		/* It's already there. */
162 
163     for (i = 0; i < DB_COUNT; ++i)
164 	if (curtab->tp_diffbuf[i] == NULL)
165 	{
166 	    curtab->tp_diffbuf[i] = buf;
167 	    curtab->tp_diff_invalid = TRUE;
168 	    diff_redraw(TRUE);
169 	    return;
170 	}
171 
172     semsg(_("E96: Cannot diff more than %d buffers"), DB_COUNT);
173 }
174 
175 /*
176  * Remove all buffers to make diffs for.
177  */
178     static void
179 diff_buf_clear(void)
180 {
181     int		i;
182 
183     for (i = 0; i < DB_COUNT; ++i)
184 	if (curtab->tp_diffbuf[i] != NULL)
185 	{
186 	    curtab->tp_diffbuf[i] = NULL;
187 	    curtab->tp_diff_invalid = TRUE;
188 	    diff_redraw(TRUE);
189 	}
190 }
191 
192 /*
193  * Find buffer "buf" in the list of diff buffers for the current tab page.
194  * Return its index or DB_COUNT if not found.
195  */
196     static int
197 diff_buf_idx(buf_T *buf)
198 {
199     int		idx;
200 
201     for (idx = 0; idx < DB_COUNT; ++idx)
202 	if (curtab->tp_diffbuf[idx] == buf)
203 	    break;
204     return idx;
205 }
206 
207 /*
208  * Find buffer "buf" in the list of diff buffers for tab page "tp".
209  * Return its index or DB_COUNT if not found.
210  */
211     static int
212 diff_buf_idx_tp(buf_T *buf, tabpage_T *tp)
213 {
214     int		idx;
215 
216     for (idx = 0; idx < DB_COUNT; ++idx)
217 	if (tp->tp_diffbuf[idx] == buf)
218 	    break;
219     return idx;
220 }
221 
222 /*
223  * Mark the diff info involving buffer "buf" as invalid, it will be updated
224  * when info is requested.
225  */
226     void
227 diff_invalidate(buf_T *buf)
228 {
229     tabpage_T	*tp;
230     int		i;
231 
232     FOR_ALL_TABPAGES(tp)
233     {
234 	i = diff_buf_idx_tp(buf, tp);
235 	if (i != DB_COUNT)
236 	{
237 	    tp->tp_diff_invalid = TRUE;
238 	    if (tp == curtab)
239 		diff_redraw(TRUE);
240 	}
241     }
242 }
243 
244 /*
245  * Called by mark_adjust(): update line numbers in "curbuf".
246  */
247     void
248 diff_mark_adjust(
249     linenr_T	line1,
250     linenr_T	line2,
251     long	amount,
252     long	amount_after)
253 {
254     int		idx;
255     tabpage_T	*tp;
256 
257     /* Handle all tab pages that use the current buffer in a diff. */
258     FOR_ALL_TABPAGES(tp)
259     {
260 	idx = diff_buf_idx_tp(curbuf, tp);
261 	if (idx != DB_COUNT)
262 	    diff_mark_adjust_tp(tp, idx, line1, line2, amount, amount_after);
263     }
264 }
265 
266 /*
267  * Update line numbers in tab page "tp" for "curbuf" with index "idx".
268  * This attempts to update the changes as much as possible:
269  * When inserting/deleting lines outside of existing change blocks, create a
270  * new change block and update the line numbers in following blocks.
271  * When inserting/deleting lines in existing change blocks, update them.
272  */
273     static void
274 diff_mark_adjust_tp(
275     tabpage_T	*tp,
276     int		idx,
277     linenr_T	line1,
278     linenr_T	line2,
279     long	amount,
280     long	amount_after)
281 {
282     diff_T	*dp;
283     diff_T	*dprev;
284     diff_T	*dnext;
285     int		i;
286     int		inserted, deleted;
287     int		n, off;
288     linenr_T	last;
289     linenr_T	lnum_deleted = line1;	/* lnum of remaining deletion */
290     int		check_unchanged;
291 
292     if (diff_internal())
293     {
294 	// Will update diffs before redrawing.  Set _invalid to update the
295 	// diffs themselves, set _update to also update folds properly just
296 	// before redrawing.
297 	// Do update marks here, it is needed for :%diffput.
298 	tp->tp_diff_invalid = TRUE;
299 	tp->tp_diff_update = TRUE;
300     }
301 
302     if (line2 == MAXLNUM)
303     {
304 	/* mark_adjust(99, MAXLNUM, 9, 0): insert lines */
305 	inserted = amount;
306 	deleted = 0;
307     }
308     else if (amount_after > 0)
309     {
310 	/* mark_adjust(99, 98, MAXLNUM, 9): a change that inserts lines*/
311 	inserted = amount_after;
312 	deleted = 0;
313     }
314     else
315     {
316 	/* mark_adjust(98, 99, MAXLNUM, -2): delete lines */
317 	inserted = 0;
318 	deleted = -amount_after;
319     }
320 
321     dprev = NULL;
322     dp = tp->tp_first_diff;
323     for (;;)
324     {
325 	/* If the change is after the previous diff block and before the next
326 	 * diff block, thus not touching an existing change, create a new diff
327 	 * block.  Don't do this when ex_diffgetput() is busy. */
328 	if ((dp == NULL || dp->df_lnum[idx] - 1 > line2
329 		    || (line2 == MAXLNUM && dp->df_lnum[idx] > line1))
330 		&& (dprev == NULL
331 		    || dprev->df_lnum[idx] + dprev->df_count[idx] < line1)
332 		&& !diff_busy)
333 	{
334 	    dnext = diff_alloc_new(tp, dprev, dp);
335 	    if (dnext == NULL)
336 		return;
337 
338 	    dnext->df_lnum[idx] = line1;
339 	    dnext->df_count[idx] = inserted;
340 	    for (i = 0; i < DB_COUNT; ++i)
341 		if (tp->tp_diffbuf[i] != NULL && i != idx)
342 		{
343 		    if (dprev == NULL)
344 			dnext->df_lnum[i] = line1;
345 		    else
346 			dnext->df_lnum[i] = line1
347 			    + (dprev->df_lnum[i] + dprev->df_count[i])
348 			    - (dprev->df_lnum[idx] + dprev->df_count[idx]);
349 		    dnext->df_count[i] = deleted;
350 		}
351 	}
352 
353 	/* if at end of the list, quit */
354 	if (dp == NULL)
355 	    break;
356 
357 	/*
358 	 * Check for these situations:
359 	 *	  1  2	3
360 	 *	  1  2	3
361 	 * line1     2	3  4  5
362 	 *	     2	3  4  5
363 	 *	     2	3  4  5
364 	 * line2     2	3  4  5
365 	 *		3     5  6
366 	 *		3     5  6
367 	 */
368 	/* compute last line of this change */
369 	last = dp->df_lnum[idx] + dp->df_count[idx] - 1;
370 
371 	/* 1. change completely above line1: nothing to do */
372 	if (last >= line1 - 1)
373 	{
374 	    /* 6. change below line2: only adjust for amount_after; also when
375 	     * "deleted" became zero when deleted all lines between two diffs */
376 	    if (dp->df_lnum[idx] - (deleted + inserted != 0) > line2)
377 	    {
378 		if (amount_after == 0)
379 		    break;	/* nothing left to change */
380 		dp->df_lnum[idx] += amount_after;
381 	    }
382 	    else
383 	    {
384 		check_unchanged = FALSE;
385 
386 		/* 2. 3. 4. 5.: inserted/deleted lines touching this diff. */
387 		if (deleted > 0)
388 		{
389 		    if (dp->df_lnum[idx] >= line1)
390 		    {
391 			off = dp->df_lnum[idx] - lnum_deleted;
392 			if (last <= line2)
393 			{
394 			    /* 4. delete all lines of diff */
395 			    if (dp->df_next != NULL
396 				    && dp->df_next->df_lnum[idx] - 1 <= line2)
397 			    {
398 				/* delete continues in next diff, only do
399 				 * lines until that one */
400 				n = dp->df_next->df_lnum[idx] - lnum_deleted;
401 				deleted -= n;
402 				n -= dp->df_count[idx];
403 				lnum_deleted = dp->df_next->df_lnum[idx];
404 			    }
405 			    else
406 				n = deleted - dp->df_count[idx];
407 			    dp->df_count[idx] = 0;
408 			}
409 			else
410 			{
411 			    /* 5. delete lines at or just before top of diff */
412 			    n = off;
413 			    dp->df_count[idx] -= line2 - dp->df_lnum[idx] + 1;
414 			    check_unchanged = TRUE;
415 			}
416 			dp->df_lnum[idx] = line1;
417 		    }
418 		    else
419 		    {
420 			off = 0;
421 			if (last < line2)
422 			{
423 			    /* 2. delete at end of of diff */
424 			    dp->df_count[idx] -= last - lnum_deleted + 1;
425 			    if (dp->df_next != NULL
426 				    && dp->df_next->df_lnum[idx] - 1 <= line2)
427 			    {
428 				/* delete continues in next diff, only do
429 				 * lines until that one */
430 				n = dp->df_next->df_lnum[idx] - 1 - last;
431 				deleted -= dp->df_next->df_lnum[idx]
432 							       - lnum_deleted;
433 				lnum_deleted = dp->df_next->df_lnum[idx];
434 			    }
435 			    else
436 				n = line2 - last;
437 			    check_unchanged = TRUE;
438 			}
439 			else
440 			{
441 			    /* 3. delete lines inside the diff */
442 			    n = 0;
443 			    dp->df_count[idx] -= deleted;
444 			}
445 		    }
446 
447 		    for (i = 0; i < DB_COUNT; ++i)
448 			if (tp->tp_diffbuf[i] != NULL && i != idx)
449 			{
450 			    dp->df_lnum[i] -= off;
451 			    dp->df_count[i] += n;
452 			}
453 		}
454 		else
455 		{
456 		    if (dp->df_lnum[idx] <= line1)
457 		    {
458 			/* inserted lines somewhere in this diff */
459 			dp->df_count[idx] += inserted;
460 			check_unchanged = TRUE;
461 		    }
462 		    else
463 			/* inserted lines somewhere above this diff */
464 			dp->df_lnum[idx] += inserted;
465 		}
466 
467 		if (check_unchanged)
468 		    /* Check if inserted lines are equal, may reduce the
469 		     * size of the diff.  TODO: also check for equal lines
470 		     * in the middle and perhaps split the block. */
471 		    diff_check_unchanged(tp, dp);
472 	    }
473 	}
474 
475 	/* check if this block touches the previous one, may merge them. */
476 	if (dprev != NULL && dprev->df_lnum[idx] + dprev->df_count[idx]
477 							  == dp->df_lnum[idx])
478 	{
479 	    for (i = 0; i < DB_COUNT; ++i)
480 		if (tp->tp_diffbuf[i] != NULL)
481 		    dprev->df_count[i] += dp->df_count[i];
482 	    dprev->df_next = dp->df_next;
483 	    vim_free(dp);
484 	    dp = dprev->df_next;
485 	}
486 	else
487 	{
488 	    /* Advance to next entry. */
489 	    dprev = dp;
490 	    dp = dp->df_next;
491 	}
492     }
493 
494     dprev = NULL;
495     dp = tp->tp_first_diff;
496     while (dp != NULL)
497     {
498 	/* All counts are zero, remove this entry. */
499 	for (i = 0; i < DB_COUNT; ++i)
500 	    if (tp->tp_diffbuf[i] != NULL && dp->df_count[i] != 0)
501 		break;
502 	if (i == DB_COUNT)
503 	{
504 	    dnext = dp->df_next;
505 	    vim_free(dp);
506 	    dp = dnext;
507 	    if (dprev == NULL)
508 		tp->tp_first_diff = dnext;
509 	    else
510 		dprev->df_next = dnext;
511 	}
512 	else
513 	{
514 	    /* Advance to next entry. */
515 	    dprev = dp;
516 	    dp = dp->df_next;
517 	}
518 
519     }
520 
521     if (tp == curtab)
522     {
523 	diff_redraw(TRUE);
524 
525 	/* Need to recompute the scroll binding, may remove or add filler
526 	 * lines (e.g., when adding lines above w_topline). But it's slow when
527 	 * making many changes, postpone until redrawing. */
528 	diff_need_scrollbind = TRUE;
529     }
530 }
531 
532 /*
533  * Allocate a new diff block and link it between "dprev" and "dp".
534  */
535     static diff_T *
536 diff_alloc_new(tabpage_T *tp, diff_T *dprev, diff_T *dp)
537 {
538     diff_T	*dnew;
539 
540     dnew = ALLOC_ONE(diff_T);
541     if (dnew != NULL)
542     {
543 	dnew->df_next = dp;
544 	if (dprev == NULL)
545 	    tp->tp_first_diff = dnew;
546 	else
547 	    dprev->df_next = dnew;
548     }
549     return dnew;
550 }
551 
552 /*
553  * Check if the diff block "dp" can be made smaller for lines at the start and
554  * end that are equal.  Called after inserting lines.
555  * This may result in a change where all buffers have zero lines, the caller
556  * must take care of removing it.
557  */
558     static void
559 diff_check_unchanged(tabpage_T *tp, diff_T *dp)
560 {
561     int		i_org;
562     int		i_new;
563     int		off_org, off_new;
564     char_u	*line_org;
565     int		dir = FORWARD;
566 
567     /* Find the first buffers, use it as the original, compare the other
568      * buffer lines against this one. */
569     for (i_org = 0; i_org < DB_COUNT; ++i_org)
570 	if (tp->tp_diffbuf[i_org] != NULL)
571 	    break;
572     if (i_org == DB_COUNT)	/* safety check */
573 	return;
574 
575     if (diff_check_sanity(tp, dp) == FAIL)
576 	return;
577 
578     /* First check lines at the top, then at the bottom. */
579     off_org = 0;
580     off_new = 0;
581     for (;;)
582     {
583 	/* Repeat until a line is found which is different or the number of
584 	 * lines has become zero. */
585 	while (dp->df_count[i_org] > 0)
586 	{
587 	    /* Copy the line, the next ml_get() will invalidate it.  */
588 	    if (dir == BACKWARD)
589 		off_org = dp->df_count[i_org] - 1;
590 	    line_org = vim_strsave(ml_get_buf(tp->tp_diffbuf[i_org],
591 					dp->df_lnum[i_org] + off_org, FALSE));
592 	    if (line_org == NULL)
593 		return;
594 	    for (i_new = i_org + 1; i_new < DB_COUNT; ++i_new)
595 	    {
596 		if (tp->tp_diffbuf[i_new] == NULL)
597 		    continue;
598 		if (dir == BACKWARD)
599 		    off_new = dp->df_count[i_new] - 1;
600 		/* if other buffer doesn't have this line, it was inserted */
601 		if (off_new < 0 || off_new >= dp->df_count[i_new])
602 		    break;
603 		if (diff_cmp(line_org, ml_get_buf(tp->tp_diffbuf[i_new],
604 				   dp->df_lnum[i_new] + off_new, FALSE)) != 0)
605 		    break;
606 	    }
607 	    vim_free(line_org);
608 
609 	    /* Stop when a line isn't equal in all diff buffers. */
610 	    if (i_new != DB_COUNT)
611 		break;
612 
613 	    /* Line matched in all buffers, remove it from the diff. */
614 	    for (i_new = i_org; i_new < DB_COUNT; ++i_new)
615 		if (tp->tp_diffbuf[i_new] != NULL)
616 		{
617 		    if (dir == FORWARD)
618 			++dp->df_lnum[i_new];
619 		    --dp->df_count[i_new];
620 		}
621 	}
622 	if (dir == BACKWARD)
623 	    break;
624 	dir = BACKWARD;
625     }
626 }
627 
628 /*
629  * Check if a diff block doesn't contain invalid line numbers.
630  * This can happen when the diff program returns invalid results.
631  */
632     static int
633 diff_check_sanity(tabpage_T *tp, diff_T *dp)
634 {
635     int		i;
636 
637     for (i = 0; i < DB_COUNT; ++i)
638 	if (tp->tp_diffbuf[i] != NULL)
639 	    if (dp->df_lnum[i] + dp->df_count[i] - 1
640 				      > tp->tp_diffbuf[i]->b_ml.ml_line_count)
641 		return FAIL;
642     return OK;
643 }
644 
645 /*
646  * Mark all diff buffers in the current tab page for redraw.
647  */
648     static void
649 diff_redraw(
650     int		dofold)	    // also recompute the folds
651 {
652     win_T	*wp;
653     int		n;
654 
655     FOR_ALL_WINDOWS(wp)
656 	if (wp->w_p_diff)
657 	{
658 	    redraw_win_later(wp, SOME_VALID);
659 #ifdef FEAT_FOLDING
660 	    if (dofold && foldmethodIsDiff(wp))
661 		foldUpdateAll(wp);
662 #endif
663 	    /* A change may have made filler lines invalid, need to take care
664 	     * of that for other windows. */
665 	    n = diff_check(wp, wp->w_topline);
666 	    if ((wp != curwin && wp->w_topfill > 0) || n > 0)
667 	    {
668 		if (wp->w_topfill > n)
669 		    wp->w_topfill = (n < 0 ? 0 : n);
670 		else if (n > 0 && n > wp->w_topfill)
671 		    wp->w_topfill = n;
672 		check_topfill(wp, FALSE);
673 	    }
674 	}
675 }
676 
677     static void
678 clear_diffin(diffin_T *din)
679 {
680     if (din->din_fname == NULL)
681     {
682 	vim_free(din->din_mmfile.ptr);
683 	din->din_mmfile.ptr = NULL;
684     }
685     else
686 	mch_remove(din->din_fname);
687 }
688 
689     static void
690 clear_diffout(diffout_T *dout)
691 {
692     if (dout->dout_fname == NULL)
693 	ga_clear_strings(&dout->dout_ga);
694     else
695 	mch_remove(dout->dout_fname);
696 }
697 
698 /*
699  * Write buffer "buf" to a memory buffer.
700  * Return FAIL for failure.
701  */
702     static int
703 diff_write_buffer(buf_T *buf, diffin_T *din)
704 {
705     linenr_T	lnum;
706     char_u	*s;
707     long	len = 0;
708     char_u	*ptr;
709 
710     // xdiff requires one big block of memory with all the text.
711     for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
712 	len += (long)STRLEN(ml_get_buf(buf, lnum, FALSE)) + 1;
713     ptr = alloc(len);
714     if (ptr == NULL)
715     {
716 	// Allocating memory failed.  This can happen, because we try to read
717 	// the whole buffer text into memory.  Set the failed flag, the diff
718 	// will be retried with external diff.  The flag is never reset.
719 	buf->b_diff_failed = TRUE;
720 	if (p_verbose > 0)
721 	{
722 	    verbose_enter();
723 	    smsg(_("Not enough memory to use internal diff for buffer \"%s\""),
724 								 buf->b_fname);
725 	    verbose_leave();
726 	}
727 	return FAIL;
728     }
729     din->din_mmfile.ptr = (char *)ptr;
730     din->din_mmfile.size = len;
731 
732     len = 0;
733     for (lnum = 1; lnum <= buf->b_ml.ml_line_count; ++lnum)
734     {
735 	for (s = ml_get_buf(buf, lnum, FALSE); *s != NUL; )
736 	{
737 	    if (diff_flags & DIFF_ICASE)
738 	    {
739 		int c;
740 		int	orig_len;
741 		char_u	cbuf[MB_MAXBYTES + 1];
742 
743 		// xdiff doesn't support ignoring case, fold-case the text.
744 		c = PTR2CHAR(s);
745 		c = enc_utf8 ? utf_fold(c) : MB_TOLOWER(c);
746 		orig_len = MB_PTR2LEN(s);
747 		if (mb_char2bytes(c, cbuf) != orig_len)
748 		    // TODO: handle byte length difference
749 		    mch_memmove(ptr + len, s, orig_len);
750 		else
751 		    mch_memmove(ptr + len, cbuf, orig_len);
752 
753 		s += orig_len;
754 		len += orig_len;
755 	    }
756 	    else
757 		ptr[len++] = *s++;
758 	}
759 	ptr[len++] = NL;
760     }
761     return OK;
762 }
763 
764 /*
765  * Write buffer "buf" to file or memory buffer.
766  * Return FAIL for failure.
767  */
768     static int
769 diff_write(buf_T *buf, diffin_T *din)
770 {
771     int		r;
772     char_u	*save_ff;
773 
774     if (din->din_fname == NULL)
775 	return diff_write_buffer(buf, din);
776 
777     // Always use 'fileformat' set to "unix".
778     save_ff = buf->b_p_ff;
779     buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
780     r = buf_write(buf, din->din_fname, NULL,
781 			(linenr_T)1, buf->b_ml.ml_line_count,
782 			NULL, FALSE, FALSE, FALSE, TRUE);
783     free_string_option(buf->b_p_ff);
784     buf->b_p_ff = save_ff;
785     return r;
786 }
787 
788 /*
789  * Update the diffs for all buffers involved.
790  */
791     static void
792 diff_try_update(
793 	diffio_T    *dio,
794 	int	    idx_orig,
795 	exarg_T	    *eap)	// "eap" can be NULL
796 {
797     buf_T	*buf;
798     int		idx_new;
799 
800     if (dio->dio_internal)
801     {
802 	ga_init2(&dio->dio_diff.dout_ga, sizeof(char *), 1000);
803     }
804     else
805     {
806 	// We need three temp file names.
807 	dio->dio_orig.din_fname = vim_tempname('o', TRUE);
808 	dio->dio_new.din_fname = vim_tempname('n', TRUE);
809 	dio->dio_diff.dout_fname = vim_tempname('d', TRUE);
810 	if (dio->dio_orig.din_fname == NULL
811 		|| dio->dio_new.din_fname == NULL
812 		|| dio->dio_diff.dout_fname == NULL)
813 	    goto theend;
814     }
815 
816     // Check external diff is actually working.
817     if (!dio->dio_internal && check_external_diff(dio) == FAIL)
818 	goto theend;
819 
820     // :diffupdate!
821     if (eap != NULL && eap->forceit)
822 	for (idx_new = idx_orig; idx_new < DB_COUNT; ++idx_new)
823 	{
824 	    buf = curtab->tp_diffbuf[idx_new];
825 	    if (buf_valid(buf))
826 		buf_check_timestamp(buf, FALSE);
827 	}
828 
829     // Write the first buffer to a tempfile or mmfile_t.
830     buf = curtab->tp_diffbuf[idx_orig];
831     if (diff_write(buf, &dio->dio_orig) == FAIL)
832 	goto theend;
833 
834     // Make a difference between the first buffer and every other.
835     for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
836     {
837 	buf = curtab->tp_diffbuf[idx_new];
838 	if (buf == NULL || buf->b_ml.ml_mfp == NULL)
839 	    continue; // skip buffer that isn't loaded
840 
841 	// Write the other buffer and diff with the first one.
842 	if (diff_write(buf, &dio->dio_new) == FAIL)
843 	    continue;
844 	if (diff_file(dio) == FAIL)
845 	    continue;
846 
847 	// Read the diff output and add each entry to the diff list.
848 	diff_read(idx_orig, idx_new, &dio->dio_diff);
849 
850 	clear_diffin(&dio->dio_new);
851 	clear_diffout(&dio->dio_diff);
852     }
853     clear_diffin(&dio->dio_orig);
854 
855 theend:
856     vim_free(dio->dio_orig.din_fname);
857     vim_free(dio->dio_new.din_fname);
858     vim_free(dio->dio_diff.dout_fname);
859 }
860 
861 /*
862  * Return TRUE if the options are set to use the internal diff library.
863  * Note that if the internal diff failed for one of the buffers, the external
864  * diff will be used anyway.
865  */
866     int
867 diff_internal(void)
868 {
869     return (diff_flags & DIFF_INTERNAL) != 0
870 #ifdef FEAT_EVAL
871 	&& *p_dex == NUL
872 #endif
873 	;
874 }
875 
876 /*
877  * Return TRUE if the internal diff failed for one of the diff buffers.
878  */
879     static int
880 diff_internal_failed(void)
881 {
882     int idx;
883 
884     // Only need to do something when there is another buffer.
885     for (idx = 0; idx < DB_COUNT; ++idx)
886 	if (curtab->tp_diffbuf[idx] != NULL
887 		&& curtab->tp_diffbuf[idx]->b_diff_failed)
888 	    return TRUE;
889     return FALSE;
890 }
891 
892 /*
893  * Completely update the diffs for the buffers involved.
894  * When using the external "diff" command the buffers are written to a file,
895  * also for unmodified buffers (the file could have been produced by
896  * autocommands, e.g. the netrw plugin).
897  */
898     void
899 ex_diffupdate(exarg_T *eap)	// "eap" can be NULL
900 {
901     int		idx_orig;
902     int		idx_new;
903     diffio_T	diffio;
904     int		had_diffs = curtab->tp_first_diff != NULL;
905 
906     if (diff_busy)
907     {
908 	diff_need_update = TRUE;
909 	return;
910     }
911 
912     // Delete all diffblocks.
913     diff_clear(curtab);
914     curtab->tp_diff_invalid = FALSE;
915 
916     // Use the first buffer as the original text.
917     for (idx_orig = 0; idx_orig < DB_COUNT; ++idx_orig)
918 	if (curtab->tp_diffbuf[idx_orig] != NULL)
919 	    break;
920     if (idx_orig == DB_COUNT)
921 	goto theend;
922 
923     // Only need to do something when there is another buffer.
924     for (idx_new = idx_orig + 1; idx_new < DB_COUNT; ++idx_new)
925 	if (curtab->tp_diffbuf[idx_new] != NULL)
926 	    break;
927     if (idx_new == DB_COUNT)
928 	goto theend;
929 
930     // Only use the internal method if it did not fail for one of the buffers.
931     vim_memset(&diffio, 0, sizeof(diffio));
932     diffio.dio_internal = diff_internal() && !diff_internal_failed();
933 
934     diff_try_update(&diffio, idx_orig, eap);
935     if (diffio.dio_internal && diff_internal_failed())
936     {
937 	// Internal diff failed, use external diff instead.
938 	vim_memset(&diffio, 0, sizeof(diffio));
939 	diff_try_update(&diffio, idx_orig, eap);
940     }
941 
942     // force updating cursor position on screen
943     curwin->w_valid_cursor.lnum = 0;
944 
945 theend:
946     // A redraw is needed if there were diffs and they were cleared, or there
947     // are diffs now, which means they got updated.
948     if (had_diffs || curtab->tp_first_diff != NULL)
949     {
950 	diff_redraw(TRUE);
951 	apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
952     }
953 }
954 
955 /*
956  * Do a quick test if "diff" really works.  Otherwise it looks like there
957  * are no differences.  Can't use the return value, it's non-zero when
958  * there are differences.
959  */
960     static int
961 check_external_diff(diffio_T *diffio)
962 {
963     FILE	*fd;
964     int		ok;
965     int		io_error = FALSE;
966 
967     // May try twice, first with "-a" and then without.
968     for (;;)
969     {
970 	ok = FALSE;
971 	fd = mch_fopen((char *)diffio->dio_orig.din_fname, "w");
972 	if (fd == NULL)
973 	    io_error = TRUE;
974 	else
975 	{
976 	    if (fwrite("line1\n", (size_t)6, (size_t)1, fd) != 1)
977 		io_error = TRUE;
978 	    fclose(fd);
979 	    fd = mch_fopen((char *)diffio->dio_new.din_fname, "w");
980 	    if (fd == NULL)
981 		io_error = TRUE;
982 	    else
983 	    {
984 		if (fwrite("line2\n", (size_t)6, (size_t)1, fd) != 1)
985 		    io_error = TRUE;
986 		fclose(fd);
987 		fd = NULL;
988 		if (diff_file(diffio) == OK)
989 		    fd = mch_fopen((char *)diffio->dio_diff.dout_fname, "r");
990 		if (fd == NULL)
991 		    io_error = TRUE;
992 		else
993 		{
994 		    char_u	linebuf[LBUFLEN];
995 
996 		    for (;;)
997 		    {
998 			/* There must be a line that contains "1c1". */
999 			if (vim_fgets(linebuf, LBUFLEN, fd))
1000 			    break;
1001 			if (STRNCMP(linebuf, "1c1", 3) == 0)
1002 			    ok = TRUE;
1003 		    }
1004 		    fclose(fd);
1005 		}
1006 		mch_remove(diffio->dio_diff.dout_fname);
1007 		mch_remove(diffio->dio_new.din_fname);
1008 	    }
1009 	    mch_remove(diffio->dio_orig.din_fname);
1010 	}
1011 
1012 #ifdef FEAT_EVAL
1013 	/* When using 'diffexpr' break here. */
1014 	if (*p_dex != NUL)
1015 	    break;
1016 #endif
1017 
1018 #if defined(MSWIN)
1019 	/* If the "-a" argument works, also check if "--binary" works. */
1020 	if (ok && diff_a_works == MAYBE && diff_bin_works == MAYBE)
1021 	{
1022 	    diff_a_works = TRUE;
1023 	    diff_bin_works = TRUE;
1024 	    continue;
1025 	}
1026 	if (!ok && diff_a_works == TRUE && diff_bin_works == TRUE)
1027 	{
1028 	    /* Tried --binary, but it failed. "-a" works though. */
1029 	    diff_bin_works = FALSE;
1030 	    ok = TRUE;
1031 	}
1032 #endif
1033 
1034 	/* If we checked if "-a" works already, break here. */
1035 	if (diff_a_works != MAYBE)
1036 	    break;
1037 	diff_a_works = ok;
1038 
1039 	/* If "-a" works break here, otherwise retry without "-a". */
1040 	if (ok)
1041 	    break;
1042     }
1043     if (!ok)
1044     {
1045 	if (io_error)
1046 	    emsg(_("E810: Cannot read or write temp files"));
1047 	emsg(_("E97: Cannot create diffs"));
1048 	diff_a_works = MAYBE;
1049 #if defined(MSWIN)
1050 	diff_bin_works = MAYBE;
1051 #endif
1052 	return FAIL;
1053     }
1054     return OK;
1055 }
1056 
1057 /*
1058  * Invoke the xdiff function.
1059  */
1060     static int
1061 diff_file_internal(diffio_T *diffio)
1062 {
1063     xpparam_t	    param;
1064     xdemitconf_t    emit_cfg;
1065     xdemitcb_t	    emit_cb;
1066 
1067     vim_memset(&param, 0, sizeof(param));
1068     vim_memset(&emit_cfg, 0, sizeof(emit_cfg));
1069     vim_memset(&emit_cb, 0, sizeof(emit_cb));
1070 
1071     param.flags = diff_algorithm;
1072 
1073     if (diff_flags & DIFF_IWHITE)
1074 	param.flags |= XDF_IGNORE_WHITESPACE_CHANGE;
1075     if (diff_flags & DIFF_IWHITEALL)
1076 	param.flags |= XDF_IGNORE_WHITESPACE;
1077     if (diff_flags & DIFF_IWHITEEOL)
1078 	param.flags |= XDF_IGNORE_WHITESPACE_AT_EOL;
1079     if (diff_flags & DIFF_IBLANK)
1080 	param.flags |= XDF_IGNORE_BLANK_LINES;
1081 
1082     emit_cfg.ctxlen = 0; // don't need any diff_context here
1083     emit_cb.priv = &diffio->dio_diff;
1084     emit_cb.outf = xdiff_out;
1085     if (xdl_diff(&diffio->dio_orig.din_mmfile,
1086 		&diffio->dio_new.din_mmfile,
1087 		&param, &emit_cfg, &emit_cb) < 0)
1088     {
1089 	emsg(_("E960: Problem creating the internal diff"));
1090 	return FAIL;
1091     }
1092     return OK;
1093 }
1094 
1095 /*
1096  * Make a diff between files "tmp_orig" and "tmp_new", results in "tmp_diff".
1097  * return OK or FAIL;
1098  */
1099     static int
1100 diff_file(diffio_T *dio)
1101 {
1102     char_u	*cmd;
1103     size_t	len;
1104     char_u	*tmp_orig = dio->dio_orig.din_fname;
1105     char_u	*tmp_new = dio->dio_new.din_fname;
1106     char_u	*tmp_diff = dio->dio_diff.dout_fname;
1107 
1108 #ifdef FEAT_EVAL
1109     if (*p_dex != NUL)
1110     {
1111 	// Use 'diffexpr' to generate the diff file.
1112 	eval_diff(tmp_orig, tmp_new, tmp_diff);
1113 	return OK;
1114     }
1115     else
1116 #endif
1117     // Use xdiff for generating the diff.
1118     if (dio->dio_internal)
1119     {
1120 	return diff_file_internal(dio);
1121     }
1122     else
1123     {
1124 	len = STRLEN(tmp_orig) + STRLEN(tmp_new)
1125 				      + STRLEN(tmp_diff) + STRLEN(p_srr) + 27;
1126 	cmd = alloc(len);
1127 	if (cmd == NULL)
1128 	    return FAIL;
1129 
1130 	// We don't want $DIFF_OPTIONS to get in the way.
1131 	if (getenv("DIFF_OPTIONS"))
1132 	    vim_setenv((char_u *)"DIFF_OPTIONS", (char_u *)"");
1133 
1134 	// Build the diff command and execute it.  Always use -a, binary
1135 	// differences are of no use.  Ignore errors, diff returns
1136 	// non-zero when differences have been found.
1137 	vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s%s%s%s %s",
1138 		diff_a_works == FALSE ? "" : "-a ",
1139 #if defined(MSWIN)
1140 		diff_bin_works == TRUE ? "--binary " : "",
1141 #else
1142 		"",
1143 #endif
1144 		(diff_flags & DIFF_IWHITE) ? "-b " : "",
1145 		(diff_flags & DIFF_IWHITEALL) ? "-w " : "",
1146 		(diff_flags & DIFF_IWHITEEOL) ? "-Z " : "",
1147 		(diff_flags & DIFF_IBLANK) ? "-B " : "",
1148 		(diff_flags & DIFF_ICASE) ? "-i " : "",
1149 		tmp_orig, tmp_new);
1150 	append_redir(cmd, (int)len, p_srr, tmp_diff);
1151 	block_autocmds();	// avoid ShellCmdPost stuff
1152 	(void)call_shell(cmd, SHELL_FILTER|SHELL_SILENT|SHELL_DOOUT);
1153 	unblock_autocmds();
1154 	vim_free(cmd);
1155 	return OK;
1156     }
1157 }
1158 
1159 /*
1160  * Create a new version of a file from the current buffer and a diff file.
1161  * The buffer is written to a file, also for unmodified buffers (the file
1162  * could have been produced by autocommands, e.g. the netrw plugin).
1163  */
1164     void
1165 ex_diffpatch(exarg_T *eap)
1166 {
1167     char_u	*tmp_orig;	/* name of original temp file */
1168     char_u	*tmp_new;	/* name of patched temp file */
1169     char_u	*buf = NULL;
1170     size_t	buflen;
1171     win_T	*old_curwin = curwin;
1172     char_u	*newname = NULL;	/* name of patched file buffer */
1173 #ifdef UNIX
1174     char_u	dirbuf[MAXPATHL];
1175     char_u	*fullname = NULL;
1176 #endif
1177 #ifdef FEAT_BROWSE
1178     char_u	*browseFile = NULL;
1179     int		browse_flag = cmdmod.browse;
1180 #endif
1181     stat_T	st;
1182     char_u	*esc_name = NULL;
1183 
1184 #ifdef FEAT_BROWSE
1185     if (cmdmod.browse)
1186     {
1187 	browseFile = do_browse(0, (char_u *)_("Patch file"),
1188 			 eap->arg, NULL, NULL,
1189 			 (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL);
1190 	if (browseFile == NULL)
1191 	    return;		/* operation cancelled */
1192 	eap->arg = browseFile;
1193 	cmdmod.browse = FALSE;	/* don't let do_ecmd() browse again */
1194     }
1195 #endif
1196 
1197     /* We need two temp file names. */
1198     tmp_orig = vim_tempname('o', FALSE);
1199     tmp_new = vim_tempname('n', FALSE);
1200     if (tmp_orig == NULL || tmp_new == NULL)
1201 	goto theend;
1202 
1203     /* Write the current buffer to "tmp_orig". */
1204     if (buf_write(curbuf, tmp_orig, NULL,
1205 		(linenr_T)1, curbuf->b_ml.ml_line_count,
1206 				     NULL, FALSE, FALSE, FALSE, TRUE) == FAIL)
1207 	goto theend;
1208 
1209 #ifdef UNIX
1210     /* Get the absolute path of the patchfile, changing directory below. */
1211     fullname = FullName_save(eap->arg, FALSE);
1212 #endif
1213     esc_name = vim_strsave_shellescape(
1214 # ifdef UNIX
1215 		    fullname != NULL ? fullname :
1216 # endif
1217 		    eap->arg, TRUE, TRUE);
1218     if (esc_name == NULL)
1219 	goto theend;
1220     buflen = STRLEN(tmp_orig) + STRLEN(esc_name) + STRLEN(tmp_new) + 16;
1221     buf = alloc(buflen);
1222     if (buf == NULL)
1223 	goto theend;
1224 
1225 #ifdef UNIX
1226     /* Temporarily chdir to /tmp, to avoid patching files in the current
1227      * directory when the patch file contains more than one patch.  When we
1228      * have our own temp dir use that instead, it will be cleaned up when we
1229      * exit (any .rej files created).  Don't change directory if we can't
1230      * return to the current. */
1231     if (mch_dirname(dirbuf, MAXPATHL) != OK || mch_chdir((char *)dirbuf) != 0)
1232 	dirbuf[0] = NUL;
1233     else
1234     {
1235 # ifdef TEMPDIRNAMES
1236 	if (vim_tempdir != NULL)
1237 	    vim_ignored = mch_chdir((char *)vim_tempdir);
1238 	else
1239 # endif
1240 	    vim_ignored = mch_chdir("/tmp");
1241 	shorten_fnames(TRUE);
1242     }
1243 #endif
1244 
1245 #ifdef FEAT_EVAL
1246     if (*p_pex != NUL)
1247 	/* Use 'patchexpr' to generate the new file. */
1248 	eval_patch(tmp_orig,
1249 # ifdef UNIX
1250 		fullname != NULL ? fullname :
1251 # endif
1252 		eap->arg, tmp_new);
1253     else
1254 #endif
1255     {
1256 	/* Build the patch command and execute it.  Ignore errors.  Switch to
1257 	 * cooked mode to allow the user to respond to prompts. */
1258 	vim_snprintf((char *)buf, buflen, "patch -o %s %s < %s",
1259 						  tmp_new, tmp_orig, esc_name);
1260 	block_autocmds();	/* Avoid ShellCmdPost stuff */
1261 	(void)call_shell(buf, SHELL_FILTER | SHELL_COOKED);
1262 	unblock_autocmds();
1263     }
1264 
1265 #ifdef UNIX
1266     if (dirbuf[0] != NUL)
1267     {
1268 	if (mch_chdir((char *)dirbuf) != 0)
1269 	    emsg(_(e_prev_dir));
1270 	shorten_fnames(TRUE);
1271     }
1272 #endif
1273 
1274     /* patch probably has written over the screen */
1275     redraw_later(CLEAR);
1276 
1277     /* Delete any .orig or .rej file created. */
1278     STRCPY(buf, tmp_new);
1279     STRCAT(buf, ".orig");
1280     mch_remove(buf);
1281     STRCPY(buf, tmp_new);
1282     STRCAT(buf, ".rej");
1283     mch_remove(buf);
1284 
1285     /* Only continue if the output file was created. */
1286     if (mch_stat((char *)tmp_new, &st) < 0 || st.st_size == 0)
1287 	emsg(_("E816: Cannot read patch output"));
1288     else
1289     {
1290 	if (curbuf->b_fname != NULL)
1291 	{
1292 	    newname = vim_strnsave(curbuf->b_fname,
1293 					  (int)(STRLEN(curbuf->b_fname) + 4));
1294 	    if (newname != NULL)
1295 		STRCAT(newname, ".new");
1296 	}
1297 
1298 #ifdef FEAT_GUI
1299 	need_mouse_correct = TRUE;
1300 #endif
1301 	/* don't use a new tab page, each tab page has its own diffs */
1302 	cmdmod.tab = 0;
1303 
1304 	if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
1305 	{
1306 	    /* Pretend it was a ":split fname" command */
1307 	    eap->cmdidx = CMD_split;
1308 	    eap->arg = tmp_new;
1309 	    do_exedit(eap, old_curwin);
1310 
1311 	    /* check that split worked and editing tmp_new */
1312 	    if (curwin != old_curwin && win_valid(old_curwin))
1313 	    {
1314 		/* Set 'diff', 'scrollbind' on and 'wrap' off. */
1315 		diff_win_options(curwin, TRUE);
1316 		diff_win_options(old_curwin, TRUE);
1317 
1318 		if (newname != NULL)
1319 		{
1320 		    /* do a ":file filename.new" on the patched buffer */
1321 		    eap->arg = newname;
1322 		    ex_file(eap);
1323 
1324 		    /* Do filetype detection with the new name. */
1325 		    if (au_has_group((char_u *)"filetypedetect"))
1326 			do_cmdline_cmd((char_u *)":doau filetypedetect BufRead");
1327 		}
1328 	    }
1329 	}
1330     }
1331 
1332 theend:
1333     if (tmp_orig != NULL)
1334 	mch_remove(tmp_orig);
1335     vim_free(tmp_orig);
1336     if (tmp_new != NULL)
1337 	mch_remove(tmp_new);
1338     vim_free(tmp_new);
1339     vim_free(newname);
1340     vim_free(buf);
1341 #ifdef UNIX
1342     vim_free(fullname);
1343 #endif
1344     vim_free(esc_name);
1345 #ifdef FEAT_BROWSE
1346     vim_free(browseFile);
1347     cmdmod.browse = browse_flag;
1348 #endif
1349 }
1350 
1351 /*
1352  * Split the window and edit another file, setting options to show the diffs.
1353  */
1354     void
1355 ex_diffsplit(exarg_T *eap)
1356 {
1357     win_T	*old_curwin = curwin;
1358     bufref_T	old_curbuf;
1359 
1360     set_bufref(&old_curbuf, curbuf);
1361 #ifdef FEAT_GUI
1362     need_mouse_correct = TRUE;
1363 #endif
1364     /* Need to compute w_fraction when no redraw happened yet. */
1365     validate_cursor();
1366     set_fraction(curwin);
1367 
1368     /* don't use a new tab page, each tab page has its own diffs */
1369     cmdmod.tab = 0;
1370 
1371     if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
1372     {
1373 	/* Pretend it was a ":split fname" command */
1374 	eap->cmdidx = CMD_split;
1375 	curwin->w_p_diff = TRUE;
1376 	do_exedit(eap, old_curwin);
1377 
1378 	if (curwin != old_curwin)		/* split must have worked */
1379 	{
1380 	    /* Set 'diff', 'scrollbind' on and 'wrap' off. */
1381 	    diff_win_options(curwin, TRUE);
1382 	    if (win_valid(old_curwin))
1383 	    {
1384 		diff_win_options(old_curwin, TRUE);
1385 
1386 		if (bufref_valid(&old_curbuf))
1387 		    /* Move the cursor position to that of the old window. */
1388 		    curwin->w_cursor.lnum = diff_get_corresponding_line(
1389 			    old_curbuf.br_buf, old_curwin->w_cursor.lnum);
1390 	    }
1391 	    /* Now that lines are folded scroll to show the cursor at the same
1392 	     * relative position. */
1393 	    scroll_to_fraction(curwin, curwin->w_height);
1394 	}
1395     }
1396 }
1397 
1398 /*
1399  * Set options to show diffs for the current window.
1400  */
1401     void
1402 ex_diffthis(exarg_T *eap UNUSED)
1403 {
1404     /* Set 'diff', 'scrollbind' on and 'wrap' off. */
1405     diff_win_options(curwin, TRUE);
1406 }
1407 
1408     static void
1409 set_diff_option(win_T *wp, int value)
1410 {
1411     win_T *old_curwin = curwin;
1412 
1413     curwin = wp;
1414     curbuf = curwin->w_buffer;
1415     ++curbuf_lock;
1416     set_option_value((char_u *)"diff", (long)value, NULL, OPT_LOCAL);
1417     --curbuf_lock;
1418     curwin = old_curwin;
1419     curbuf = curwin->w_buffer;
1420 }
1421 
1422 /*
1423  * Set options in window "wp" for diff mode.
1424  */
1425     void
1426 diff_win_options(
1427     win_T	*wp,
1428     int		addbuf)		/* Add buffer to diff. */
1429 {
1430 # ifdef FEAT_FOLDING
1431     win_T *old_curwin = curwin;
1432 
1433     /* close the manually opened folds */
1434     curwin = wp;
1435     newFoldLevel();
1436     curwin = old_curwin;
1437 # endif
1438 
1439     /* Use 'scrollbind' and 'cursorbind' when available */
1440     if (!wp->w_p_diff)
1441 	wp->w_p_scb_save = wp->w_p_scb;
1442     wp->w_p_scb = TRUE;
1443     if (!wp->w_p_diff)
1444 	wp->w_p_crb_save = wp->w_p_crb;
1445     wp->w_p_crb = TRUE;
1446     if (!wp->w_p_diff)
1447 	wp->w_p_wrap_save = wp->w_p_wrap;
1448     wp->w_p_wrap = FALSE;
1449 # ifdef FEAT_FOLDING
1450     if (!wp->w_p_diff)
1451     {
1452 	if (wp->w_p_diff_saved)
1453 	    free_string_option(wp->w_p_fdm_save);
1454 	wp->w_p_fdm_save = vim_strsave(wp->w_p_fdm);
1455     }
1456     set_string_option_direct_in_win(wp, (char_u *)"fdm", -1, (char_u *)"diff",
1457 						       OPT_LOCAL|OPT_FREE, 0);
1458     if (!wp->w_p_diff)
1459     {
1460 	wp->w_p_fdc_save = wp->w_p_fdc;
1461 	wp->w_p_fen_save = wp->w_p_fen;
1462 	wp->w_p_fdl_save = wp->w_p_fdl;
1463     }
1464     wp->w_p_fdc = diff_foldcolumn;
1465     wp->w_p_fen = TRUE;
1466     wp->w_p_fdl = 0;
1467     foldUpdateAll(wp);
1468     /* make sure topline is not halfway a fold */
1469     changed_window_setting_win(wp);
1470 # endif
1471     if (vim_strchr(p_sbo, 'h') == NULL)
1472 	do_cmdline_cmd((char_u *)"set sbo+=hor");
1473     /* Save the current values, to be restored in ex_diffoff(). */
1474     wp->w_p_diff_saved = TRUE;
1475 
1476     set_diff_option(wp, TRUE);
1477 
1478     if (addbuf)
1479 	diff_buf_add(wp->w_buffer);
1480     redraw_win_later(wp, NOT_VALID);
1481 }
1482 
1483 /*
1484  * Set options not to show diffs.  For the current window or all windows.
1485  * Only in the current tab page.
1486  */
1487     void
1488 ex_diffoff(exarg_T *eap)
1489 {
1490     win_T	*wp;
1491     int		diffwin = FALSE;
1492 
1493     FOR_ALL_WINDOWS(wp)
1494     {
1495 	if (eap->forceit ? wp->w_p_diff : wp == curwin)
1496 	{
1497 	    /* Set 'diff' off. If option values were saved in
1498 	     * diff_win_options(), restore the ones whose settings seem to have
1499 	     * been left over from diff mode.  */
1500 	    set_diff_option(wp, FALSE);
1501 
1502 	    if (wp->w_p_diff_saved)
1503 	    {
1504 
1505 		if (wp->w_p_scb)
1506 		    wp->w_p_scb = wp->w_p_scb_save;
1507 		if (wp->w_p_crb)
1508 		    wp->w_p_crb = wp->w_p_crb_save;
1509 		if (!wp->w_p_wrap)
1510 		    wp->w_p_wrap = wp->w_p_wrap_save;
1511 #ifdef FEAT_FOLDING
1512 		free_string_option(wp->w_p_fdm);
1513 		wp->w_p_fdm = vim_strsave(
1514 		    *wp->w_p_fdm_save ? wp->w_p_fdm_save : (char_u*)"manual");
1515 
1516 		if (wp->w_p_fdc == diff_foldcolumn)
1517 		    wp->w_p_fdc = wp->w_p_fdc_save;
1518 		if (wp->w_p_fdl == 0)
1519 		    wp->w_p_fdl = wp->w_p_fdl_save;
1520 
1521 		/* Only restore 'foldenable' when 'foldmethod' is not
1522 		 * "manual", otherwise we continue to show the diff folds. */
1523 		if (wp->w_p_fen)
1524 		    wp->w_p_fen = foldmethodIsManual(wp) ? FALSE
1525 							 : wp->w_p_fen_save;
1526 
1527 		foldUpdateAll(wp);
1528 #endif
1529 	    }
1530 	    /* remove filler lines */
1531 	    wp->w_topfill = 0;
1532 
1533 	    /* make sure topline is not halfway a fold and cursor is
1534 	     * invalidated */
1535 	    changed_window_setting_win(wp);
1536 
1537 	    /* Note: 'sbo' is not restored, it's a global option. */
1538 	    diff_buf_adjust(wp);
1539 	}
1540 	diffwin |= wp->w_p_diff;
1541     }
1542 
1543     /* Also remove hidden buffers from the list. */
1544     if (eap->forceit)
1545 	diff_buf_clear();
1546 
1547     /* Remove "hor" from from 'scrollopt' if there are no diff windows left. */
1548     if (!diffwin && vim_strchr(p_sbo, 'h') != NULL)
1549 	do_cmdline_cmd((char_u *)"set sbo-=hor");
1550 }
1551 
1552 /*
1553  * Read the diff output and add each entry to the diff list.
1554  */
1555     static void
1556 diff_read(
1557     int		idx_orig,	// idx of original file
1558     int		idx_new,	// idx of new file
1559     diffout_T	*dout)		// diff output
1560 {
1561     FILE	*fd = NULL;
1562     int		line_idx = 0;
1563     diff_T	*dprev = NULL;
1564     diff_T	*dp = curtab->tp_first_diff;
1565     diff_T	*dn, *dpl;
1566     char_u	linebuf[LBUFLEN];   /* only need to hold the diff line */
1567     char_u	*line;
1568     long	off;
1569     int		i;
1570     linenr_T	lnum_orig, lnum_new;
1571     long	count_orig, count_new;
1572     int		notset = TRUE;	    /* block "*dp" not set yet */
1573     enum {
1574 	DIFF_ED,
1575 	DIFF_UNIFIED,
1576 	DIFF_NONE
1577     } diffstyle = DIFF_NONE;
1578 
1579     if (dout->dout_fname == NULL)
1580     {
1581 	diffstyle = DIFF_UNIFIED;
1582     }
1583     else
1584     {
1585 	fd = mch_fopen((char *)dout->dout_fname, "r");
1586 	if (fd == NULL)
1587 	{
1588 	    emsg(_("E98: Cannot read diff output"));
1589 	    return;
1590 	}
1591     }
1592 
1593     for (;;)
1594     {
1595 	if (fd == NULL)
1596 	{
1597 	    if (line_idx >= dout->dout_ga.ga_len)
1598 		break;	    // did last line
1599 	    line = ((char_u **)dout->dout_ga.ga_data)[line_idx++];
1600 	}
1601 	else
1602 	{
1603 	    if (vim_fgets(linebuf, LBUFLEN, fd))
1604 		break;		// end of file
1605 	    line = linebuf;
1606 	}
1607 
1608 	if (diffstyle == DIFF_NONE)
1609 	{
1610 	    // Determine diff style.
1611 	    // ed like diff looks like this:
1612 	    // {first}[,{last}]c{first}[,{last}]
1613 	    // {first}a{first}[,{last}]
1614 	    // {first}[,{last}]d{first}
1615 	    //
1616 	    // unified diff looks like this:
1617 	    // --- file1       2018-03-20 13:23:35.783153140 +0100
1618 	    // +++ file2       2018-03-20 13:23:41.183156066 +0100
1619 	    // @@ -1,3 +1,5 @@
1620 	    if (isdigit(*line))
1621 		diffstyle = DIFF_ED;
1622 	    else if ((STRNCMP(line, "@@ ", 3) == 0))
1623 	       diffstyle = DIFF_UNIFIED;
1624 	    else if ((STRNCMP(line, "--- ", 4) == 0)
1625 		    && (vim_fgets(linebuf, LBUFLEN, fd) == 0)
1626 		    && (STRNCMP(line, "+++ ", 4) == 0)
1627 		    && (vim_fgets(linebuf, LBUFLEN, fd) == 0)
1628 		    && (STRNCMP(line, "@@ ", 3) == 0))
1629 		diffstyle = DIFF_UNIFIED;
1630 	    else
1631 		// Format not recognized yet, skip over this line.  Cygwin diff
1632 		// may put a warning at the start of the file.
1633 		continue;
1634 	}
1635 
1636 	if (diffstyle == DIFF_ED)
1637 	{
1638 	    if (!isdigit(*line))
1639 		continue;	// not the start of a diff block
1640 	    if (parse_diff_ed(line, &lnum_orig, &count_orig,
1641 						&lnum_new, &count_new) == FAIL)
1642 		continue;
1643 	}
1644 	else if (diffstyle == DIFF_UNIFIED)
1645 	{
1646 	    if (STRNCMP(line, "@@ ", 3)  != 0)
1647 		continue;	// not the start of a diff block
1648 	    if (parse_diff_unified(line, &lnum_orig, &count_orig,
1649 						&lnum_new, &count_new) == FAIL)
1650 		continue;
1651 	}
1652 	else
1653 	{
1654 	    emsg(_("E959: Invalid diff format."));
1655 	    break;
1656 	}
1657 
1658 	// Go over blocks before the change, for which orig and new are equal.
1659 	// Copy blocks from orig to new.
1660 	while (dp != NULL
1661 		&& lnum_orig > dp->df_lnum[idx_orig] + dp->df_count[idx_orig])
1662 	{
1663 	    if (notset)
1664 		diff_copy_entry(dprev, dp, idx_orig, idx_new);
1665 	    dprev = dp;
1666 	    dp = dp->df_next;
1667 	    notset = TRUE;
1668 	}
1669 
1670 	if (dp != NULL
1671 		&& lnum_orig <= dp->df_lnum[idx_orig] + dp->df_count[idx_orig]
1672 		&& lnum_orig + count_orig >= dp->df_lnum[idx_orig])
1673 	{
1674 	    // New block overlaps with existing block(s).
1675 	    // First find last block that overlaps.
1676 	    for (dpl = dp; dpl->df_next != NULL; dpl = dpl->df_next)
1677 		if (lnum_orig + count_orig < dpl->df_next->df_lnum[idx_orig])
1678 		    break;
1679 
1680 	    // If the newly found block starts before the old one, set the
1681 	    // start back a number of lines.
1682 	    off = dp->df_lnum[idx_orig] - lnum_orig;
1683 	    if (off > 0)
1684 	    {
1685 		for (i = idx_orig; i < idx_new; ++i)
1686 		    if (curtab->tp_diffbuf[i] != NULL)
1687 			dp->df_lnum[i] -= off;
1688 		dp->df_lnum[idx_new] = lnum_new;
1689 		dp->df_count[idx_new] = count_new;
1690 	    }
1691 	    else if (notset)
1692 	    {
1693 		// new block inside existing one, adjust new block
1694 		dp->df_lnum[idx_new] = lnum_new + off;
1695 		dp->df_count[idx_new] = count_new - off;
1696 	    }
1697 	    else
1698 		// second overlap of new block with existing block
1699 		dp->df_count[idx_new] += count_new - count_orig
1700 		    + dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]
1701 		    - (dp->df_lnum[idx_orig] + dp->df_count[idx_orig]);
1702 
1703 	    // Adjust the size of the block to include all the lines to the
1704 	    // end of the existing block or the new diff, whatever ends last.
1705 	    off = (lnum_orig + count_orig)
1706 			 - (dpl->df_lnum[idx_orig] + dpl->df_count[idx_orig]);
1707 	    if (off < 0)
1708 	    {
1709 		// new change ends in existing block, adjust the end if not
1710 		// done already
1711 		if (notset)
1712 		    dp->df_count[idx_new] += -off;
1713 		off = 0;
1714 	    }
1715 	    for (i = idx_orig; i < idx_new; ++i)
1716 		if (curtab->tp_diffbuf[i] != NULL)
1717 		    dp->df_count[i] = dpl->df_lnum[i] + dpl->df_count[i]
1718 						       - dp->df_lnum[i] + off;
1719 
1720 	    // Delete the diff blocks that have been merged into one.
1721 	    dn = dp->df_next;
1722 	    dp->df_next = dpl->df_next;
1723 	    while (dn != dp->df_next)
1724 	    {
1725 		dpl = dn->df_next;
1726 		vim_free(dn);
1727 		dn = dpl;
1728 	    }
1729 	}
1730 	else
1731 	{
1732 	    // Allocate a new diffblock.
1733 	    dp = diff_alloc_new(curtab, dprev, dp);
1734 	    if (dp == NULL)
1735 		goto done;
1736 
1737 	    dp->df_lnum[idx_orig] = lnum_orig;
1738 	    dp->df_count[idx_orig] = count_orig;
1739 	    dp->df_lnum[idx_new] = lnum_new;
1740 	    dp->df_count[idx_new] = count_new;
1741 
1742 	    // Set values for other buffers, these must be equal to the
1743 	    // original buffer, otherwise there would have been a change
1744 	    // already.
1745 	    for (i = idx_orig + 1; i < idx_new; ++i)
1746 		if (curtab->tp_diffbuf[i] != NULL)
1747 		    diff_copy_entry(dprev, dp, idx_orig, i);
1748 	}
1749 	notset = FALSE;		// "*dp" has been set
1750     }
1751 
1752     // for remaining diff blocks orig and new are equal
1753     while (dp != NULL)
1754     {
1755 	if (notset)
1756 	    diff_copy_entry(dprev, dp, idx_orig, idx_new);
1757 	dprev = dp;
1758 	dp = dp->df_next;
1759 	notset = TRUE;
1760     }
1761 
1762 done:
1763     if (fd != NULL)
1764 	fclose(fd);
1765 }
1766 
1767 /*
1768  * Copy an entry at "dp" from "idx_orig" to "idx_new".
1769  */
1770     static void
1771 diff_copy_entry(
1772     diff_T	*dprev,
1773     diff_T	*dp,
1774     int		idx_orig,
1775     int		idx_new)
1776 {
1777     long	off;
1778 
1779     if (dprev == NULL)
1780 	off = 0;
1781     else
1782 	off = (dprev->df_lnum[idx_orig] + dprev->df_count[idx_orig])
1783 	    - (dprev->df_lnum[idx_new] + dprev->df_count[idx_new]);
1784     dp->df_lnum[idx_new] = dp->df_lnum[idx_orig] - off;
1785     dp->df_count[idx_new] = dp->df_count[idx_orig];
1786 }
1787 
1788 /*
1789  * Clear the list of diffblocks for tab page "tp".
1790  */
1791     void
1792 diff_clear(tabpage_T *tp)
1793 {
1794     diff_T	*p, *next_p;
1795 
1796     for (p = tp->tp_first_diff; p != NULL; p = next_p)
1797     {
1798 	next_p = p->df_next;
1799 	vim_free(p);
1800     }
1801     tp->tp_first_diff = NULL;
1802 }
1803 
1804 /*
1805  * Check diff status for line "lnum" in buffer "buf":
1806  * Returns 0 for nothing special
1807  * Returns -1 for a line that should be highlighted as changed.
1808  * Returns -2 for a line that should be highlighted as added/deleted.
1809  * Returns > 0 for inserting that many filler lines above it (never happens
1810  * when 'diffopt' doesn't contain "filler").
1811  * This should only be used for windows where 'diff' is set.
1812  */
1813     int
1814 diff_check(win_T *wp, linenr_T lnum)
1815 {
1816     int		idx;		/* index in tp_diffbuf[] for this buffer */
1817     diff_T	*dp;
1818     int		maxcount;
1819     int		i;
1820     buf_T	*buf = wp->w_buffer;
1821     int		cmp;
1822 
1823     if (curtab->tp_diff_invalid)
1824 	ex_diffupdate(NULL);		/* update after a big change */
1825 
1826     if (curtab->tp_first_diff == NULL || !wp->w_p_diff)	/* no diffs at all */
1827 	return 0;
1828 
1829     /* safety check: "lnum" must be a buffer line */
1830     if (lnum < 1 || lnum > buf->b_ml.ml_line_count + 1)
1831 	return 0;
1832 
1833     idx = diff_buf_idx(buf);
1834     if (idx == DB_COUNT)
1835 	return 0;		/* no diffs for buffer "buf" */
1836 
1837 #ifdef FEAT_FOLDING
1838     /* A closed fold never has filler lines. */
1839     if (hasFoldingWin(wp, lnum, NULL, NULL, TRUE, NULL))
1840 	return 0;
1841 #endif
1842 
1843     /* search for a change that includes "lnum" in the list of diffblocks. */
1844     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
1845 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
1846 	    break;
1847     if (dp == NULL || lnum < dp->df_lnum[idx])
1848 	return 0;
1849 
1850     if (lnum < dp->df_lnum[idx] + dp->df_count[idx])
1851     {
1852 	int	zero = FALSE;
1853 
1854 	/* Changed or inserted line.  If the other buffers have a count of
1855 	 * zero, the lines were inserted.  If the other buffers have the same
1856 	 * count, check if the lines are identical. */
1857 	cmp = FALSE;
1858 	for (i = 0; i < DB_COUNT; ++i)
1859 	    if (i != idx && curtab->tp_diffbuf[i] != NULL)
1860 	    {
1861 		if (dp->df_count[i] == 0)
1862 		    zero = TRUE;
1863 		else
1864 		{
1865 		    if (dp->df_count[i] != dp->df_count[idx])
1866 			return -1;	    /* nr of lines changed. */
1867 		    cmp = TRUE;
1868 		}
1869 	    }
1870 	if (cmp)
1871 	{
1872 	    /* Compare all lines.  If they are equal the lines were inserted
1873 	     * in some buffers, deleted in others, but not changed. */
1874 	    for (i = 0; i < DB_COUNT; ++i)
1875 		if (i != idx && curtab->tp_diffbuf[i] != NULL
1876 						      && dp->df_count[i] != 0)
1877 		    if (!diff_equal_entry(dp, idx, i))
1878 			return -1;
1879 	}
1880 	/* If there is no buffer with zero lines then there is no difference
1881 	 * any longer.  Happens when making a change (or undo) that removes
1882 	 * the difference.  Can't remove the entry here, we might be halfway
1883 	 * updating the window.  Just report the text as unchanged.  Other
1884 	 * windows might still show the change though. */
1885 	if (zero == FALSE)
1886 	    return 0;
1887 	return -2;
1888     }
1889 
1890     /* If 'diffopt' doesn't contain "filler", return 0. */
1891     if (!(diff_flags & DIFF_FILLER))
1892 	return 0;
1893 
1894     /* Insert filler lines above the line just below the change.  Will return
1895      * 0 when this buf had the max count. */
1896     maxcount = 0;
1897     for (i = 0; i < DB_COUNT; ++i)
1898 	if (curtab->tp_diffbuf[i] != NULL && dp->df_count[i] > maxcount)
1899 	    maxcount = dp->df_count[i];
1900     return maxcount - dp->df_count[idx];
1901 }
1902 
1903 /*
1904  * Compare two entries in diff "*dp" and return TRUE if they are equal.
1905  */
1906     static int
1907 diff_equal_entry(diff_T *dp, int idx1, int idx2)
1908 {
1909     int		i;
1910     char_u	*line;
1911     int		cmp;
1912 
1913     if (dp->df_count[idx1] != dp->df_count[idx2])
1914 	return FALSE;
1915     if (diff_check_sanity(curtab, dp) == FAIL)
1916 	return FALSE;
1917     for (i = 0; i < dp->df_count[idx1]; ++i)
1918     {
1919 	line = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx1],
1920 					       dp->df_lnum[idx1] + i, FALSE));
1921 	if (line == NULL)
1922 	    return FALSE;
1923 	cmp = diff_cmp(line, ml_get_buf(curtab->tp_diffbuf[idx2],
1924 					       dp->df_lnum[idx2] + i, FALSE));
1925 	vim_free(line);
1926 	if (cmp != 0)
1927 	    return FALSE;
1928     }
1929     return TRUE;
1930 }
1931 
1932 /*
1933  * Compare the characters at "p1" and "p2".  If they are equal (possibly
1934  * ignoring case) return TRUE and set "len" to the number of bytes.
1935  */
1936     static int
1937 diff_equal_char(char_u *p1, char_u *p2, int *len)
1938 {
1939     int l  = (*mb_ptr2len)(p1);
1940 
1941     if (l != (*mb_ptr2len)(p2))
1942 	return FALSE;
1943     if (l > 1)
1944     {
1945 	if (STRNCMP(p1, p2, l) != 0
1946 		&& (!enc_utf8
1947 		    || !(diff_flags & DIFF_ICASE)
1948 		    || utf_fold(utf_ptr2char(p1))
1949 						!= utf_fold(utf_ptr2char(p2))))
1950 	    return FALSE;
1951 	*len = l;
1952     }
1953     else
1954     {
1955 	if ((*p1 != *p2)
1956 		&& (!(diff_flags & DIFF_ICASE)
1957 		    || TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2)))
1958 	    return FALSE;
1959 	*len = 1;
1960     }
1961     return TRUE;
1962 }
1963 
1964 /*
1965  * Compare strings "s1" and "s2" according to 'diffopt'.
1966  * Return non-zero when they are different.
1967  */
1968     static int
1969 diff_cmp(char_u *s1, char_u *s2)
1970 {
1971     char_u	*p1, *p2;
1972     int		l;
1973 
1974     if ((diff_flags & DIFF_IBLANK)
1975 	    && (*skipwhite(s1) == NUL || *skipwhite(s2) == NUL))
1976 	return 0;
1977 
1978     if ((diff_flags & (DIFF_ICASE | ALL_WHITE_DIFF)) == 0)
1979 	return STRCMP(s1, s2);
1980     if ((diff_flags & DIFF_ICASE) && !(diff_flags & ALL_WHITE_DIFF))
1981 	return MB_STRICMP(s1, s2);
1982 
1983     p1 = s1;
1984     p2 = s2;
1985 
1986     // Ignore white space changes and possibly ignore case.
1987     while (*p1 != NUL && *p2 != NUL)
1988     {
1989 	if (((diff_flags & DIFF_IWHITE)
1990 		    && VIM_ISWHITE(*p1) && VIM_ISWHITE(*p2))
1991 		|| ((diff_flags & DIFF_IWHITEALL)
1992 		    && (VIM_ISWHITE(*p1) || VIM_ISWHITE(*p2))))
1993 	{
1994 	    p1 = skipwhite(p1);
1995 	    p2 = skipwhite(p2);
1996 	}
1997 	else
1998 	{
1999 	    if (!diff_equal_char(p1, p2, &l))
2000 		break;
2001 	    p1 += l;
2002 	    p2 += l;
2003 	}
2004     }
2005 
2006     // Ignore trailing white space.
2007     p1 = skipwhite(p1);
2008     p2 = skipwhite(p2);
2009     if (*p1 != NUL || *p2 != NUL)
2010 	return 1;
2011     return 0;
2012 }
2013 
2014 /*
2015  * Return the number of filler lines above "lnum".
2016  */
2017     int
2018 diff_check_fill(win_T *wp, linenr_T lnum)
2019 {
2020     int		n;
2021 
2022     /* be quick when there are no filler lines */
2023     if (!(diff_flags & DIFF_FILLER))
2024 	return 0;
2025     n = diff_check(wp, lnum);
2026     if (n <= 0)
2027 	return 0;
2028     return n;
2029 }
2030 
2031 /*
2032  * Set the topline of "towin" to match the position in "fromwin", so that they
2033  * show the same diff'ed lines.
2034  */
2035     void
2036 diff_set_topline(win_T *fromwin, win_T *towin)
2037 {
2038     buf_T	*frombuf = fromwin->w_buffer;
2039     linenr_T	lnum = fromwin->w_topline;
2040     int		fromidx;
2041     int		toidx;
2042     diff_T	*dp;
2043     int		max_count;
2044     int		i;
2045 
2046     fromidx = diff_buf_idx(frombuf);
2047     if (fromidx == DB_COUNT)
2048 	return;		/* safety check */
2049 
2050     if (curtab->tp_diff_invalid)
2051 	ex_diffupdate(NULL);		/* update after a big change */
2052 
2053     towin->w_topfill = 0;
2054 
2055     /* search for a change that includes "lnum" in the list of diffblocks. */
2056     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
2057 	if (lnum <= dp->df_lnum[fromidx] + dp->df_count[fromidx])
2058 	    break;
2059     if (dp == NULL)
2060     {
2061 	/* After last change, compute topline relative to end of file; no
2062 	 * filler lines. */
2063 	towin->w_topline = towin->w_buffer->b_ml.ml_line_count
2064 				       - (frombuf->b_ml.ml_line_count - lnum);
2065     }
2066     else
2067     {
2068 	/* Find index for "towin". */
2069 	toidx = diff_buf_idx(towin->w_buffer);
2070 	if (toidx == DB_COUNT)
2071 	    return;		/* safety check */
2072 
2073 	towin->w_topline = lnum + (dp->df_lnum[toidx] - dp->df_lnum[fromidx]);
2074 	if (lnum >= dp->df_lnum[fromidx])
2075 	{
2076 	    /* Inside a change: compute filler lines. With three or more
2077 	     * buffers we need to know the largest count. */
2078 	    max_count = 0;
2079 	    for (i = 0; i < DB_COUNT; ++i)
2080 		if (curtab->tp_diffbuf[i] != NULL
2081 					       && max_count < dp->df_count[i])
2082 		    max_count = dp->df_count[i];
2083 
2084 	    if (dp->df_count[toidx] == dp->df_count[fromidx])
2085 	    {
2086 		/* same number of lines: use same filler count */
2087 		towin->w_topfill = fromwin->w_topfill;
2088 	    }
2089 	    else if (dp->df_count[toidx] > dp->df_count[fromidx])
2090 	    {
2091 		if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
2092 		{
2093 		    /* more lines in towin and fromwin doesn't show diff
2094 		     * lines, only filler lines */
2095 		    if (max_count - fromwin->w_topfill >= dp->df_count[toidx])
2096 		    {
2097 			/* towin also only shows filler lines */
2098 			towin->w_topline = dp->df_lnum[toidx]
2099 						       + dp->df_count[toidx];
2100 			towin->w_topfill = fromwin->w_topfill;
2101 		    }
2102 		    else
2103 			/* towin still has some diff lines to show */
2104 			towin->w_topline = dp->df_lnum[toidx]
2105 					     + max_count - fromwin->w_topfill;
2106 		}
2107 	    }
2108 	    else if (towin->w_topline >= dp->df_lnum[toidx]
2109 							+ dp->df_count[toidx])
2110 	    {
2111 		/* less lines in towin and no diff lines to show: compute
2112 		 * filler lines */
2113 		towin->w_topline = dp->df_lnum[toidx] + dp->df_count[toidx];
2114 		if (diff_flags & DIFF_FILLER)
2115 		{
2116 		    if (lnum == dp->df_lnum[fromidx] + dp->df_count[fromidx])
2117 			/* fromwin is also out of diff lines */
2118 			towin->w_topfill = fromwin->w_topfill;
2119 		    else
2120 			/* fromwin has some diff lines */
2121 			towin->w_topfill = dp->df_lnum[fromidx]
2122 							   + max_count - lnum;
2123 		}
2124 	    }
2125 	}
2126     }
2127 
2128     /* safety check (if diff info gets outdated strange things may happen) */
2129     towin->w_botfill = FALSE;
2130     if (towin->w_topline > towin->w_buffer->b_ml.ml_line_count)
2131     {
2132 	towin->w_topline = towin->w_buffer->b_ml.ml_line_count;
2133 	towin->w_botfill = TRUE;
2134     }
2135     if (towin->w_topline < 1)
2136     {
2137 	towin->w_topline = 1;
2138 	towin->w_topfill = 0;
2139     }
2140 
2141     /* When w_topline changes need to recompute w_botline and cursor position */
2142     invalidate_botline_win(towin);
2143     changed_line_abv_curs_win(towin);
2144 
2145     check_topfill(towin, FALSE);
2146 #ifdef FEAT_FOLDING
2147     (void)hasFoldingWin(towin, towin->w_topline, &towin->w_topline,
2148 							    NULL, TRUE, NULL);
2149 #endif
2150 }
2151 
2152 /*
2153  * This is called when 'diffopt' is changed.
2154  */
2155     int
2156 diffopt_changed(void)
2157 {
2158     char_u	*p;
2159     int		diff_context_new = 6;
2160     int		diff_flags_new = 0;
2161     int		diff_foldcolumn_new = 2;
2162     long	diff_algorithm_new = 0;
2163     long	diff_indent_heuristic = 0;
2164     tabpage_T	*tp;
2165 
2166     p = p_dip;
2167     while (*p != NUL)
2168     {
2169 	if (STRNCMP(p, "filler", 6) == 0)
2170 	{
2171 	    p += 6;
2172 	    diff_flags_new |= DIFF_FILLER;
2173 	}
2174 	else if (STRNCMP(p, "context:", 8) == 0 && VIM_ISDIGIT(p[8]))
2175 	{
2176 	    p += 8;
2177 	    diff_context_new = getdigits(&p);
2178 	}
2179 	else if (STRNCMP(p, "iblank", 6) == 0)
2180 	{
2181 	    p += 6;
2182 	    diff_flags_new |= DIFF_IBLANK;
2183 	}
2184 	else if (STRNCMP(p, "icase", 5) == 0)
2185 	{
2186 	    p += 5;
2187 	    diff_flags_new |= DIFF_ICASE;
2188 	}
2189 	else if (STRNCMP(p, "iwhiteall", 9) == 0)
2190 	{
2191 	    p += 9;
2192 	    diff_flags_new |= DIFF_IWHITEALL;
2193 	}
2194 	else if (STRNCMP(p, "iwhiteeol", 9) == 0)
2195 	{
2196 	    p += 9;
2197 	    diff_flags_new |= DIFF_IWHITEEOL;
2198 	}
2199 	else if (STRNCMP(p, "iwhite", 6) == 0)
2200 	{
2201 	    p += 6;
2202 	    diff_flags_new |= DIFF_IWHITE;
2203 	}
2204 	else if (STRNCMP(p, "horizontal", 10) == 0)
2205 	{
2206 	    p += 10;
2207 	    diff_flags_new |= DIFF_HORIZONTAL;
2208 	}
2209 	else if (STRNCMP(p, "vertical", 8) == 0)
2210 	{
2211 	    p += 8;
2212 	    diff_flags_new |= DIFF_VERTICAL;
2213 	}
2214 	else if (STRNCMP(p, "foldcolumn:", 11) == 0 && VIM_ISDIGIT(p[11]))
2215 	{
2216 	    p += 11;
2217 	    diff_foldcolumn_new = getdigits(&p);
2218 	}
2219 	else if (STRNCMP(p, "hiddenoff", 9) == 0)
2220 	{
2221 	    p += 9;
2222 	    diff_flags_new |= DIFF_HIDDEN_OFF;
2223 	}
2224 	else if (STRNCMP(p, "indent-heuristic", 16) == 0)
2225 	{
2226 	    p += 16;
2227 	    diff_indent_heuristic = XDF_INDENT_HEURISTIC;
2228 	}
2229 	else if (STRNCMP(p, "internal", 8) == 0)
2230 	{
2231 	    p += 8;
2232 	    diff_flags_new |= DIFF_INTERNAL;
2233 	}
2234 	else if (STRNCMP(p, "algorithm:", 10) == 0)
2235 	{
2236 	    p += 10;
2237 	    if (STRNCMP(p, "myers", 5) == 0)
2238 	    {
2239 		p += 5;
2240 		diff_algorithm_new = 0;
2241 	    }
2242 	    else if (STRNCMP(p, "minimal", 7) == 0)
2243 	    {
2244 		p += 7;
2245 		diff_algorithm_new = XDF_NEED_MINIMAL;
2246 	    }
2247 	    else if (STRNCMP(p, "patience", 8) == 0)
2248 	    {
2249 		p += 8;
2250 		diff_algorithm_new = XDF_PATIENCE_DIFF;
2251 	    }
2252 	    else if (STRNCMP(p, "histogram", 9) == 0)
2253 	    {
2254 		p += 9;
2255 		diff_algorithm_new = XDF_HISTOGRAM_DIFF;
2256 	    }
2257 	    else
2258 		return FAIL;
2259 	}
2260 
2261 	if (*p != ',' && *p != NUL)
2262 	    return FAIL;
2263 	if (*p == ',')
2264 	    ++p;
2265     }
2266 
2267     diff_algorithm_new |= diff_indent_heuristic;
2268 
2269     /* Can't have both "horizontal" and "vertical". */
2270     if ((diff_flags_new & DIFF_HORIZONTAL) && (diff_flags_new & DIFF_VERTICAL))
2271 	return FAIL;
2272 
2273     // If flags were added or removed, or the algorithm was changed, need to
2274     // update the diff.
2275     if (diff_flags != diff_flags_new || diff_algorithm != diff_algorithm_new)
2276 	FOR_ALL_TABPAGES(tp)
2277 	    tp->tp_diff_invalid = TRUE;
2278 
2279     diff_flags = diff_flags_new;
2280     diff_context = diff_context_new == 0 ? 1 : diff_context_new;
2281     diff_foldcolumn = diff_foldcolumn_new;
2282     diff_algorithm = diff_algorithm_new;
2283 
2284     diff_redraw(TRUE);
2285 
2286     /* recompute the scroll binding with the new option value, may
2287      * remove or add filler lines */
2288     check_scrollbind((linenr_T)0, 0L);
2289 
2290     return OK;
2291 }
2292 
2293 /*
2294  * Return TRUE if 'diffopt' contains "horizontal".
2295  */
2296     int
2297 diffopt_horizontal(void)
2298 {
2299     return (diff_flags & DIFF_HORIZONTAL) != 0;
2300 }
2301 
2302 /*
2303  * Return TRUE if 'diffopt' contains "hiddenoff".
2304  */
2305     int
2306 diffopt_hiddenoff(void)
2307 {
2308     return (diff_flags & DIFF_HIDDEN_OFF) != 0;
2309 }
2310 
2311 /*
2312  * Find the difference within a changed line.
2313  * Returns TRUE if the line was added, no other buffer has it.
2314  */
2315     int
2316 diff_find_change(
2317     win_T	*wp,
2318     linenr_T	lnum,
2319     int		*startp,	/* first char of the change */
2320     int		*endp)		/* last char of the change */
2321 {
2322     char_u	*line_org;
2323     char_u	*line_new;
2324     int		i;
2325     int		si_org, si_new;
2326     int		ei_org, ei_new;
2327     diff_T	*dp;
2328     int		idx;
2329     int		off;
2330     int		added = TRUE;
2331     char_u	*p1, *p2;
2332     int		l;
2333 
2334     /* Make a copy of the line, the next ml_get() will invalidate it. */
2335     line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE));
2336     if (line_org == NULL)
2337 	return FALSE;
2338 
2339     idx = diff_buf_idx(wp->w_buffer);
2340     if (idx == DB_COUNT)	/* cannot happen */
2341     {
2342 	vim_free(line_org);
2343 	return FALSE;
2344     }
2345 
2346     /* search for a change that includes "lnum" in the list of diffblocks. */
2347     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
2348 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
2349 	    break;
2350     if (dp == NULL || diff_check_sanity(curtab, dp) == FAIL)
2351     {
2352 	vim_free(line_org);
2353 	return FALSE;
2354     }
2355 
2356     off = lnum - dp->df_lnum[idx];
2357 
2358     for (i = 0; i < DB_COUNT; ++i)
2359 	if (curtab->tp_diffbuf[i] != NULL && i != idx)
2360 	{
2361 	    /* Skip lines that are not in the other change (filler lines). */
2362 	    if (off >= dp->df_count[i])
2363 		continue;
2364 	    added = FALSE;
2365 	    line_new = ml_get_buf(curtab->tp_diffbuf[i],
2366 						 dp->df_lnum[i] + off, FALSE);
2367 
2368 	    /* Search for start of difference */
2369 	    si_org = si_new = 0;
2370 	    while (line_org[si_org] != NUL)
2371 	    {
2372 		if (((diff_flags & DIFF_IWHITE)
2373 			    && VIM_ISWHITE(line_org[si_org])
2374 					      && VIM_ISWHITE(line_new[si_new]))
2375 			|| ((diff_flags & DIFF_IWHITEALL)
2376 			    && (VIM_ISWHITE(line_org[si_org])
2377 					    || VIM_ISWHITE(line_new[si_new]))))
2378 		{
2379 		    si_org = (int)(skipwhite(line_org + si_org) - line_org);
2380 		    si_new = (int)(skipwhite(line_new + si_new) - line_new);
2381 		}
2382 		else
2383 		{
2384 		    if (!diff_equal_char(line_org + si_org, line_new + si_new,
2385 									   &l))
2386 			break;
2387 		    si_org += l;
2388 		    si_new += l;
2389 		}
2390 	    }
2391 	    if (has_mbyte)
2392 	    {
2393 		/* Move back to first byte of character in both lines (may
2394 		 * have "nn^" in line_org and "n^ in line_new). */
2395 		si_org -= (*mb_head_off)(line_org, line_org + si_org);
2396 		si_new -= (*mb_head_off)(line_new, line_new + si_new);
2397 	    }
2398 	    if (*startp > si_org)
2399 		*startp = si_org;
2400 
2401 	    /* Search for end of difference, if any. */
2402 	    if (line_org[si_org] != NUL || line_new[si_new] != NUL)
2403 	    {
2404 		ei_org = (int)STRLEN(line_org);
2405 		ei_new = (int)STRLEN(line_new);
2406 		while (ei_org >= *startp && ei_new >= si_new
2407 						&& ei_org >= 0 && ei_new >= 0)
2408 		{
2409 		    if (((diff_flags & DIFF_IWHITE)
2410 				&& VIM_ISWHITE(line_org[ei_org])
2411 					      && VIM_ISWHITE(line_new[ei_new]))
2412 			    || ((diff_flags & DIFF_IWHITEALL)
2413 				&& (VIM_ISWHITE(line_org[ei_org])
2414 					    || VIM_ISWHITE(line_new[ei_new]))))
2415 		    {
2416 			while (ei_org >= *startp
2417 					     && VIM_ISWHITE(line_org[ei_org]))
2418 			    --ei_org;
2419 			while (ei_new >= si_new
2420 					     && VIM_ISWHITE(line_new[ei_new]))
2421 			    --ei_new;
2422 		    }
2423 		    else
2424 		    {
2425 			p1 = line_org + ei_org;
2426 			p2 = line_new + ei_new;
2427 			p1 -= (*mb_head_off)(line_org, p1);
2428 			p2 -= (*mb_head_off)(line_new, p2);
2429 			if (!diff_equal_char(p1, p2, &l))
2430 			    break;
2431 			ei_org -= l;
2432 			ei_new -= l;
2433 		    }
2434 		}
2435 		if (*endp < ei_org)
2436 		    *endp = ei_org;
2437 	    }
2438 	}
2439 
2440     vim_free(line_org);
2441     return added;
2442 }
2443 
2444 #if defined(FEAT_FOLDING) || defined(PROTO)
2445 /*
2446  * Return TRUE if line "lnum" is not close to a diff block, this line should
2447  * be in a fold.
2448  * Return FALSE if there are no diff blocks at all in this window.
2449  */
2450     int
2451 diff_infold(win_T *wp, linenr_T lnum)
2452 {
2453     int		i;
2454     int		idx = -1;
2455     int		other = FALSE;
2456     diff_T	*dp;
2457 
2458     /* Return if 'diff' isn't set. */
2459     if (!wp->w_p_diff)
2460 	return FALSE;
2461 
2462     for (i = 0; i < DB_COUNT; ++i)
2463     {
2464 	if (curtab->tp_diffbuf[i] == wp->w_buffer)
2465 	    idx = i;
2466 	else if (curtab->tp_diffbuf[i] != NULL)
2467 	    other = TRUE;
2468     }
2469 
2470     /* return here if there are no diffs in the window */
2471     if (idx == -1 || !other)
2472 	return FALSE;
2473 
2474     if (curtab->tp_diff_invalid)
2475 	ex_diffupdate(NULL);		/* update after a big change */
2476 
2477     /* Return if there are no diff blocks.  All lines will be folded. */
2478     if (curtab->tp_first_diff == NULL)
2479 	return TRUE;
2480 
2481     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
2482     {
2483 	/* If this change is below the line there can't be any further match. */
2484 	if (dp->df_lnum[idx] - diff_context > lnum)
2485 	    break;
2486 	/* If this change ends before the line we have a match. */
2487 	if (dp->df_lnum[idx] + dp->df_count[idx] + diff_context > lnum)
2488 	    return FALSE;
2489     }
2490     return TRUE;
2491 }
2492 #endif
2493 
2494 /*
2495  * "dp" and "do" commands.
2496  */
2497     void
2498 nv_diffgetput(int put, long count)
2499 {
2500     exarg_T	ea;
2501     char_u	buf[30];
2502 
2503 #ifdef FEAT_JOB_CHANNEL
2504     if (bt_prompt(curbuf))
2505     {
2506 	vim_beep(BO_OPER);
2507 	return;
2508     }
2509 #endif
2510     if (count == 0)
2511 	ea.arg = (char_u *)"";
2512     else
2513     {
2514 	vim_snprintf((char *)buf, 30, "%ld", count);
2515 	ea.arg = buf;
2516     }
2517     if (put)
2518 	ea.cmdidx = CMD_diffput;
2519     else
2520 	ea.cmdidx = CMD_diffget;
2521     ea.addr_count = 0;
2522     ea.line1 = curwin->w_cursor.lnum;
2523     ea.line2 = curwin->w_cursor.lnum;
2524     ex_diffgetput(&ea);
2525 }
2526 
2527 /*
2528  * ":diffget"
2529  * ":diffput"
2530  */
2531     void
2532 ex_diffgetput(exarg_T *eap)
2533 {
2534     linenr_T	lnum;
2535     int		count;
2536     linenr_T	off = 0;
2537     diff_T	*dp;
2538     diff_T	*dprev;
2539     diff_T	*dfree;
2540     int		idx_cur;
2541     int		idx_other;
2542     int		idx_from;
2543     int		idx_to;
2544     int		i;
2545     int		added;
2546     char_u	*p;
2547     aco_save_T	aco;
2548     buf_T	*buf;
2549     int		start_skip, end_skip;
2550     int		new_count;
2551     int		buf_empty;
2552     int		found_not_ma = FALSE;
2553 
2554     /* Find the current buffer in the list of diff buffers. */
2555     idx_cur = diff_buf_idx(curbuf);
2556     if (idx_cur == DB_COUNT)
2557     {
2558 	emsg(_("E99: Current buffer is not in diff mode"));
2559 	return;
2560     }
2561 
2562     if (*eap->arg == NUL)
2563     {
2564 	/* No argument: Find the other buffer in the list of diff buffers. */
2565 	for (idx_other = 0; idx_other < DB_COUNT; ++idx_other)
2566 	    if (curtab->tp_diffbuf[idx_other] != curbuf
2567 		    && curtab->tp_diffbuf[idx_other] != NULL)
2568 	    {
2569 		if (eap->cmdidx != CMD_diffput
2570 				     || curtab->tp_diffbuf[idx_other]->b_p_ma)
2571 		    break;
2572 		found_not_ma = TRUE;
2573 	    }
2574 	if (idx_other == DB_COUNT)
2575 	{
2576 	    if (found_not_ma)
2577 		emsg(_("E793: No other buffer in diff mode is modifiable"));
2578 	    else
2579 		emsg(_("E100: No other buffer in diff mode"));
2580 	    return;
2581 	}
2582 
2583 	/* Check that there isn't a third buffer in the list */
2584 	for (i = idx_other + 1; i < DB_COUNT; ++i)
2585 	    if (curtab->tp_diffbuf[i] != curbuf
2586 		    && curtab->tp_diffbuf[i] != NULL
2587 		    && (eap->cmdidx != CMD_diffput || curtab->tp_diffbuf[i]->b_p_ma))
2588 	    {
2589 		emsg(_("E101: More than two buffers in diff mode, don't know which one to use"));
2590 		return;
2591 	    }
2592     }
2593     else
2594     {
2595 	/* Buffer number or pattern given.  Ignore trailing white space. */
2596 	p = eap->arg + STRLEN(eap->arg);
2597 	while (p > eap->arg && VIM_ISWHITE(p[-1]))
2598 	    --p;
2599 	for (i = 0; vim_isdigit(eap->arg[i]) && eap->arg + i < p; ++i)
2600 	    ;
2601 	if (eap->arg + i == p)	    /* digits only */
2602 	    i = atol((char *)eap->arg);
2603 	else
2604 	{
2605 	    i = buflist_findpat(eap->arg, p, FALSE, TRUE, FALSE);
2606 	    if (i < 0)
2607 		return;		/* error message already given */
2608 	}
2609 	buf = buflist_findnr(i);
2610 	if (buf == NULL)
2611 	{
2612 	    semsg(_("E102: Can't find buffer \"%s\""), eap->arg);
2613 	    return;
2614 	}
2615 	if (buf == curbuf)
2616 	    return;		/* nothing to do */
2617 	idx_other = diff_buf_idx(buf);
2618 	if (idx_other == DB_COUNT)
2619 	{
2620 	    semsg(_("E103: Buffer \"%s\" is not in diff mode"), eap->arg);
2621 	    return;
2622 	}
2623     }
2624 
2625     diff_busy = TRUE;
2626 
2627     /* When no range given include the line above or below the cursor. */
2628     if (eap->addr_count == 0)
2629     {
2630 	/* Make it possible that ":diffget" on the last line gets line below
2631 	 * the cursor line when there is no difference above the cursor. */
2632 	if (eap->cmdidx == CMD_diffget
2633 		&& eap->line1 == curbuf->b_ml.ml_line_count
2634 		&& diff_check(curwin, eap->line1) == 0
2635 		&& (eap->line1 == 1 || diff_check(curwin, eap->line1 - 1) == 0))
2636 	    ++eap->line2;
2637 	else if (eap->line1 > 0)
2638 	    --eap->line1;
2639     }
2640 
2641     if (eap->cmdidx == CMD_diffget)
2642     {
2643 	idx_from = idx_other;
2644 	idx_to = idx_cur;
2645     }
2646     else
2647     {
2648 	idx_from = idx_cur;
2649 	idx_to = idx_other;
2650 	/* Need to make the other buffer the current buffer to be able to make
2651 	 * changes in it. */
2652 	/* set curwin/curbuf to buf and save a few things */
2653 	aucmd_prepbuf(&aco, curtab->tp_diffbuf[idx_other]);
2654     }
2655 
2656     /* May give the warning for a changed buffer here, which can trigger the
2657      * FileChangedRO autocommand, which may do nasty things and mess
2658      * everything up. */
2659     if (!curbuf->b_changed)
2660     {
2661 	change_warning(0);
2662 	if (diff_buf_idx(curbuf) != idx_to)
2663 	{
2664 	    emsg(_("E787: Buffer changed unexpectedly"));
2665 	    goto theend;
2666 	}
2667     }
2668 
2669     dprev = NULL;
2670     for (dp = curtab->tp_first_diff; dp != NULL; )
2671     {
2672 	if (dp->df_lnum[idx_cur] > eap->line2 + off)
2673 	    break;	/* past the range that was specified */
2674 
2675 	dfree = NULL;
2676 	lnum = dp->df_lnum[idx_to];
2677 	count = dp->df_count[idx_to];
2678 	if (dp->df_lnum[idx_cur] + dp->df_count[idx_cur] > eap->line1 + off
2679 		&& u_save(lnum - 1, lnum + count) != FAIL)
2680 	{
2681 	    /* Inside the specified range and saving for undo worked. */
2682 	    start_skip = 0;
2683 	    end_skip = 0;
2684 	    if (eap->addr_count > 0)
2685 	    {
2686 		/* A range was specified: check if lines need to be skipped. */
2687 		start_skip = eap->line1 + off - dp->df_lnum[idx_cur];
2688 		if (start_skip > 0)
2689 		{
2690 		    /* range starts below start of current diff block */
2691 		    if (start_skip > count)
2692 		    {
2693 			lnum += count;
2694 			count = 0;
2695 		    }
2696 		    else
2697 		    {
2698 			count -= start_skip;
2699 			lnum += start_skip;
2700 		    }
2701 		}
2702 		else
2703 		    start_skip = 0;
2704 
2705 		end_skip = dp->df_lnum[idx_cur] + dp->df_count[idx_cur] - 1
2706 							 - (eap->line2 + off);
2707 		if (end_skip > 0)
2708 		{
2709 		    /* range ends above end of current/from diff block */
2710 		    if (idx_cur == idx_from)	/* :diffput */
2711 		    {
2712 			i = dp->df_count[idx_cur] - start_skip - end_skip;
2713 			if (count > i)
2714 			    count = i;
2715 		    }
2716 		    else			/* :diffget */
2717 		    {
2718 			count -= end_skip;
2719 			end_skip = dp->df_count[idx_from] - start_skip - count;
2720 			if (end_skip < 0)
2721 			    end_skip = 0;
2722 		    }
2723 		}
2724 		else
2725 		    end_skip = 0;
2726 	    }
2727 
2728 	    buf_empty = BUFEMPTY();
2729 	    added = 0;
2730 	    for (i = 0; i < count; ++i)
2731 	    {
2732 		/* remember deleting the last line of the buffer */
2733 		buf_empty = curbuf->b_ml.ml_line_count == 1;
2734 		ml_delete(lnum, FALSE);
2735 		--added;
2736 	    }
2737 	    for (i = 0; i < dp->df_count[idx_from] - start_skip - end_skip; ++i)
2738 	    {
2739 		linenr_T nr;
2740 
2741 		nr = dp->df_lnum[idx_from] + start_skip + i;
2742 		if (nr > curtab->tp_diffbuf[idx_from]->b_ml.ml_line_count)
2743 		    break;
2744 		p = vim_strsave(ml_get_buf(curtab->tp_diffbuf[idx_from],
2745 								  nr, FALSE));
2746 		if (p != NULL)
2747 		{
2748 		    ml_append(lnum + i - 1, p, 0, FALSE);
2749 		    vim_free(p);
2750 		    ++added;
2751 		    if (buf_empty && curbuf->b_ml.ml_line_count == 2)
2752 		    {
2753 			/* Added the first line into an empty buffer, need to
2754 			 * delete the dummy empty line. */
2755 			buf_empty = FALSE;
2756 			ml_delete((linenr_T)2, FALSE);
2757 		    }
2758 		}
2759 	    }
2760 	    new_count = dp->df_count[idx_to] + added;
2761 	    dp->df_count[idx_to] = new_count;
2762 
2763 	    if (start_skip == 0 && end_skip == 0)
2764 	    {
2765 		/* Check if there are any other buffers and if the diff is
2766 		 * equal in them. */
2767 		for (i = 0; i < DB_COUNT; ++i)
2768 		    if (curtab->tp_diffbuf[i] != NULL && i != idx_from
2769 								&& i != idx_to
2770 			    && !diff_equal_entry(dp, idx_from, i))
2771 			break;
2772 		if (i == DB_COUNT)
2773 		{
2774 		    /* delete the diff entry, the buffers are now equal here */
2775 		    dfree = dp;
2776 		    dp = dp->df_next;
2777 		    if (dprev == NULL)
2778 			curtab->tp_first_diff = dp;
2779 		    else
2780 			dprev->df_next = dp;
2781 		}
2782 	    }
2783 
2784 	    /* Adjust marks.  This will change the following entries! */
2785 	    if (added != 0)
2786 	    {
2787 		mark_adjust(lnum, lnum + count - 1, (long)MAXLNUM, (long)added);
2788 		if (curwin->w_cursor.lnum >= lnum)
2789 		{
2790 		    /* Adjust the cursor position if it's in/after the changed
2791 		     * lines. */
2792 		    if (curwin->w_cursor.lnum >= lnum + count)
2793 			curwin->w_cursor.lnum += added;
2794 		    else if (added < 0)
2795 			curwin->w_cursor.lnum = lnum;
2796 		}
2797 	    }
2798 	    changed_lines(lnum, 0, lnum + count, (long)added);
2799 
2800 	    if (dfree != NULL)
2801 	    {
2802 		/* Diff is deleted, update folds in other windows. */
2803 #ifdef FEAT_FOLDING
2804 		diff_fold_update(dfree, idx_to);
2805 #endif
2806 		vim_free(dfree);
2807 	    }
2808 	    else
2809 		/* mark_adjust() may have changed the count in a wrong way */
2810 		dp->df_count[idx_to] = new_count;
2811 
2812 	    /* When changing the current buffer, keep track of line numbers */
2813 	    if (idx_cur == idx_to)
2814 		off += added;
2815 	}
2816 
2817 	/* If before the range or not deleted, go to next diff. */
2818 	if (dfree == NULL)
2819 	{
2820 	    dprev = dp;
2821 	    dp = dp->df_next;
2822 	}
2823     }
2824 
2825     /* restore curwin/curbuf and a few other things */
2826     if (eap->cmdidx != CMD_diffget)
2827     {
2828 	/* Syncing undo only works for the current buffer, but we change
2829 	 * another buffer.  Sync undo if the command was typed.  This isn't
2830 	 * 100% right when ":diffput" is used in a function or mapping. */
2831 	if (KeyTyped)
2832 	    u_sync(FALSE);
2833 	aucmd_restbuf(&aco);
2834     }
2835 
2836 theend:
2837     diff_busy = FALSE;
2838     if (diff_need_update)
2839 	ex_diffupdate(NULL);
2840 
2841     // Check that the cursor is on a valid character and update its
2842     // position.  When there were filler lines the topline has become
2843     // invalid.
2844     check_cursor();
2845     changed_line_abv_curs();
2846 
2847     if (diff_need_update)
2848 	// redraw already done by ex_diffupdate()
2849 	diff_need_update = FALSE;
2850     else
2851     {
2852 	// Also need to redraw the other buffers.
2853 	diff_redraw(FALSE);
2854 	apply_autocmds(EVENT_DIFFUPDATED, NULL, NULL, FALSE, curbuf);
2855     }
2856 }
2857 
2858 #ifdef FEAT_FOLDING
2859 /*
2860  * Update folds for all diff buffers for entry "dp".
2861  * Skip buffer with index "skip_idx".
2862  * When there are no diffs, all folds are removed.
2863  */
2864     static void
2865 diff_fold_update(diff_T *dp, int skip_idx)
2866 {
2867     int		i;
2868     win_T	*wp;
2869 
2870     FOR_ALL_WINDOWS(wp)
2871 	for (i = 0; i < DB_COUNT; ++i)
2872 	    if (curtab->tp_diffbuf[i] == wp->w_buffer && i != skip_idx)
2873 		foldUpdate(wp, dp->df_lnum[i],
2874 					    dp->df_lnum[i] + dp->df_count[i]);
2875 }
2876 #endif
2877 
2878 /*
2879  * Return TRUE if buffer "buf" is in diff-mode.
2880  */
2881     int
2882 diff_mode_buf(buf_T *buf)
2883 {
2884     tabpage_T	*tp;
2885 
2886     FOR_ALL_TABPAGES(tp)
2887 	if (diff_buf_idx_tp(buf, tp) != DB_COUNT)
2888 	    return TRUE;
2889     return FALSE;
2890 }
2891 
2892 /*
2893  * Move "count" times in direction "dir" to the next diff block.
2894  * Return FAIL if there isn't such a diff block.
2895  */
2896     int
2897 diff_move_to(int dir, long count)
2898 {
2899     int		idx;
2900     linenr_T	lnum = curwin->w_cursor.lnum;
2901     diff_T	*dp;
2902 
2903     idx = diff_buf_idx(curbuf);
2904     if (idx == DB_COUNT || curtab->tp_first_diff == NULL)
2905 	return FAIL;
2906 
2907     if (curtab->tp_diff_invalid)
2908 	ex_diffupdate(NULL);		/* update after a big change */
2909 
2910     if (curtab->tp_first_diff == NULL)		/* no diffs today */
2911 	return FAIL;
2912 
2913     while (--count >= 0)
2914     {
2915 	/* Check if already before first diff. */
2916 	if (dir == BACKWARD && lnum <= curtab->tp_first_diff->df_lnum[idx])
2917 	    break;
2918 
2919 	for (dp = curtab->tp_first_diff; ; dp = dp->df_next)
2920 	{
2921 	    if (dp == NULL)
2922 		break;
2923 	    if ((dir == FORWARD && lnum < dp->df_lnum[idx])
2924 		    || (dir == BACKWARD
2925 			&& (dp->df_next == NULL
2926 			    || lnum <= dp->df_next->df_lnum[idx])))
2927 	    {
2928 		lnum = dp->df_lnum[idx];
2929 		break;
2930 	    }
2931 	}
2932     }
2933 
2934     /* don't end up past the end of the file */
2935     if (lnum > curbuf->b_ml.ml_line_count)
2936 	lnum = curbuf->b_ml.ml_line_count;
2937 
2938     /* When the cursor didn't move at all we fail. */
2939     if (lnum == curwin->w_cursor.lnum)
2940 	return FAIL;
2941 
2942     setpcmark();
2943     curwin->w_cursor.lnum = lnum;
2944     curwin->w_cursor.col = 0;
2945 
2946     return OK;
2947 }
2948 
2949 /*
2950  * Return the line number in the current window that is closest to "lnum1" in
2951  * "buf1" in diff mode.
2952  */
2953     static linenr_T
2954 diff_get_corresponding_line_int(
2955     buf_T	*buf1,
2956     linenr_T	lnum1)
2957 {
2958     int		idx1;
2959     int		idx2;
2960     diff_T	*dp;
2961     int		baseline = 0;
2962 
2963     idx1 = diff_buf_idx(buf1);
2964     idx2 = diff_buf_idx(curbuf);
2965     if (idx1 == DB_COUNT || idx2 == DB_COUNT || curtab->tp_first_diff == NULL)
2966 	return lnum1;
2967 
2968     if (curtab->tp_diff_invalid)
2969 	ex_diffupdate(NULL);		/* update after a big change */
2970 
2971     if (curtab->tp_first_diff == NULL)		/* no diffs today */
2972 	return lnum1;
2973 
2974     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
2975     {
2976 	if (dp->df_lnum[idx1] > lnum1)
2977 	    return lnum1 - baseline;
2978 	if ((dp->df_lnum[idx1] + dp->df_count[idx1]) > lnum1)
2979 	{
2980 	    /* Inside the diffblock */
2981 	    baseline = lnum1 - dp->df_lnum[idx1];
2982 	    if (baseline > dp->df_count[idx2])
2983 		baseline = dp->df_count[idx2];
2984 
2985 	    return dp->df_lnum[idx2] + baseline;
2986 	}
2987 	if (    (dp->df_lnum[idx1] == lnum1)
2988 	     && (dp->df_count[idx1] == 0)
2989 	     && (dp->df_lnum[idx2] <= curwin->w_cursor.lnum)
2990 	     && ((dp->df_lnum[idx2] + dp->df_count[idx2])
2991 						      > curwin->w_cursor.lnum))
2992 	    /*
2993 	     * Special case: if the cursor is just after a zero-count
2994 	     * block (i.e. all filler) and the target cursor is already
2995 	     * inside the corresponding block, leave the target cursor
2996 	     * unmoved. This makes repeated CTRL-W W operations work
2997 	     * as expected.
2998 	     */
2999 	    return curwin->w_cursor.lnum;
3000 	baseline = (dp->df_lnum[idx1] + dp->df_count[idx1])
3001 				   - (dp->df_lnum[idx2] + dp->df_count[idx2]);
3002     }
3003 
3004     /* If we get here then the cursor is after the last diff */
3005     return lnum1 - baseline;
3006 }
3007 
3008 /*
3009  * Return the line number in the current window that is closest to "lnum1" in
3010  * "buf1" in diff mode.  Checks the line number to be valid.
3011  */
3012     linenr_T
3013 diff_get_corresponding_line(buf_T *buf1, linenr_T lnum1)
3014 {
3015     linenr_T lnum = diff_get_corresponding_line_int(buf1, lnum1);
3016 
3017     /* don't end up past the end of the file */
3018     if (lnum > curbuf->b_ml.ml_line_count)
3019 	return curbuf->b_ml.ml_line_count;
3020     return lnum;
3021 }
3022 
3023 /*
3024  * For line "lnum" in the current window find the equivalent lnum in window
3025  * "wp", compensating for inserted/deleted lines.
3026  */
3027     linenr_T
3028 diff_lnum_win(linenr_T lnum, win_T *wp)
3029 {
3030     diff_T	*dp;
3031     int		idx;
3032     int		i;
3033     linenr_T	n;
3034 
3035     idx = diff_buf_idx(curbuf);
3036     if (idx == DB_COUNT)		/* safety check */
3037 	return (linenr_T)0;
3038 
3039     if (curtab->tp_diff_invalid)
3040 	ex_diffupdate(NULL);		/* update after a big change */
3041 
3042     /* search for a change that includes "lnum" in the list of diffblocks. */
3043     for (dp = curtab->tp_first_diff; dp != NULL; dp = dp->df_next)
3044 	if (lnum <= dp->df_lnum[idx] + dp->df_count[idx])
3045 	    break;
3046 
3047     /* When after the last change, compute relative to the last line number. */
3048     if (dp == NULL)
3049 	return wp->w_buffer->b_ml.ml_line_count
3050 					- (curbuf->b_ml.ml_line_count - lnum);
3051 
3052     /* Find index for "wp". */
3053     i = diff_buf_idx(wp->w_buffer);
3054     if (i == DB_COUNT)			/* safety check */
3055 	return (linenr_T)0;
3056 
3057     n = lnum + (dp->df_lnum[i] - dp->df_lnum[idx]);
3058     if (n > dp->df_lnum[i] + dp->df_count[i])
3059 	n = dp->df_lnum[i] + dp->df_count[i];
3060     return n;
3061 }
3062 
3063 /*
3064  * Handle an ED style diff line.
3065  * Return FAIL if the line does not contain diff info.
3066  */
3067     static int
3068 parse_diff_ed(
3069 	char_u	    *line,
3070 	linenr_T    *lnum_orig,
3071 	long	    *count_orig,
3072 	linenr_T    *lnum_new,
3073 	long	    *count_new)
3074 {
3075     char_u *p;
3076     long    f1, l1, f2, l2;
3077     int	    difftype;
3078 
3079     // The line must be one of three formats:
3080     // change: {first}[,{last}]c{first}[,{last}]
3081     // append: {first}a{first}[,{last}]
3082     // delete: {first}[,{last}]d{first}
3083     p = line;
3084     f1 = getdigits(&p);
3085     if (*p == ',')
3086     {
3087 	++p;
3088 	l1 = getdigits(&p);
3089     }
3090     else
3091 	l1 = f1;
3092     if (*p != 'a' && *p != 'c' && *p != 'd')
3093 	return FAIL;		// invalid diff format
3094     difftype = *p++;
3095     f2 = getdigits(&p);
3096     if (*p == ',')
3097     {
3098 	++p;
3099 	l2 = getdigits(&p);
3100     }
3101     else
3102 	l2 = f2;
3103     if (l1 < f1 || l2 < f2)
3104 	return FAIL;
3105 
3106     if (difftype == 'a')
3107     {
3108 	*lnum_orig = f1 + 1;
3109 	*count_orig = 0;
3110     }
3111     else
3112     {
3113 	*lnum_orig = f1;
3114 	*count_orig = l1 - f1 + 1;
3115     }
3116     if (difftype == 'd')
3117     {
3118 	*lnum_new = f2 + 1;
3119 	*count_new = 0;
3120     }
3121     else
3122     {
3123 	*lnum_new = f2;
3124 	*count_new = l2 - f2 + 1;
3125     }
3126     return OK;
3127 }
3128 
3129 /*
3130  * Parses unified diff with zero(!) context lines.
3131  * Return FAIL if there is no diff information in "line".
3132  */
3133     static int
3134 parse_diff_unified(
3135 	char_u	    *line,
3136 	linenr_T    *lnum_orig,
3137 	long	    *count_orig,
3138 	linenr_T    *lnum_new,
3139 	long	    *count_new)
3140 {
3141     char_u *p;
3142     long    oldline, oldcount, newline, newcount;
3143 
3144     // Parse unified diff hunk header:
3145     // @@ -oldline,oldcount +newline,newcount @@
3146     p = line;
3147     if (*p++ == '@' && *p++ == '@' && *p++ == ' ' && *p++ == '-')
3148     {
3149 	oldline = getdigits(&p);
3150 	if (*p == ',')
3151 	{
3152 	    ++p;
3153 	    oldcount = getdigits(&p);
3154 	}
3155 	else
3156 	    oldcount = 1;
3157 	if (*p++ == ' ' && *p++ == '+')
3158 	{
3159 	    newline = getdigits(&p);
3160 	    if (*p == ',')
3161 	    {
3162 		++p;
3163 		newcount = getdigits(&p);
3164 	    }
3165 	    else
3166 		newcount = 1;
3167 	}
3168 	else
3169 	    return FAIL;	// invalid diff format
3170 
3171 	if (oldcount == 0)
3172 	    oldline += 1;
3173 	if (newcount == 0)
3174 	    newline += 1;
3175 	if (newline == 0)
3176 	    newline = 1;
3177 
3178 	*lnum_orig = oldline;
3179 	*count_orig = oldcount;
3180 	*lnum_new = newline;
3181 	*count_new = newcount;
3182 
3183 	return OK;
3184     }
3185 
3186     return FAIL;
3187 }
3188 
3189 /*
3190  * Callback function for the xdl_diff() function.
3191  * Stores the diff output in a grow array.
3192  */
3193     static int
3194 xdiff_out(void *priv, mmbuffer_t *mb, int nbuf)
3195 {
3196     diffout_T	*dout = (diffout_T *)priv;
3197     char_u	*p;
3198 
3199     // The header line always comes by itself, text lines in at least two
3200     // parts.  We drop the text part.
3201     if (nbuf > 1)
3202 	return 0;
3203 
3204     // sanity check
3205     if (STRNCMP(mb[0].ptr, "@@ ", 3)  != 0)
3206 	return 0;
3207 
3208     if (ga_grow(&dout->dout_ga, 1) == FAIL)
3209 	return -1;
3210     p = vim_strnsave((char_u *)mb[0].ptr, mb[0].size);
3211     if (p == NULL)
3212 	return -1;
3213     ((char_u **)dout->dout_ga.ga_data)[dout->dout_ga.ga_len++] = p;
3214     return 0;
3215 }
3216 
3217 #endif	/* FEAT_DIFF */
3218