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