This source file includes following definitions.
- TAB_SKIP
- fill_by_space
- rewrite_backup_content
- open_temp
- dview_fdopen
- dview_ffree
- dview_ftemp
- dview_fopen
- dview_fgets
- dview_fseek
- dview_freset
- dview_fwrite
- dview_ftrunc
- dview_fclose
- dview_popen
- dview_pclose
- dview_get_byte
- dview_get_utf
- dview_str_utf8_offset_to_pos
- scan_deci
- scan_line
- scan_diff
- dff_execute
- printer_for
- dff_reparse
- lcsubstr
- hdiff_multi
- hdiff_scan
- is_inside
- cvt_cpy
- cvt_ncpy
- cvt_mget
- cvt_mgeta
- cvt_fget
- cc_free_elt
- printer
- redo_diff
- destroy_hdiff
- get_digits
- get_line_numbers
- calc_nwidth
- find_prev_hunk
- find_next_hunk
- get_current_hunk
- dview_remove_hunk
- dview_add_hunk
- dview_replace_hunk
- do_merge_hunk
- dview_compute_split
- dview_compute_areas
- dview_reread
- dview_set_codeset
- dview_select_encoding
- dview_load_options
- dview_save_options
- dview_diff_options
- dview_init
- dview_fini
- dview_display_file
- dview_status
- dview_redo
- dview_update
- dview_edit
- dview_goto_cmd
- dview_labels
- dview_save
- dview_do_save
- dview_ok_to_exit
- dview_execute_cmd
- dview_handle_key
- dview_callback
- dview_mouse_callback
- dview_dialog_callback
- dview_get_title
- diff_view
- dview_diff_cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 #include <config.h>
31
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/wait.h>
39
40 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/color.h"
43 #include "lib/tty/key.h"
44 #include "lib/skin.h"
45 #include "lib/vfs/vfs.h"
46 #include "lib/util.h"
47 #include "lib/widget.h"
48 #include "lib/strutil.h"
49 #include "lib/strescape.h"
50 #ifdef HAVE_CHARSET
51 #include "lib/charsets.h"
52 #endif
53 #include "lib/event.h"
54
55 #include "src/filemanager/cmd.h"
56 #include "src/filemanager/panel.h"
57 #include "src/filemanager/layout.h"
58
59 #include "src/execute.h"
60 #include "src/keymap.h"
61 #include "src/setup.h"
62 #include "src/history.h"
63 #ifdef HAVE_CHARSET
64 #include "src/selcodepage.h"
65 #endif
66
67 #include "ydiff.h"
68 #include "internal.h"
69
70
71
72
73
74 #define FILE_READ_BUF 4096
75 #define FILE_FLAG_TEMP (1 << 0)
76
77 #define ADD_CH '+'
78 #define DEL_CH '-'
79 #define CHG_CH '*'
80 #define EQU_CH ' '
81
82 #define HDIFF_ENABLE 1
83 #define HDIFF_MINCTX 5
84 #define HDIFF_DEPTH 10
85
86 #define FILE_DIRTY(fs) \
87 do \
88 { \
89 (fs)->pos = 0; \
90 (fs)->len = 0; \
91 } \
92 while (0)
93
94
95
96 typedef enum
97 {
98 FROM_LEFT_TO_RIGHT,
99 FROM_RIGHT_TO_LEFT
100 } action_direction_t;
101
102
103
104
105
106
107
108
109
110 static inline int
111 TAB_SKIP (int ts, int pos)
112 {
113 if (ts > 0 && ts < 9)
114 return ts - pos % ts;
115 else
116 return 8 - pos % 8;
117 }
118
119
120
121
122
123
124
125
126
127
128 static void
129 fill_by_space (char *buf, size_t n, gboolean zero_terminate)
130 {
131 memset (buf, ' ', n);
132 if (zero_terminate)
133 buf[n] = '\0';
134 }
135
136
137
138 static gboolean
139 rewrite_backup_content (const vfs_path_t * from_file_name_vpath, const char *to_file_name)
140 {
141 FILE *backup_fd;
142 char *contents;
143 gsize length;
144 const char *from_file_name;
145
146 from_file_name = vfs_path_get_last_path_str (from_file_name_vpath);
147 if (!g_file_get_contents (from_file_name, &contents, &length, NULL))
148 return FALSE;
149
150 backup_fd = fopen (to_file_name, "w");
151 if (backup_fd == NULL)
152 {
153 g_free (contents);
154 return FALSE;
155 }
156
157 length = fwrite ((const void *) contents, length, 1, backup_fd);
158
159 fflush (backup_fd);
160 fclose (backup_fd);
161 g_free (contents);
162 return TRUE;
163 }
164
165
166
167
168
169
170
171
172
173
174
175 static int
176 open_temp (void **name)
177 {
178 int fd;
179 vfs_path_t *diff_file_name = NULL;
180
181 fd = mc_mkstemps (&diff_file_name, "mcdiff", NULL);
182 if (fd == -1)
183 {
184 message (D_ERROR, MSG_ERROR,
185 _("Cannot create temporary diff file\n%s"), unix_error_string (errno));
186 return -1;
187 }
188
189 *name = vfs_path_free (diff_file_name, FALSE);
190 return fd;
191 }
192
193
194
195
196
197
198
199
200
201
202 static FBUF *
203 dview_fdopen (int fd)
204 {
205 FBUF *fs;
206
207 if (fd < 0)
208 return NULL;
209
210 fs = g_try_malloc (sizeof (FBUF));
211 if (fs == NULL)
212 return NULL;
213
214 fs->buf = g_try_malloc (FILE_READ_BUF);
215 if (fs->buf == NULL)
216 {
217 g_free (fs);
218 return NULL;
219 }
220
221 fs->fd = fd;
222 FILE_DIRTY (fs);
223 fs->flags = 0;
224 fs->data = NULL;
225
226 return fs;
227 }
228
229
230
231
232
233
234
235
236
237
238 static int
239 dview_ffree (FBUF * fs)
240 {
241 int rv = 0;
242
243 if ((fs->flags & FILE_FLAG_TEMP) != 0)
244 {
245 rv = unlink (fs->data);
246 g_free (fs->data);
247 }
248 g_free (fs->buf);
249 g_free (fs);
250 return rv;
251 }
252
253
254
255
256
257
258
259
260
261 static FBUF *
262 dview_ftemp (void)
263 {
264 int fd;
265 FBUF *fs;
266
267 fs = dview_fdopen (0);
268 if (fs == NULL)
269 return NULL;
270
271 fd = open_temp (&fs->data);
272 if (fd < 0)
273 {
274 dview_ffree (fs);
275 return NULL;
276 }
277
278 fs->fd = fd;
279 fs->flags = FILE_FLAG_TEMP;
280 return fs;
281 }
282
283
284
285
286
287
288
289
290
291
292
293
294 static FBUF *
295 dview_fopen (const char *filename, int flags)
296 {
297 int fd;
298 FBUF *fs;
299
300 fs = dview_fdopen (0);
301 if (fs == NULL)
302 return NULL;
303
304 fd = open (filename, flags);
305 if (fd < 0)
306 {
307 dview_ffree (fs);
308 return NULL;
309 }
310
311 fs->fd = fd;
312 return fs;
313 }
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 static size_t
330 dview_fgets (char *buf, size_t size, FBUF * fs)
331 {
332 size_t j = 0;
333
334 do
335 {
336 int i;
337 gboolean stop = FALSE;
338
339 for (i = fs->pos; j < size && i < fs->len && !stop; i++, j++)
340 {
341 buf[j] = fs->buf[i];
342 if (buf[j] == '\n')
343 stop = TRUE;
344 }
345 fs->pos = i;
346
347 if (j == size || stop)
348 break;
349
350 fs->pos = 0;
351 fs->len = read (fs->fd, fs->buf, FILE_READ_BUF);
352 }
353 while (fs->len > 0);
354
355 return j;
356 }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 static off_t
372 dview_fseek (FBUF * fs, off_t off, int whence)
373 {
374 off_t rv;
375
376 if (fs->len != 0 && whence != SEEK_END)
377 {
378 rv = lseek (fs->fd, 0, SEEK_CUR);
379 if (rv != -1)
380 {
381 if (whence == SEEK_CUR)
382 {
383 whence = SEEK_SET;
384 off += rv - fs->len + fs->pos;
385 }
386 if (off - rv >= -fs->len && off - rv <= 0)
387 {
388 fs->pos = fs->len + off - rv;
389 return off;
390 }
391 }
392 }
393
394 rv = lseek (fs->fd, off, whence);
395 if (rv != -1)
396 FILE_DIRTY (fs);
397 return rv;
398 }
399
400
401
402
403
404
405
406
407
408
409
410 static off_t
411 dview_freset (FBUF * fs)
412 {
413 off_t rv;
414
415 rv = lseek (fs->fd, 0, SEEK_SET);
416 if (rv != -1)
417 FILE_DIRTY (fs);
418 return rv;
419 }
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434 static ssize_t
435 dview_fwrite (FBUF * fs, const char *buf, size_t size)
436 {
437 ssize_t rv;
438
439 rv = write (fs->fd, buf, size);
440 if (rv >= 0)
441 FILE_DIRTY (fs);
442 return rv;
443 }
444
445
446
447
448
449
450
451
452
453
454
455
456 static off_t
457 dview_ftrunc (FBUF * fs)
458 {
459 off_t off;
460
461 off = lseek (fs->fd, 0, SEEK_CUR);
462 if (off != -1)
463 {
464 int rv;
465
466 rv = ftruncate (fs->fd, off);
467 if (rv != 0)
468 off = -1;
469 else
470 FILE_DIRTY (fs);
471 }
472 return off;
473 }
474
475
476
477
478
479
480
481
482
483
484
485 static int
486 dview_fclose (FBUF * fs)
487 {
488 int rv = -1;
489
490 if (fs != NULL)
491 {
492 rv = close (fs->fd);
493 dview_ffree (fs);
494 }
495
496 return rv;
497 }
498
499
500
501
502
503
504
505
506
507
508
509
510 static FBUF *
511 dview_popen (const char *cmd, int flags)
512 {
513 FILE *f;
514 FBUF *fs;
515 const char *type = NULL;
516
517 if (flags == O_RDONLY)
518 type = "r";
519 else if (flags == O_WRONLY)
520 type = "w";
521
522 if (type == NULL)
523 return NULL;
524
525 fs = dview_fdopen (0);
526 if (fs == NULL)
527 return NULL;
528
529 f = popen (cmd, type);
530 if (f == NULL)
531 {
532 dview_ffree (fs);
533 return NULL;
534 }
535
536 fs->fd = fileno (f);
537 fs->data = f;
538 return fs;
539 }
540
541
542
543
544
545
546
547
548
549
550 static int
551 dview_pclose (FBUF * fs)
552 {
553 int rv = -1;
554
555 if (fs != NULL)
556 {
557 rv = pclose (fs->data);
558 dview_ffree (fs);
559 }
560
561 return rv;
562 }
563
564
565
566
567
568
569
570
571
572
573
574 static gboolean
575 dview_get_byte (const char *str, int *ch)
576 {
577 if (str == NULL)
578 return FALSE;
579
580 *ch = (unsigned char) (*str);
581 return TRUE;
582 }
583
584
585
586 #ifdef HAVE_CHARSET
587
588
589
590
591
592
593
594
595
596 static gboolean
597 dview_get_utf (const char *str, int *ch, int *ch_length)
598 {
599 if (str == NULL)
600 return FALSE;
601
602 *ch = g_utf8_get_char_validated (str, -1);
603
604 if (*ch < 0)
605 {
606 *ch = (unsigned char) (*str);
607 *ch_length = 1;
608 }
609 else
610 {
611 char *next_ch;
612
613
614 next_ch = g_utf8_next_char (str);
615 *ch_length = next_ch - str;
616 }
617
618 return TRUE;
619 }
620
621
622
623 static int
624 dview_str_utf8_offset_to_pos (const char *text, size_t length)
625 {
626 ptrdiff_t result;
627
628 if (text == NULL || text[0] == '\0')
629 return length;
630
631 if (g_utf8_validate (text, -1, NULL))
632 result = g_utf8_offset_to_pointer (text, length) - text;
633 else
634 {
635 gunichar uni;
636 char *tmpbuf, *buffer;
637
638 buffer = tmpbuf = g_strdup (text);
639 while (tmpbuf[0] != '\0')
640 {
641 uni = g_utf8_get_char_validated (tmpbuf, -1);
642 if ((uni != (gunichar) (-1)) && (uni != (gunichar) (-2)))
643 tmpbuf = g_utf8_next_char (tmpbuf);
644 else
645 {
646 tmpbuf[0] = '.';
647 tmpbuf++;
648 }
649 }
650 result = g_utf8_offset_to_pointer (tmpbuf, length) - tmpbuf;
651 g_free (buffer);
652 }
653 return MAX (length, (size_t) result);
654 }
655 #endif
656
657
658
659
660
661
662
663
664
665
666
667
668
669 static int
670 scan_deci (const char **str, int *n)
671 {
672 const char *p = *str;
673 char *q;
674
675 errno = 0;
676 *n = strtol (p, &q, 10);
677 if (errno != 0 || p == q)
678 return -1;
679 *str = q;
680 return 0;
681 }
682
683
684
685
686
687
688
689
690
691
692
693 static int
694 scan_line (const char *p, GArray * ops)
695 {
696 DIFFCMD op;
697
698 int f1, f2;
699 int t1, t2;
700 int cmd;
701 gboolean range = FALSE;
702
703
704
705
706
707
708
709
710 if (scan_deci (&p, &f1) != 0 || f1 < 0)
711 return -1;
712
713 f2 = f1;
714 if (*p == ',')
715 {
716 p++;
717 if (scan_deci (&p, &f2) != 0 || f2 < f1)
718 return -1;
719
720 range = TRUE;
721 }
722
723 cmd = *p++;
724 if (cmd == 'a')
725 {
726 if (range)
727 return -1;
728 }
729 else if (cmd != 'c' && cmd != 'd')
730 return -1;
731
732 if (scan_deci (&p, &t1) != 0 || t1 < 0)
733 return -1;
734
735 t2 = t1;
736 range = FALSE;
737 if (*p == ',')
738 {
739 p++;
740 if (scan_deci (&p, &t2) != 0 || t2 < t1)
741 return -1;
742
743 range = TRUE;
744 }
745
746 if (cmd == 'd' && range)
747 return -1;
748
749 op.a[0][0] = f1;
750 op.a[0][1] = f2;
751 op.cmd = cmd;
752 op.a[1][0] = t1;
753 op.a[1][1] = t2;
754 g_array_append_val (ops, op);
755 return 0;
756 }
757
758
759
760
761
762
763
764
765
766
767
768 static int
769 scan_diff (FBUF * f, GArray * ops)
770 {
771 int sz;
772 char buf[BUFSIZ];
773
774 while ((sz = dview_fgets (buf, sizeof (buf) - 1, f)) != 0)
775 {
776 if (isdigit (buf[0]))
777 {
778 if (buf[sz - 1] != '\n')
779 return -1;
780
781 buf[sz] = '\0';
782 if (scan_line (buf, ops) != 0)
783 return -1;
784 }
785 else
786 while (buf[sz - 1] != '\n' && (sz = dview_fgets (buf, sizeof (buf), f)) != 0)
787 ;
788 }
789
790 return ops->len;
791 }
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807 static int
808 dff_execute (const char *args, const char *extra, const char *file1, const char *file2,
809 GArray * ops)
810 {
811 static const char *opt =
812 " --old-group-format='%df%(f=l?:,%dl)d%dE\n'"
813 " --new-group-format='%dea%dF%(F=L?:,%dL)\n'"
814 " --changed-group-format='%df%(f=l?:,%dl)c%dF%(F=L?:,%dL)\n'"
815 " --unchanged-group-format=''";
816
817 int rv;
818 FBUF *f;
819 char *cmd;
820 int code;
821 char *file1_esc, *file2_esc;
822
823
824 file1_esc = strutils_shell_escape (file1);
825 file2_esc = strutils_shell_escape (file2);
826 cmd = g_strdup_printf ("diff %s %s %s %s %s", args, extra, opt, file1_esc, file2_esc);
827 g_free (file1_esc);
828 g_free (file2_esc);
829
830 if (cmd == NULL)
831 return -1;
832
833 f = dview_popen (cmd, O_RDONLY);
834 g_free (cmd);
835
836 if (f == NULL)
837 return -1;
838
839 rv = scan_diff (f, ops);
840 code = dview_pclose (f);
841
842 if (rv < 0 || code == -1 || !WIFEXITED (code) || WEXITSTATUS (code) == 2)
843 rv = -1;
844
845 return rv;
846 }
847
848
849
850 static gboolean
851 printer_for (char ch, DFUNC printer, void *ctx, FBUF * f, int *line, off_t * off)
852 {
853 size_t sz;
854 char buf[BUFSIZ];
855
856 sz = dview_fgets (buf, sizeof (buf), f);
857 if (sz == 0)
858 return FALSE;
859
860 (*line)++;
861 printer (ctx, ch, *line, *off, sz, buf);
862 *off += sz;
863
864 while (buf[sz - 1] != '\n')
865 {
866 sz = dview_fgets (buf, sizeof (buf), f);
867 if (sz == 0)
868 {
869 printer (ctx, 0, 0, 0, 1, "\n");
870 break;
871 }
872
873 printer (ctx, 0, 0, 0, sz, buf);
874 *off += sz;
875 }
876
877 return TRUE;
878 }
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894 static int
895 dff_reparse (diff_place_t ord, const char *filename, const GArray * ops, DFUNC printer, void *ctx)
896 {
897 size_t i;
898 FBUF *f;
899 int line = 0;
900 off_t off = 0;
901 const DIFFCMD *op;
902 diff_place_t eff;
903 int add_cmd, del_cmd;
904
905 f = dview_fopen (filename, O_RDONLY);
906 if (f == NULL)
907 return -1;
908
909 if (ord != DIFF_LEFT)
910 ord = DIFF_RIGHT;
911 eff = ord;
912
913 if (ord != DIFF_LEFT)
914 {
915 add_cmd = 'd';
916 del_cmd = 'a';
917 }
918 else
919 {
920 add_cmd = 'a';
921 del_cmd = 'd';
922 }
923 #define F1 a[eff][0]
924 #define F2 a[eff][1]
925 #define T1 a[ ord^1 ][0]
926 #define T2 a[ ord^1 ][1]
927 for (i = 0; i < ops->len; i++)
928 {
929 int n;
930
931 op = &g_array_index (ops, DIFFCMD, i);
932
933 n = op->F1;
934 if (op->cmd != add_cmd)
935 n--;
936
937 while (line < n && printer_for (EQU_CH, printer, ctx, f, &line, &off))
938 ;
939
940 if (line != n)
941 goto err;
942
943 if (op->cmd == add_cmd)
944 for (n = op->T2 - op->T1 + 1; n != 0; n--)
945 printer (ctx, DEL_CH, 0, 0, 1, "\n");
946
947 if (op->cmd == del_cmd)
948 {
949 for (n = op->F2 - op->F1 + 1;
950 n != 0 && printer_for (ADD_CH, printer, ctx, f, &line, &off); n--)
951 ;
952
953 if (n != 0)
954 goto err;
955 }
956
957 if (op->cmd == 'c')
958 {
959 for (n = op->F2 - op->F1 + 1;
960 n != 0 && printer_for (CHG_CH, printer, ctx, f, &line, &off); n--)
961 ;
962
963 if (n != 0)
964 goto err;
965
966 for (n = op->T2 - op->T1 - (op->F2 - op->F1); n > 0; n--)
967 printer (ctx, CHG_CH, 0, 0, 1, "\n");
968 }
969 }
970 #undef T2
971 #undef T1
972 #undef F2
973 #undef F1
974
975 while (printer_for (EQU_CH, printer, ctx, f, &line, &off))
976 ;
977
978 dview_fclose (f);
979 return 0;
980
981 err:
982 dview_fclose (f);
983 return -1;
984 }
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003 static int
1004 lcsubstr (const char *s, int m, const char *t, int n, GArray * ret, int min)
1005 {
1006 int i, j;
1007 int *Lprev, *Lcurr;
1008 int z = 0;
1009
1010 if (m < min || n < min)
1011 {
1012
1013 return 0;
1014 }
1015
1016 Lprev = g_try_new0 (int, n + 1);
1017 if (Lprev == NULL)
1018 return -1;
1019
1020 Lcurr = g_try_new0 (int, n + 1);
1021 if (Lcurr == NULL)
1022 {
1023 g_free (Lprev);
1024 return -1;
1025 }
1026
1027 for (i = 0; i < m; i++)
1028 {
1029 int *L;
1030
1031 L = Lprev;
1032 Lprev = Lcurr;
1033 Lcurr = L;
1034 #ifdef USE_MEMSET_IN_LCS
1035 memset (Lcurr, 0, (n + 1) * sizeof (*Lcurr));
1036 #endif
1037 for (j = 0; j < n; j++)
1038 {
1039 #ifndef USE_MEMSET_IN_LCS
1040 Lcurr[j + 1] = 0;
1041 #endif
1042 if (s[i] == t[j])
1043 {
1044 int v;
1045
1046 v = Lprev[j] + 1;
1047 Lcurr[j + 1] = v;
1048 if (z < v)
1049 {
1050 z = v;
1051 g_array_set_size (ret, 0);
1052 }
1053 if (z == v && z >= min)
1054 {
1055 int off0, off1;
1056 size_t k;
1057
1058 off0 = i - z + 1;
1059 off1 = j - z + 1;
1060
1061 for (k = 0; k < ret->len; k++)
1062 {
1063 PAIR *p = (PAIR *) g_array_index (ret, PAIR, k);
1064 if ((*p)[0] == off0 || (*p)[1] >= off1)
1065 break;
1066 }
1067 if (k == ret->len)
1068 {
1069 PAIR p2;
1070
1071 p2[0] = off0;
1072 p2[1] = off1;
1073 g_array_append_val (ret, p2);
1074 }
1075 }
1076 }
1077 }
1078 }
1079
1080 g_free (Lcurr);
1081 g_free (Lprev);
1082 return z;
1083 }
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100 static gboolean
1101 hdiff_multi (const char *s, const char *t, const BRACKET bracket, int min, GArray * hdiff,
1102 unsigned int depth)
1103 {
1104 BRACKET p;
1105
1106 if (depth-- != 0)
1107 {
1108 GArray *ret;
1109 BRACKET b;
1110 int len;
1111
1112 ret = g_array_new (FALSE, TRUE, sizeof (PAIR));
1113
1114 len = lcsubstr (s + bracket[DIFF_LEFT].off, bracket[DIFF_LEFT].len,
1115 t + bracket[DIFF_RIGHT].off, bracket[DIFF_RIGHT].len, ret, min);
1116 if (ret->len != 0)
1117 {
1118 size_t k = 0;
1119 const PAIR *data = (const PAIR *) &g_array_index (ret, PAIR, 0);
1120 const PAIR *data2;
1121
1122 b[DIFF_LEFT].off = bracket[DIFF_LEFT].off;
1123 b[DIFF_LEFT].len = (*data)[0];
1124 b[DIFF_RIGHT].off = bracket[DIFF_RIGHT].off;
1125 b[DIFF_RIGHT].len = (*data)[1];
1126 if (!hdiff_multi (s, t, b, min, hdiff, depth))
1127 return FALSE;
1128
1129 for (k = 0; k < ret->len - 1; k++)
1130 {
1131 data = (const PAIR *) &g_array_index (ret, PAIR, k);
1132 data2 = (const PAIR *) &g_array_index (ret, PAIR, k + 1);
1133 b[DIFF_LEFT].off = bracket[DIFF_LEFT].off + (*data)[0] + len;
1134 b[DIFF_LEFT].len = (*data2)[0] - (*data)[0] - len;
1135 b[DIFF_RIGHT].off = bracket[DIFF_RIGHT].off + (*data)[1] + len;
1136 b[DIFF_RIGHT].len = (*data2)[1] - (*data)[1] - len;
1137 if (!hdiff_multi (s, t, b, min, hdiff, depth))
1138 return FALSE;
1139 }
1140 data = (const PAIR *) &g_array_index (ret, PAIR, k);
1141 b[DIFF_LEFT].off = bracket[DIFF_LEFT].off + (*data)[0] + len;
1142 b[DIFF_LEFT].len = bracket[DIFF_LEFT].len - (*data)[0] - len;
1143 b[DIFF_RIGHT].off = bracket[DIFF_RIGHT].off + (*data)[1] + len;
1144 b[DIFF_RIGHT].len = bracket[DIFF_RIGHT].len - (*data)[1] - len;
1145 if (!hdiff_multi (s, t, b, min, hdiff, depth))
1146 return FALSE;
1147
1148 g_array_free (ret, TRUE);
1149 return TRUE;
1150 }
1151 }
1152
1153 p[DIFF_LEFT].off = bracket[DIFF_LEFT].off;
1154 p[DIFF_LEFT].len = bracket[DIFF_LEFT].len;
1155 p[DIFF_RIGHT].off = bracket[DIFF_RIGHT].off;
1156 p[DIFF_RIGHT].len = bracket[DIFF_RIGHT].len;
1157 g_array_append_val (hdiff, p);
1158
1159 return TRUE;
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178 static gboolean
1179 hdiff_scan (const char *s, int m, const char *t, int n, int min, GArray * hdiff, unsigned int depth)
1180 {
1181 int i;
1182 BRACKET b;
1183
1184
1185 for (i = 0; i < m && i < n && s[i] == t[i]; i++)
1186 ;
1187 for (; m > i && n > i && s[m - 1] == t[n - 1]; m--, n--)
1188 ;
1189
1190 b[DIFF_LEFT].off = i;
1191 b[DIFF_LEFT].len = m - i;
1192 b[DIFF_RIGHT].off = i;
1193 b[DIFF_RIGHT].len = n - i;
1194
1195
1196 return hdiff_multi (s, t, b, min, hdiff, depth);
1197 }
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213 static gboolean
1214 is_inside (int k, GArray * hdiff, diff_place_t ord)
1215 {
1216 size_t i;
1217 BRACKET *b;
1218
1219 for (i = 0; i < hdiff->len; i++)
1220 {
1221 int start, end;
1222
1223 b = &g_array_index (hdiff, BRACKET, i);
1224 start = (*b)[ord].off;
1225 end = start + (*b)[ord].len;
1226 if (k >= start && k < end)
1227 return TRUE;
1228 }
1229 return FALSE;
1230 }
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247 static int
1248 cvt_cpy (char *dst, const char *src, size_t srcsize, int base, int ts)
1249 {
1250 int i;
1251
1252 for (i = 0; srcsize != 0; i++, src++, dst++, srcsize--)
1253 {
1254 *dst = *src;
1255 if (*src == '\t')
1256 {
1257 int j;
1258
1259 j = TAB_SKIP (ts, i + base);
1260 i += j - 1;
1261 fill_by_space (dst, j, FALSE);
1262 dst += j - 1;
1263 }
1264 }
1265 return i + base;
1266 }
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287 static int
1288 cvt_ncpy (char *dst, int dstsize, const char **_src, size_t srcsize, int base, int ts)
1289 {
1290 int i;
1291 const char *src = *_src;
1292
1293 for (i = 0; i < dstsize && srcsize != 0; i++, src++, dst++, srcsize--)
1294 {
1295 *dst = *src;
1296 if (*src == '\t')
1297 {
1298 int j;
1299
1300 j = TAB_SKIP (ts, i + base);
1301 if (j > dstsize - i)
1302 j = dstsize - i;
1303 i += j - 1;
1304 fill_by_space (dst, j, FALSE);
1305 dst += j - 1;
1306 }
1307 }
1308 *_src = src;
1309 return i + base;
1310 }
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328 static int
1329 cvt_mget (const char *src, size_t srcsize, char *dst, int dstsize, int skip, int ts,
1330 gboolean show_cr)
1331 {
1332 int sz = 0;
1333
1334 if (src != NULL)
1335 {
1336 int i;
1337 char *tmp = dst;
1338 const int base = 0;
1339
1340 for (i = 0; dstsize != 0 && srcsize != 0 && *src != '\n'; i++, src++, srcsize--)
1341 {
1342 if (*src == '\t')
1343 {
1344 int j;
1345
1346 j = TAB_SKIP (ts, i + base);
1347 i += j - 1;
1348 while (j-- > 0)
1349 {
1350 if (skip > 0)
1351 skip--;
1352 else if (dstsize != 0)
1353 {
1354 dstsize--;
1355 *dst++ = ' ';
1356 }
1357 }
1358 }
1359 else if (src[0] == '\r' && (srcsize == 1 || src[1] == '\n'))
1360 {
1361 if (skip == 0 && show_cr)
1362 {
1363 if (dstsize > 1)
1364 {
1365 dstsize -= 2;
1366 *dst++ = '^';
1367 *dst++ = 'M';
1368 }
1369 else
1370 {
1371 dstsize--;
1372 *dst++ = '.';
1373 }
1374 }
1375 break;
1376 }
1377 else if (skip > 0)
1378 {
1379 #ifdef HAVE_CHARSET
1380 int ch = 0;
1381 int ch_length = 1;
1382
1383 (void) dview_get_utf (src, &ch, &ch_length);
1384
1385 if (ch_length > 1)
1386 skip += ch_length - 1;
1387 #endif
1388
1389 skip--;
1390 }
1391 else
1392 {
1393 dstsize--;
1394 *dst++ = *src;
1395 }
1396 }
1397 sz = dst - tmp;
1398 }
1399
1400 fill_by_space (dst, dstsize, TRUE);
1401
1402 return sz;
1403 }
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424 static int
1425 cvt_mgeta (const char *src, size_t srcsize, char *dst, int dstsize, int skip, int ts,
1426 gboolean show_cr, GArray * hdiff, diff_place_t ord, char *att)
1427 {
1428 int sz = 0;
1429
1430 if (src != NULL)
1431 {
1432 int i, k;
1433 char *tmp = dst;
1434 const int base = 0;
1435
1436 for (i = 0, k = 0; dstsize != 0 && srcsize != 0 && *src != '\n'; i++, k++, src++, srcsize--)
1437 {
1438 if (*src == '\t')
1439 {
1440 int j;
1441
1442 j = TAB_SKIP (ts, i + base);
1443 i += j - 1;
1444 while (j-- > 0)
1445 {
1446 if (skip != 0)
1447 skip--;
1448 else if (dstsize != 0)
1449 {
1450 dstsize--;
1451 *att++ = is_inside (k, hdiff, ord);
1452 *dst++ = ' ';
1453 }
1454 }
1455 }
1456 else if (src[0] == '\r' && (srcsize == 1 || src[1] == '\n'))
1457 {
1458 if (skip == 0 && show_cr)
1459 {
1460 if (dstsize > 1)
1461 {
1462 dstsize -= 2;
1463 *att++ = is_inside (k, hdiff, ord);
1464 *dst++ = '^';
1465 *att++ = is_inside (k, hdiff, ord);
1466 *dst++ = 'M';
1467 }
1468 else
1469 {
1470 dstsize--;
1471 *att++ = is_inside (k, hdiff, ord);
1472 *dst++ = '.';
1473 }
1474 }
1475 break;
1476 }
1477 else if (skip != 0)
1478 {
1479 #ifdef HAVE_CHARSET
1480 int ch = 0;
1481 int ch_length = 1;
1482
1483 (void) dview_get_utf (src, &ch, &ch_length);
1484 if (ch_length > 1)
1485 skip += ch_length - 1;
1486 #endif
1487
1488 skip--;
1489 }
1490 else
1491 {
1492 dstsize--;
1493 *att++ = is_inside (k, hdiff, ord);
1494 *dst++ = *src;
1495 }
1496 }
1497 sz = dst - tmp;
1498 }
1499
1500 memset (att, '\0', dstsize);
1501 fill_by_space (dst, dstsize, TRUE);
1502
1503 return sz;
1504 }
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522 static int
1523 cvt_fget (FBUF * f, off_t off, char *dst, size_t dstsize, int skip, int ts, gboolean show_cr)
1524 {
1525 int base = 0;
1526 int old_base = base;
1527 size_t amount = dstsize;
1528 size_t useful, offset;
1529 size_t i;
1530 size_t sz;
1531 int lastch = '\0';
1532 const char *q = NULL;
1533 char tmp[BUFSIZ];
1534 char cvt[BUFSIZ];
1535
1536 if (sizeof (tmp) < amount || sizeof (tmp) <= dstsize || sizeof (cvt) < 8 * amount)
1537 {
1538
1539 fill_by_space (dst, dstsize, TRUE);
1540 return 0;
1541 }
1542
1543 dview_fseek (f, off, SEEK_SET);
1544
1545 while (skip > base)
1546 {
1547 old_base = base;
1548 sz = dview_fgets (tmp, amount, f);
1549 if (sz == 0)
1550 break;
1551
1552 base = cvt_cpy (cvt, tmp, sz, old_base, ts);
1553 if (cvt[base - old_base - 1] == '\n')
1554 {
1555 q = &cvt[base - old_base - 1];
1556 base = old_base + q - cvt + 1;
1557 break;
1558 }
1559 }
1560
1561 if (base < skip)
1562 {
1563 fill_by_space (dst, dstsize, TRUE);
1564 return 0;
1565 }
1566
1567 useful = base - skip;
1568 offset = skip - old_base;
1569
1570 if (useful <= dstsize)
1571 {
1572 if (useful != 0)
1573 memmove (dst, cvt + offset, useful);
1574
1575 if (q == NULL)
1576 {
1577 sz = dview_fgets (tmp, dstsize - useful + 1, f);
1578 if (sz != 0)
1579 {
1580 const char *ptr = tmp;
1581
1582 useful += cvt_ncpy (dst + useful, dstsize - useful, &ptr, sz, base, ts) - base;
1583 if (ptr < tmp + sz)
1584 lastch = *ptr;
1585 }
1586 }
1587 sz = useful;
1588 }
1589 else
1590 {
1591 memmove (dst, cvt + offset, dstsize);
1592 sz = dstsize;
1593 lastch = cvt[offset + dstsize];
1594 }
1595
1596 dst[sz] = lastch;
1597 for (i = 0; i < sz && dst[i] != '\n'; i++)
1598 if (dst[i] == '\r' && dst[i + 1] == '\n')
1599 {
1600 if (show_cr)
1601 {
1602 if (i + 1 < dstsize)
1603 {
1604 dst[i++] = '^';
1605 dst[i++] = 'M';
1606 }
1607 else
1608 dst[i++] = '*';
1609 }
1610 break;
1611 }
1612
1613 fill_by_space (dst, dstsize, TRUE);
1614
1615 return sz;
1616 }
1617
1618
1619
1620
1621 static void
1622 cc_free_elt (gpointer elt)
1623 {
1624 DIFFLN *p = (DIFFLN *) elt;
1625
1626 if (p != NULL)
1627 g_free (p->p);
1628 }
1629
1630
1631
1632 static int
1633 printer (void *ctx, int ch, int line, off_t off, size_t sz, const char *str)
1634 {
1635 GArray *a = ((PRINTER_CTX *) ctx)->a;
1636 DSRC dsrc = ((PRINTER_CTX *) ctx)->dsrc;
1637
1638 if (ch != 0)
1639 {
1640 DIFFLN p;
1641
1642 p.p = NULL;
1643 p.ch = ch;
1644 p.line = line;
1645 p.u.off = off;
1646 if (dsrc == DATA_SRC_MEM && line != 0)
1647 {
1648 if (sz != 0 && str[sz - 1] == '\n')
1649 sz--;
1650 if (sz > 0)
1651 p.p = g_strndup (str, sz);
1652 p.u.len = sz;
1653 }
1654 g_array_append_val (a, p);
1655 }
1656 else if (dsrc == DATA_SRC_MEM)
1657 {
1658 DIFFLN *p;
1659
1660 p = &g_array_index (a, DIFFLN, a->len - 1);
1661 if (sz != 0 && str[sz - 1] == '\n')
1662 sz--;
1663 if (sz != 0)
1664 {
1665 size_t new_size;
1666 char *q;
1667
1668 new_size = p->u.len + sz;
1669 q = g_realloc (p->p, new_size);
1670 memcpy (q + p->u.len, str, sz);
1671 p->p = q;
1672 }
1673 p->u.len += sz;
1674 }
1675 if (dsrc == DATA_SRC_TMP && (line != 0 || ch == 0))
1676 {
1677 FBUF *f = ((PRINTER_CTX *) ctx)->f;
1678 dview_fwrite (f, str, sz);
1679 }
1680 return 0;
1681 }
1682
1683
1684
1685 static int
1686 redo_diff (WDiff * dview)
1687 {
1688 FBUF *const *f = dview->f;
1689 PRINTER_CTX ctx;
1690 GArray *ops;
1691 int ndiff;
1692 int rv = 0;
1693 char extra[BUF_MEDIUM];
1694
1695 extra[0] = '\0';
1696 if (dview->opt.quality == 2)
1697 strcat (extra, " -d");
1698 if (dview->opt.quality == 1)
1699 strcat (extra, " --speed-large-files");
1700 if (dview->opt.strip_trailing_cr)
1701 strcat (extra, " --strip-trailing-cr");
1702 if (dview->opt.ignore_tab_expansion)
1703 strcat (extra, " -E");
1704 if (dview->opt.ignore_space_change)
1705 strcat (extra, " -b");
1706 if (dview->opt.ignore_all_space)
1707 strcat (extra, " -w");
1708 if (dview->opt.ignore_case)
1709 strcat (extra, " -i");
1710
1711 if (dview->dsrc != DATA_SRC_MEM)
1712 {
1713 dview_freset (f[DIFF_LEFT]);
1714 dview_freset (f[DIFF_RIGHT]);
1715 }
1716
1717 ops = g_array_new (FALSE, FALSE, sizeof (DIFFCMD));
1718 ndiff = dff_execute (dview->args, extra, dview->file[DIFF_LEFT], dview->file[DIFF_RIGHT], ops);
1719 if (ndiff < 0)
1720 {
1721 if (ops != NULL)
1722 g_array_free (ops, TRUE);
1723 return -1;
1724 }
1725
1726 ctx.dsrc = dview->dsrc;
1727 ctx.a = dview->a[DIFF_LEFT];
1728 ctx.f = f[DIFF_LEFT];
1729 rv |= dff_reparse (DIFF_LEFT, dview->file[DIFF_LEFT], ops, printer, &ctx);
1730
1731 ctx.a = dview->a[DIFF_RIGHT];
1732 ctx.f = f[DIFF_RIGHT];
1733 rv |= dff_reparse (DIFF_RIGHT, dview->file[DIFF_RIGHT], ops, printer, &ctx);
1734
1735 if (ops != NULL)
1736 g_array_free (ops, TRUE);
1737
1738 if (rv != 0 || dview->a[DIFF_LEFT]->len != dview->a[DIFF_RIGHT]->len)
1739 return -1;
1740
1741 if (dview->dsrc == DATA_SRC_TMP)
1742 {
1743 dview_ftrunc (f[DIFF_LEFT]);
1744 dview_ftrunc (f[DIFF_RIGHT]);
1745 }
1746
1747 if (dview->dsrc == DATA_SRC_MEM && HDIFF_ENABLE)
1748 {
1749 size_t i;
1750
1751 dview->hdiff = g_ptr_array_new ();
1752
1753 for (i = 0; i < dview->a[DIFF_LEFT]->len; i++)
1754 {
1755 GArray *h = NULL;
1756 const DIFFLN *p;
1757 const DIFFLN *q;
1758
1759 p = &g_array_index (dview->a[DIFF_LEFT], DIFFLN, i);
1760 q = &g_array_index (dview->a[DIFF_RIGHT], DIFFLN, i);
1761 if (p->line != 0 && q->line != 0 && p->ch == CHG_CH)
1762 {
1763 gboolean runresult;
1764
1765 h = g_array_new (FALSE, FALSE, sizeof (BRACKET));
1766
1767 runresult =
1768 hdiff_scan (p->p, p->u.len, q->p, q->u.len, HDIFF_MINCTX, h, HDIFF_DEPTH);
1769 if (!runresult)
1770 {
1771 g_array_free (h, TRUE);
1772 h = NULL;
1773 }
1774 }
1775
1776 g_ptr_array_add (dview->hdiff, h);
1777 }
1778 }
1779 return ndiff;
1780 }
1781
1782
1783
1784 static void
1785 destroy_hdiff (WDiff * dview)
1786 {
1787 if (dview->hdiff != NULL)
1788 {
1789 int i;
1790 int len;
1791
1792 len = dview->a[DIFF_LEFT]->len;
1793
1794 for (i = 0; i < len; i++)
1795 {
1796 GArray *h;
1797
1798 h = (GArray *) g_ptr_array_index (dview->hdiff, i);
1799 if (h != NULL)
1800 g_array_free (h, TRUE);
1801 }
1802 g_ptr_array_free (dview->hdiff, TRUE);
1803 dview->hdiff = NULL;
1804 }
1805
1806 mc_search_free (dview->search.handle);
1807 dview->search.handle = NULL;
1808 MC_PTR_FREE (dview->search.last_string);
1809 }
1810
1811
1812
1813
1814 static int
1815 get_digits (unsigned int n)
1816 {
1817 int d = 1;
1818
1819 while ((n /= 10) != 0)
1820 d++;
1821 return d;
1822 }
1823
1824
1825
1826 static int
1827 get_line_numbers (const GArray * a, size_t pos, int *linenum, int *lineofs)
1828 {
1829 const DIFFLN *p;
1830
1831 *linenum = 0;
1832 *lineofs = 0;
1833
1834 if (a->len != 0)
1835 {
1836 if (pos >= a->len)
1837 pos = a->len - 1;
1838
1839 p = &g_array_index (a, DIFFLN, pos);
1840
1841 if (p->line == 0)
1842 {
1843 int n;
1844
1845 for (n = pos; n > 0; n--)
1846 {
1847 p--;
1848 if (p->line != 0)
1849 break;
1850 }
1851 *lineofs = pos - n + 1;
1852 }
1853
1854 *linenum = p->line;
1855 }
1856 return 0;
1857 }
1858
1859
1860
1861 static int
1862 calc_nwidth (const GArray * const *a)
1863 {
1864 int l1, o1;
1865 int l2, o2;
1866
1867 get_line_numbers (a[DIFF_LEFT], a[DIFF_LEFT]->len - 1, &l1, &o1);
1868 get_line_numbers (a[DIFF_RIGHT], a[DIFF_RIGHT]->len - 1, &l2, &o2);
1869 if (l1 < l2)
1870 l1 = l2;
1871 return get_digits (l1);
1872 }
1873
1874
1875
1876 static int
1877 find_prev_hunk (const GArray * a, int pos)
1878 {
1879 #if 1
1880 for (; pos > 0 && ((DIFFLN *) & g_array_index (a, DIFFLN, pos))->ch != EQU_CH; pos--)
1881 ;
1882 for (; pos > 0 && ((DIFFLN *) & g_array_index (a, DIFFLN, pos))->ch == EQU_CH; pos--)
1883 ;
1884 for (; pos > 0 && ((DIFFLN *) & g_array_index (a, DIFFLN, pos))->ch != EQU_CH; pos--)
1885 ;
1886 if (pos > 0 && (size_t) pos < a->len)
1887 pos++;
1888 #else
1889 for (; pos > 0 && ((DIFFLN *) & g_array_index (a, DIFFLN, pos - 1))->ch == EQU_CH; pos--)
1890 ;
1891 for (; pos > 0 && ((DIFFLN *) & g_array_index (a, DIFFLN, pos - 1))->ch != EQU_CH; pos--)
1892 ;
1893 #endif
1894
1895 return pos;
1896 }
1897
1898
1899
1900 static size_t
1901 find_next_hunk (const GArray * a, size_t pos)
1902 {
1903 for (; pos < a->len && ((DIFFLN *) & g_array_index (a, DIFFLN, pos))->ch != EQU_CH; pos++)
1904 ;
1905 for (; pos < a->len && ((DIFFLN *) & g_array_index (a, DIFFLN, pos))->ch == EQU_CH; pos++)
1906 ;
1907 return pos;
1908 }
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922 static int
1923 get_current_hunk (WDiff * dview, int *start_line1, int *end_line1, int *start_line2, int *end_line2)
1924 {
1925 const GArray *a0 = dview->a[DIFF_LEFT];
1926 const GArray *a1 = dview->a[DIFF_RIGHT];
1927 size_t pos;
1928 int ch;
1929 int res = 0;
1930
1931 *start_line1 = 1;
1932 *start_line2 = 1;
1933 *end_line1 = 1;
1934 *end_line2 = 1;
1935
1936 pos = dview->skip_rows;
1937 ch = ((DIFFLN *) & g_array_index (a0, DIFFLN, pos))->ch;
1938 if (ch != EQU_CH)
1939 {
1940 switch (ch)
1941 {
1942 case ADD_CH:
1943 res = DIFF_DEL;
1944 break;
1945 case DEL_CH:
1946 res = DIFF_ADD;
1947 break;
1948 case CHG_CH:
1949 res = DIFF_CHG;
1950 break;
1951 default:
1952 break;
1953 }
1954
1955 for (; pos > 0 && ((DIFFLN *) & g_array_index (a0, DIFFLN, pos))->ch != EQU_CH; pos--)
1956 ;
1957 if (pos > 0)
1958 {
1959 *start_line1 = ((DIFFLN *) & g_array_index (a0, DIFFLN, pos))->line + 1;
1960 *start_line2 = ((DIFFLN *) & g_array_index (a1, DIFFLN, pos))->line + 1;
1961 }
1962
1963 for (pos = dview->skip_rows;
1964 pos < a0->len && ((DIFFLN *) & g_array_index (a0, DIFFLN, pos))->ch != EQU_CH; pos++)
1965 {
1966 int l0, l1;
1967
1968 l0 = ((DIFFLN *) & g_array_index (a0, DIFFLN, pos))->line;
1969 l1 = ((DIFFLN *) & g_array_index (a1, DIFFLN, pos))->line;
1970 if (l0 > 0)
1971 *end_line1 = MAX (*start_line1, l0);
1972 if (l1 > 0)
1973 *end_line2 = MAX (*start_line2, l1);
1974 }
1975 }
1976 return res;
1977 }
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990 static void
1991 dview_remove_hunk (WDiff * dview, FILE * merge_file, int from1, int to1,
1992 action_direction_t merge_direction)
1993 {
1994 int line;
1995 char buf[BUF_10K];
1996 FILE *f0;
1997
1998 if (merge_direction == FROM_RIGHT_TO_LEFT)
1999 f0 = fopen (dview->file[DIFF_RIGHT], "r");
2000 else
2001 f0 = fopen (dview->file[DIFF_LEFT], "r");
2002
2003 for (line = 0; fgets (buf, sizeof (buf), f0) != NULL && line < from1 - 1; line++)
2004 fputs (buf, merge_file);
2005
2006 while (fgets (buf, sizeof (buf), f0) != NULL)
2007 {
2008 line++;
2009 if (line >= to1)
2010 fputs (buf, merge_file);
2011 }
2012 fclose (f0);
2013 }
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027 static void
2028 dview_add_hunk (WDiff * dview, FILE * merge_file, int from1, int from2, int to2,
2029 action_direction_t merge_direction)
2030 {
2031 int line;
2032 char buf[BUF_10K];
2033 FILE *f0, *f1;
2034
2035 if (merge_direction == FROM_RIGHT_TO_LEFT)
2036 {
2037 f0 = fopen (dview->file[DIFF_RIGHT], "r");
2038 f1 = fopen (dview->file[DIFF_LEFT], "r");
2039 }
2040 else
2041 {
2042 f0 = fopen (dview->file[DIFF_LEFT], "r");
2043 f1 = fopen (dview->file[DIFF_RIGHT], "r");
2044 }
2045
2046 for (line = 0; fgets (buf, sizeof (buf), f0) != NULL && line < from1 - 1; line++)
2047 fputs (buf, merge_file);
2048 for (line = 0; fgets (buf, sizeof (buf), f1) != NULL && line <= to2;)
2049 {
2050 line++;
2051 if (line >= from2)
2052 fputs (buf, merge_file);
2053 }
2054 while (fgets (buf, sizeof (buf), f0) != NULL)
2055 fputs (buf, merge_file);
2056
2057 fclose (f0);
2058 fclose (f1);
2059 }
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074 static void
2075 dview_replace_hunk (WDiff * dview, FILE * merge_file, int from1, int to1, int from2, int to2,
2076 action_direction_t merge_direction)
2077 {
2078 int line1, line2;
2079 char buf[BUF_10K];
2080 FILE *f0, *f1;
2081
2082 if (merge_direction == FROM_RIGHT_TO_LEFT)
2083 {
2084 f0 = fopen (dview->file[DIFF_RIGHT], "r");
2085 f1 = fopen (dview->file[DIFF_LEFT], "r");
2086 }
2087 else
2088 {
2089 f0 = fopen (dview->file[DIFF_LEFT], "r");
2090 f1 = fopen (dview->file[DIFF_RIGHT], "r");
2091 }
2092
2093 for (line1 = 0; fgets (buf, sizeof (buf), f0) != NULL && line1 < from1 - 1; line1++)
2094 fputs (buf, merge_file);
2095 for (line2 = 0; fgets (buf, sizeof (buf), f1) != NULL && line2 <= to2;)
2096 {
2097 line2++;
2098 if (line2 >= from2)
2099 fputs (buf, merge_file);
2100 }
2101 while (fgets (buf, sizeof (buf), f0) != NULL)
2102 {
2103 line1++;
2104 if (line1 > to1)
2105 fputs (buf, merge_file);
2106 }
2107 fclose (f0);
2108 fclose (f1);
2109 }
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119 static void
2120 do_merge_hunk (WDiff * dview, action_direction_t merge_direction)
2121 {
2122 int from1, to1, from2, to2;
2123 int hunk;
2124 diff_place_t n_merge = (merge_direction == FROM_RIGHT_TO_LEFT) ? DIFF_RIGHT : DIFF_LEFT;
2125
2126 if (merge_direction == FROM_RIGHT_TO_LEFT)
2127 hunk = get_current_hunk (dview, &from2, &to2, &from1, &to1);
2128 else
2129 hunk = get_current_hunk (dview, &from1, &to1, &from2, &to2);
2130
2131 if (hunk > 0)
2132 {
2133 int merge_file_fd;
2134 FILE *merge_file;
2135 vfs_path_t *merge_file_name_vpath = NULL;
2136
2137 if (!dview->merged[n_merge])
2138 {
2139 dview->merged[n_merge] = mc_util_make_backup_if_possible (dview->file[n_merge], "~~~");
2140 if (!dview->merged[n_merge])
2141 {
2142 message (D_ERROR, MSG_ERROR,
2143 _("Cannot create backup file\n%s%s\n%s"),
2144 dview->file[n_merge], "~~~", unix_error_string (errno));
2145 return;
2146 }
2147 }
2148
2149 merge_file_fd = mc_mkstemps (&merge_file_name_vpath, "mcmerge", NULL);
2150 if (merge_file_fd == -1)
2151 {
2152 message (D_ERROR, MSG_ERROR, _("Cannot create temporary merge file\n%s"),
2153 unix_error_string (errno));
2154 return;
2155 }
2156
2157 merge_file = fdopen (merge_file_fd, "w");
2158
2159 switch (hunk)
2160 {
2161 case DIFF_DEL:
2162 if (merge_direction == FROM_RIGHT_TO_LEFT)
2163 dview_add_hunk (dview, merge_file, from1, from2, to2, FROM_RIGHT_TO_LEFT);
2164 else
2165 dview_remove_hunk (dview, merge_file, from1, to1, FROM_LEFT_TO_RIGHT);
2166 break;
2167 case DIFF_ADD:
2168 if (merge_direction == FROM_RIGHT_TO_LEFT)
2169 dview_remove_hunk (dview, merge_file, from1, to1, FROM_RIGHT_TO_LEFT);
2170 else
2171 dview_add_hunk (dview, merge_file, from1, from2, to2, FROM_LEFT_TO_RIGHT);
2172 break;
2173 case DIFF_CHG:
2174 dview_replace_hunk (dview, merge_file, from1, to1, from2, to2, merge_direction);
2175 break;
2176 default:
2177 break;
2178 }
2179 fflush (merge_file);
2180 fclose (merge_file);
2181 {
2182 int res;
2183
2184 res = rewrite_backup_content (merge_file_name_vpath, dview->file[n_merge]);
2185 (void) res;
2186 }
2187 mc_unlink (merge_file_name_vpath);
2188 vfs_path_free (merge_file_name_vpath, TRUE);
2189 }
2190 }
2191
2192
2193
2194
2195 static void
2196 dview_compute_split (WDiff * dview, int i)
2197 {
2198 dview->bias += i;
2199 if (dview->bias < 2 - dview->half1)
2200 dview->bias = 2 - dview->half1;
2201 if (dview->bias > dview->half2 - 2)
2202 dview->bias = dview->half2 - 2;
2203 }
2204
2205
2206
2207 static void
2208 dview_compute_areas (WDiff * dview)
2209 {
2210 Widget *w = WIDGET (dview);
2211
2212 dview->height = w->rect.lines - 1;
2213 dview->half1 = w->rect.cols / 2;
2214 dview->half2 = w->rect.cols - dview->half1;
2215
2216 dview_compute_split (dview, 0);
2217 }
2218
2219
2220
2221 static void
2222 dview_reread (WDiff * dview)
2223 {
2224 int ndiff;
2225
2226 destroy_hdiff (dview);
2227 if (dview->a[DIFF_LEFT] != NULL)
2228 g_array_free (dview->a[DIFF_LEFT], TRUE);
2229 if (dview->a[DIFF_RIGHT] != NULL)
2230 g_array_free (dview->a[DIFF_RIGHT], TRUE);
2231
2232 dview->a[DIFF_LEFT] = g_array_new (FALSE, FALSE, sizeof (DIFFLN));
2233 g_array_set_clear_func (dview->a[DIFF_LEFT], cc_free_elt);
2234 dview->a[DIFF_RIGHT] = g_array_new (FALSE, FALSE, sizeof (DIFFLN));
2235 g_array_set_clear_func (dview->a[DIFF_RIGHT], cc_free_elt);
2236
2237 ndiff = redo_diff (dview);
2238 if (ndiff >= 0)
2239 dview->ndiff = ndiff;
2240 }
2241
2242
2243
2244 #ifdef HAVE_CHARSET
2245 static void
2246 dview_set_codeset (WDiff * dview)
2247 {
2248 const char *encoding_id = NULL;
2249
2250 dview->utf8 = TRUE;
2251 encoding_id =
2252 get_codepage_id (mc_global.source_codepage >=
2253 0 ? mc_global.source_codepage : mc_global.display_codepage);
2254 if (encoding_id != NULL)
2255 {
2256 GIConv conv;
2257
2258 conv = str_crt_conv_from (encoding_id);
2259 if (conv != INVALID_CONV)
2260 {
2261 if (dview->converter != str_cnv_from_term)
2262 str_close_conv (dview->converter);
2263 dview->converter = conv;
2264 }
2265 dview->utf8 = (gboolean) str_isutf8 (encoding_id);
2266 }
2267 }
2268
2269
2270
2271 static void
2272 dview_select_encoding (WDiff * dview)
2273 {
2274 if (do_select_codepage ())
2275 dview_set_codeset (dview);
2276 dview_reread (dview);
2277 tty_touch_screen ();
2278 repaint_screen ();
2279 }
2280 #endif
2281
2282
2283
2284 static void
2285 dview_load_options (WDiff * dview)
2286 {
2287 gboolean show_numbers;
2288 int tab_size;
2289
2290 dview->display_symbols =
2291 mc_config_get_bool (mc_global.main_config, "DiffView", "show_symbols", FALSE);
2292 show_numbers = mc_config_get_bool (mc_global.main_config, "DiffView", "show_numbers", FALSE);
2293 if (show_numbers)
2294 dview->display_numbers = 1;
2295 tab_size = mc_config_get_int (mc_global.main_config, "DiffView", "tab_size", 8);
2296 if (tab_size > 0 && tab_size < 9)
2297 dview->tab_size = tab_size;
2298 else
2299 dview->tab_size = 8;
2300
2301 dview->opt.quality = mc_config_get_int (mc_global.main_config, "DiffView", "diff_quality", 0);
2302
2303 dview->opt.strip_trailing_cr =
2304 mc_config_get_bool (mc_global.main_config, "DiffView", "diff_ignore_tws", FALSE);
2305 dview->opt.ignore_all_space =
2306 mc_config_get_bool (mc_global.main_config, "DiffView", "diff_ignore_all_space", FALSE);
2307 dview->opt.ignore_space_change =
2308 mc_config_get_bool (mc_global.main_config, "DiffView", "diff_ignore_space_change", FALSE);
2309 dview->opt.ignore_tab_expansion =
2310 mc_config_get_bool (mc_global.main_config, "DiffView", "diff_tab_expansion", FALSE);
2311 dview->opt.ignore_case =
2312 mc_config_get_bool (mc_global.main_config, "DiffView", "diff_ignore_case", FALSE);
2313
2314 dview->new_frame = TRUE;
2315 }
2316
2317
2318
2319 static void
2320 dview_save_options (WDiff * dview)
2321 {
2322 mc_config_set_bool (mc_global.main_config, "DiffView", "show_symbols", dview->display_symbols);
2323 mc_config_set_bool (mc_global.main_config, "DiffView", "show_numbers",
2324 dview->display_numbers != 0);
2325 mc_config_set_int (mc_global.main_config, "DiffView", "tab_size", dview->tab_size);
2326
2327 mc_config_set_int (mc_global.main_config, "DiffView", "diff_quality", dview->opt.quality);
2328
2329 mc_config_set_bool (mc_global.main_config, "DiffView", "diff_ignore_tws",
2330 dview->opt.strip_trailing_cr);
2331 mc_config_set_bool (mc_global.main_config, "DiffView", "diff_ignore_all_space",
2332 dview->opt.ignore_all_space);
2333 mc_config_set_bool (mc_global.main_config, "DiffView", "diff_ignore_space_change",
2334 dview->opt.ignore_space_change);
2335 mc_config_set_bool (mc_global.main_config, "DiffView", "diff_tab_expansion",
2336 dview->opt.ignore_tab_expansion);
2337 mc_config_set_bool (mc_global.main_config, "DiffView", "diff_ignore_case",
2338 dview->opt.ignore_case);
2339 }
2340
2341
2342
2343 static void
2344 dview_diff_options (WDiff * dview)
2345 {
2346 const char *quality_str[] = {
2347 N_("No&rmal"),
2348 N_("&Fastest (Assume large files)"),
2349 N_("&Minimal (Find a smaller set of change)")
2350 };
2351
2352 quick_widget_t quick_widgets[] = {
2353
2354 QUICK_START_GROUPBOX (N_("Diff algorithm")),
2355 QUICK_RADIO (3, (const char **) quality_str, (int *) &dview->opt.quality, NULL),
2356 QUICK_STOP_GROUPBOX,
2357 QUICK_START_GROUPBOX (N_("Diff extra options")),
2358 QUICK_CHECKBOX (N_("&Ignore case"), &dview->opt.ignore_case, NULL),
2359 QUICK_CHECKBOX (N_("Ignore tab &expansion"), &dview->opt.ignore_tab_expansion, NULL),
2360 QUICK_CHECKBOX (N_("Ignore &space change"), &dview->opt.ignore_space_change, NULL),
2361 QUICK_CHECKBOX (N_("Ignore all &whitespace"), &dview->opt.ignore_all_space, NULL),
2362 QUICK_CHECKBOX (N_("Strip &trailing carriage return"), &dview->opt.strip_trailing_cr,
2363 NULL),
2364 QUICK_STOP_GROUPBOX,
2365 QUICK_BUTTONS_OK_CANCEL,
2366 QUICK_END
2367
2368 };
2369
2370 WRect r = { -1, -1, 0, 56 };
2371
2372 quick_dialog_t qdlg = {
2373 r, N_("Diff Options"), "[Diff Options]",
2374 quick_widgets, NULL, NULL
2375 };
2376
2377 if (quick_dialog (&qdlg) != B_CANCEL)
2378 dview_reread (dview);
2379 }
2380
2381
2382
2383 static int
2384 dview_init (WDiff * dview, const char *args, const char *file1, const char *file2,
2385 const char *label1, const char *label2, DSRC dsrc)
2386 {
2387 int ndiff;
2388 FBUF *f[DIFF_COUNT];
2389
2390 f[DIFF_LEFT] = NULL;
2391 f[DIFF_RIGHT] = NULL;
2392
2393 if (dsrc == DATA_SRC_TMP)
2394 {
2395 f[DIFF_LEFT] = dview_ftemp ();
2396 if (f[DIFF_LEFT] == NULL)
2397 return -1;
2398
2399 f[DIFF_RIGHT] = dview_ftemp ();
2400 if (f[DIFF_RIGHT] == NULL)
2401 {
2402 dview_fclose (f[DIFF_LEFT]);
2403 return -1;
2404 }
2405 }
2406 else if (dsrc == DATA_SRC_ORG)
2407 {
2408 f[DIFF_LEFT] = dview_fopen (file1, O_RDONLY);
2409 if (f[DIFF_LEFT] == NULL)
2410 return -1;
2411
2412 f[DIFF_RIGHT] = dview_fopen (file2, O_RDONLY);
2413 if (f[DIFF_RIGHT] == NULL)
2414 {
2415 dview_fclose (f[DIFF_LEFT]);
2416 return -1;
2417 }
2418 }
2419
2420 dview->view_quit = FALSE;
2421
2422 dview->bias = 0;
2423 dview->new_frame = TRUE;
2424 dview->skip_rows = 0;
2425 dview->skip_cols = 0;
2426 dview->display_symbols = FALSE;
2427 dview->display_numbers = 0;
2428 dview->show_cr = TRUE;
2429 dview->tab_size = 8;
2430 dview->ord = DIFF_LEFT;
2431 dview->full = FALSE;
2432
2433 dview->search.handle = NULL;
2434 dview->search.last_string = NULL;
2435 dview->search.last_found_line = -1;
2436 dview->search.last_accessed_num_line = -1;
2437
2438 dview_load_options (dview);
2439
2440 dview->args = args;
2441 dview->file[DIFF_LEFT] = file1;
2442 dview->file[DIFF_RIGHT] = file2;
2443 dview->label[DIFF_LEFT] = g_strdup (label1);
2444 dview->label[DIFF_RIGHT] = g_strdup (label2);
2445 dview->f[DIFF_LEFT] = f[0];
2446 dview->f[DIFF_RIGHT] = f[1];
2447 dview->merged[DIFF_LEFT] = FALSE;
2448 dview->merged[DIFF_RIGHT] = FALSE;
2449 dview->hdiff = NULL;
2450 dview->dsrc = dsrc;
2451 #ifdef HAVE_CHARSET
2452 dview->converter = str_cnv_from_term;
2453 dview_set_codeset (dview);
2454 #endif
2455 dview->a[DIFF_LEFT] = g_array_new (FALSE, FALSE, sizeof (DIFFLN));
2456 g_array_set_clear_func (dview->a[DIFF_LEFT], cc_free_elt);
2457 dview->a[DIFF_RIGHT] = g_array_new (FALSE, FALSE, sizeof (DIFFLN));
2458 g_array_set_clear_func (dview->a[DIFF_RIGHT], cc_free_elt);
2459
2460 ndiff = redo_diff (dview);
2461 if (ndiff < 0)
2462 {
2463
2464 dview_fclose (f[DIFF_LEFT]);
2465 dview_fclose (f[DIFF_RIGHT]);
2466 return -1;
2467 }
2468
2469 dview->ndiff = ndiff;
2470
2471 dview_compute_areas (dview);
2472
2473 return 0;
2474 }
2475
2476
2477
2478 static void
2479 dview_fini (WDiff * dview)
2480 {
2481 if (dview->dsrc != DATA_SRC_MEM)
2482 {
2483 dview_fclose (dview->f[DIFF_RIGHT]);
2484 dview_fclose (dview->f[DIFF_LEFT]);
2485 }
2486
2487 #ifdef HAVE_CHARSET
2488 if (dview->converter != str_cnv_from_term)
2489 str_close_conv (dview->converter);
2490 #endif
2491
2492 destroy_hdiff (dview);
2493 if (dview->a[DIFF_LEFT] != NULL)
2494 {
2495 g_array_free (dview->a[DIFF_LEFT], TRUE);
2496 dview->a[DIFF_LEFT] = NULL;
2497 }
2498 if (dview->a[DIFF_RIGHT] != NULL)
2499 {
2500 g_array_free (dview->a[DIFF_RIGHT], TRUE);
2501 dview->a[DIFF_RIGHT] = NULL;
2502 }
2503
2504 g_free (dview->label[DIFF_LEFT]);
2505 g_free (dview->label[DIFF_RIGHT]);
2506 }
2507
2508
2509
2510 static int
2511 dview_display_file (const WDiff * dview, diff_place_t ord, int r, int c, int height, int width)
2512 {
2513 size_t i, k;
2514 int j;
2515 char buf[BUFSIZ];
2516 FBUF *f = dview->f[ord];
2517 int skip = dview->skip_cols;
2518 gboolean display_symbols = dview->display_symbols;
2519 int display_numbers = dview->display_numbers;
2520 gboolean show_cr = dview->show_cr;
2521 int tab_size = 8;
2522 const DIFFLN *p;
2523 int nwidth = display_numbers;
2524 int xwidth;
2525
2526 xwidth = display_numbers;
2527 if (display_symbols)
2528 xwidth++;
2529 if (dview->tab_size > 0 && dview->tab_size < 9)
2530 tab_size = dview->tab_size;
2531
2532 if (xwidth != 0)
2533 {
2534 if (xwidth > width && display_symbols)
2535 {
2536 xwidth--;
2537 display_symbols = FALSE;
2538 }
2539 if (xwidth > width && display_numbers != 0)
2540 {
2541 xwidth = width;
2542 display_numbers = width;
2543 }
2544
2545 xwidth++;
2546 c += xwidth;
2547 width -= xwidth;
2548 if (width < 0)
2549 width = 0;
2550 }
2551
2552 if ((int) sizeof (buf) <= width || (int) sizeof (buf) <= nwidth)
2553 {
2554
2555 return -1;
2556 }
2557
2558 for (i = dview->skip_rows, j = 0; i < dview->a[ord]->len && j < height; j++, i++)
2559 {
2560 int ch;
2561 int next_ch = 0;
2562 int col;
2563 size_t cnt;
2564
2565 p = (DIFFLN *) & g_array_index (dview->a[ord], DIFFLN, i);
2566 ch = p->ch;
2567 tty_setcolor (NORMAL_COLOR);
2568 if (display_symbols)
2569 {
2570 tty_gotoyx (r + j, c - 2);
2571 tty_print_char (ch);
2572 }
2573 if (p->line != 0)
2574 {
2575 if (display_numbers != 0)
2576 {
2577 tty_gotoyx (r + j, c - xwidth);
2578 g_snprintf (buf, display_numbers + 1, "%*d", nwidth, p->line);
2579 tty_print_string (str_fit_to_term (buf, nwidth, J_LEFT_FIT));
2580 }
2581 if (ch == ADD_CH)
2582 tty_setcolor (DFF_ADD_COLOR);
2583 if (ch == CHG_CH)
2584 tty_setcolor (DFF_CHG_COLOR);
2585 if (f == NULL)
2586 {
2587 if (i == (size_t) dview->search.last_found_line)
2588 tty_setcolor (MARKED_SELECTED_COLOR);
2589 else if (dview->hdiff != NULL && g_ptr_array_index (dview->hdiff, i) != NULL)
2590 {
2591 char att[BUFSIZ];
2592
2593 #ifdef HAVE_CHARSET
2594 if (dview->utf8)
2595 k = dview_str_utf8_offset_to_pos (p->p, width);
2596 else
2597 #endif
2598 k = width;
2599
2600 cvt_mgeta (p->p, p->u.len, buf, k, skip, tab_size, show_cr,
2601 g_ptr_array_index (dview->hdiff, i), ord, att);
2602 tty_gotoyx (r + j, c);
2603 col = 0;
2604
2605 for (cnt = 0; cnt < strlen (buf) && col < width; cnt++)
2606 {
2607 gboolean ch_res;
2608
2609 #ifdef HAVE_CHARSET
2610 if (dview->utf8)
2611 {
2612 int ch_length = 0;
2613
2614 ch_res = dview_get_utf (buf + cnt, &next_ch, &ch_length);
2615 if (ch_length > 1)
2616 cnt += ch_length - 1;
2617 if (!g_unichar_isprint (next_ch))
2618 next_ch = '.';
2619 }
2620 else
2621 #endif
2622 ch_res = dview_get_byte (buf + cnt, &next_ch);
2623
2624 if (ch_res)
2625 {
2626 tty_setcolor (att[cnt] ? DFF_CHH_COLOR : DFF_CHG_COLOR);
2627 #ifdef HAVE_CHARSET
2628 if (mc_global.utf8_display)
2629 {
2630 if (!dview->utf8)
2631 {
2632 next_ch =
2633 convert_from_8bit_to_utf_c ((unsigned char) next_ch,
2634 dview->converter);
2635 }
2636 }
2637 else if (dview->utf8)
2638 next_ch = convert_from_utf_to_current_c (next_ch, dview->converter);
2639 else
2640 next_ch = convert_to_display_c (next_ch);
2641 #endif
2642 tty_print_anychar (next_ch);
2643 col++;
2644 }
2645 }
2646 continue;
2647 }
2648
2649 if (ch == CHG_CH)
2650 tty_setcolor (DFF_CHH_COLOR);
2651
2652 #ifdef HAVE_CHARSET
2653 if (dview->utf8)
2654 k = dview_str_utf8_offset_to_pos (p->p, width);
2655 else
2656 #endif
2657 k = width;
2658 cvt_mget (p->p, p->u.len, buf, k, skip, tab_size, show_cr);
2659 }
2660 else
2661 cvt_fget (f, p->u.off, buf, width, skip, tab_size, show_cr);
2662 }
2663 else
2664 {
2665 if (display_numbers != 0)
2666 {
2667 tty_gotoyx (r + j, c - xwidth);
2668 fill_by_space (buf, display_numbers, TRUE);
2669 tty_print_string (buf);
2670 }
2671 if (ch == DEL_CH)
2672 tty_setcolor (DFF_DEL_COLOR);
2673 if (ch == CHG_CH)
2674 tty_setcolor (DFF_CHD_COLOR);
2675 fill_by_space (buf, width, TRUE);
2676 }
2677 tty_gotoyx (r + j, c);
2678
2679 col = 0;
2680 for (cnt = 0; cnt < strlen (buf) && col < width; cnt++)
2681 {
2682 gboolean ch_res;
2683
2684 #ifdef HAVE_CHARSET
2685 if (dview->utf8)
2686 {
2687 int ch_length = 0;
2688
2689 ch_res = dview_get_utf (buf + cnt, &next_ch, &ch_length);
2690 if (ch_length > 1)
2691 cnt += ch_length - 1;
2692 if (!g_unichar_isprint (next_ch))
2693 next_ch = '.';
2694 }
2695 else
2696 #endif
2697 ch_res = dview_get_byte (buf + cnt, &next_ch);
2698
2699 if (ch_res)
2700 {
2701 #ifdef HAVE_CHARSET
2702 if (mc_global.utf8_display)
2703 {
2704 if (!dview->utf8)
2705 next_ch =
2706 convert_from_8bit_to_utf_c ((unsigned char) next_ch, dview->converter);
2707 }
2708 else if (dview->utf8)
2709 next_ch = convert_from_utf_to_current_c (next_ch, dview->converter);
2710 else
2711 next_ch = convert_to_display_c (next_ch);
2712 #endif
2713
2714 tty_print_anychar (next_ch);
2715 col++;
2716 }
2717 }
2718 }
2719 tty_setcolor (NORMAL_COLOR);
2720 k = width;
2721 if (width < xwidth - 1)
2722 k = xwidth - 1;
2723 fill_by_space (buf, k, TRUE);
2724 for (; j < height; j++)
2725 {
2726 if (xwidth != 0)
2727 {
2728 tty_gotoyx (r + j, c - xwidth);
2729
2730 tty_print_string (str_fit_to_term (buf, xwidth - 1, J_LEFT_FIT));
2731 }
2732 tty_gotoyx (r + j, c);
2733
2734 tty_print_string (str_fit_to_term (buf, width, J_LEFT_FIT));
2735 }
2736
2737 return 0;
2738 }
2739
2740
2741
2742 static void
2743 dview_status (const WDiff * dview, diff_place_t ord, int width, int c)
2744 {
2745 const char *buf;
2746 int filename_width;
2747 int linenum, lineofs;
2748 vfs_path_t *vpath;
2749 char *path;
2750
2751 tty_setcolor (STATUSBAR_COLOR);
2752
2753 tty_gotoyx (0, c);
2754 get_line_numbers (dview->a[ord], dview->skip_rows, &linenum, &lineofs);
2755
2756 filename_width = width - 24;
2757 if (filename_width < 8)
2758 filename_width = 8;
2759
2760 vpath = vfs_path_from_str (dview->label[ord]);
2761 path = vfs_path_to_str_flags (vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
2762 vfs_path_free (vpath, TRUE);
2763 buf = str_term_trim (path, filename_width);
2764 if (ord == DIFF_LEFT)
2765 tty_printf ("%s%-*s %6d+%-4d Col %-4d ", dview->merged[ord] ? "* " : " ", filename_width,
2766 buf, linenum, lineofs, dview->skip_cols);
2767 else
2768 tty_printf ("%s%-*s %6d+%-4d Dif %-4d ", dview->merged[ord] ? "* " : " ", filename_width,
2769 buf, linenum, lineofs, dview->ndiff);
2770 g_free (path);
2771 }
2772
2773
2774
2775 static void
2776 dview_redo (WDiff * dview)
2777 {
2778 if (dview->display_numbers != 0)
2779 {
2780 int old;
2781
2782 old = dview->display_numbers;
2783 dview->display_numbers = calc_nwidth ((const GArray * const *) dview->a);
2784 dview->new_frame = (old != dview->display_numbers);
2785 }
2786 dview_reread (dview);
2787 }
2788
2789
2790
2791 static void
2792 dview_update (WDiff * dview)
2793 {
2794 int height = dview->height;
2795 int width1, width2;
2796 int last;
2797
2798 last = dview->a[DIFF_LEFT]->len - 1;
2799
2800 if (dview->skip_rows > last)
2801 dview->skip_rows = dview->search.last_accessed_num_line = last;
2802 if (dview->skip_rows < 0)
2803 dview->skip_rows = dview->search.last_accessed_num_line = 0;
2804 if (dview->skip_cols < 0)
2805 dview->skip_cols = 0;
2806
2807 if (height < 2)
2808 return;
2809
2810
2811 if (dview->display_numbers != 0)
2812 dview->display_numbers = calc_nwidth ((const GArray * const *) dview->a);
2813
2814 width1 = dview->half1 + dview->bias;
2815 width2 = dview->half2 - dview->bias;
2816 if (dview->full)
2817 {
2818 width1 = COLS;
2819 width2 = 0;
2820 }
2821
2822 if (dview->new_frame)
2823 {
2824 int xwidth;
2825
2826 tty_setcolor (NORMAL_COLOR);
2827 xwidth = dview->display_numbers;
2828 if (dview->display_symbols)
2829 xwidth++;
2830 if (width1 > 1)
2831 tty_draw_box (1, 0, height, width1, FALSE);
2832 if (width2 > 1)
2833 tty_draw_box (1, width1, height, width2, FALSE);
2834
2835 if (xwidth != 0)
2836 {
2837 xwidth++;
2838 if (xwidth < width1 - 1)
2839 {
2840 tty_gotoyx (1, xwidth);
2841 tty_print_alt_char (ACS_TTEE, FALSE);
2842 tty_gotoyx (height, xwidth);
2843 tty_print_alt_char (ACS_BTEE, FALSE);
2844 tty_draw_vline (2, xwidth, ACS_VLINE, height - 2);
2845 }
2846 if (xwidth < width2 - 1)
2847 {
2848 tty_gotoyx (1, width1 + xwidth);
2849 tty_print_alt_char (ACS_TTEE, FALSE);
2850 tty_gotoyx (height, width1 + xwidth);
2851 tty_print_alt_char (ACS_BTEE, FALSE);
2852 tty_draw_vline (2, width1 + xwidth, ACS_VLINE, height - 2);
2853 }
2854 }
2855 dview->new_frame = FALSE;
2856 }
2857
2858 if (width1 > 2)
2859 {
2860 dview_status (dview, dview->ord, width1, 0);
2861 dview_display_file (dview, dview->ord, 2, 1, height - 2, width1 - 2);
2862 }
2863 if (width2 > 2)
2864 {
2865 diff_place_t ord;
2866
2867 ord = dview->ord == DIFF_LEFT ? DIFF_RIGHT : DIFF_LEFT;
2868 dview_status (dview, ord, width2, width1);
2869 dview_display_file (dview, ord, 2, width1 + 1, height - 2, width2 - 2);
2870 }
2871 }
2872
2873
2874
2875 static void
2876 dview_edit (WDiff * dview, diff_place_t ord)
2877 {
2878 Widget *h;
2879 gboolean h_modal;
2880 int linenum, lineofs;
2881
2882 if (dview->dsrc == DATA_SRC_TMP)
2883 {
2884 error_dialog (_("Edit"), _("Edit is disabled"));
2885 return;
2886 }
2887
2888 h = WIDGET (WIDGET (dview)->owner);
2889 h_modal = widget_get_state (h, WST_MODAL);
2890
2891 get_line_numbers (dview->a[ord], dview->skip_rows, &linenum, &lineofs);
2892
2893
2894 widget_set_state (h, WST_MODAL, TRUE);
2895
2896 {
2897 vfs_path_t *tmp_vpath;
2898
2899 tmp_vpath = vfs_path_from_str (dview->file[ord]);
2900 edit_file_at_line (tmp_vpath, use_internal_edit, linenum);
2901 vfs_path_free (tmp_vpath, TRUE);
2902 }
2903
2904 widget_set_state (h, WST_MODAL, h_modal);
2905 dview_redo (dview);
2906 dview_update (dview);
2907 }
2908
2909
2910
2911 static void
2912 dview_goto_cmd (WDiff * dview, diff_place_t ord)
2913 {
2914 static gboolean first_run = TRUE;
2915
2916
2917 static const char *title[2] = {
2918 N_("Goto line (left)"),
2919 N_("Goto line (right)")
2920 };
2921
2922
2923 int newline;
2924 char *input;
2925
2926 input =
2927 input_dialog (_(title[ord]), _("Enter line:"), MC_HISTORY_YDIFF_GOTO_LINE,
2928 first_run ? NULL : INPUT_LAST_TEXT, INPUT_COMPLETE_NONE);
2929 if (input != NULL)
2930 {
2931 const char *s = input;
2932
2933 if (scan_deci (&s, &newline) == 0 && *s == '\0')
2934 {
2935 size_t i = 0;
2936
2937 if (newline > 0)
2938 for (; i < dview->a[ord]->len; i++)
2939 {
2940 const DIFFLN *p;
2941
2942 p = &g_array_index (dview->a[ord], DIFFLN, i);
2943 if (p->line == newline)
2944 break;
2945 }
2946
2947 dview->skip_rows = dview->search.last_accessed_num_line = (ssize_t) i;
2948 }
2949
2950 g_free (input);
2951 }
2952
2953 first_run = FALSE;
2954 }
2955
2956
2957
2958 static void
2959 dview_labels (WDiff * dview)
2960 {
2961 Widget *d = WIDGET (dview);
2962 WButtonBar *b;
2963
2964 b = buttonbar_find (DIALOG (d->owner));
2965
2966 buttonbar_set_label (b, 1, Q_ ("ButtonBar|Help"), d->keymap, d);
2967 buttonbar_set_label (b, 2, Q_ ("ButtonBar|Save"), d->keymap, d);
2968 buttonbar_set_label (b, 4, Q_ ("ButtonBar|Edit"), d->keymap, d);
2969 buttonbar_set_label (b, 5, Q_ ("ButtonBar|Merge"), d->keymap, d);
2970 buttonbar_set_label (b, 7, Q_ ("ButtonBar|Search"), d->keymap, d);
2971 buttonbar_set_label (b, 9, Q_ ("ButtonBar|Options"), d->keymap, d);
2972 buttonbar_set_label (b, 10, Q_ ("ButtonBar|Quit"), d->keymap, d);
2973 }
2974
2975
2976
2977 static gboolean
2978 dview_save (WDiff * dview)
2979 {
2980 gboolean res = TRUE;
2981
2982 if (dview->merged[DIFF_LEFT])
2983 {
2984 res = mc_util_unlink_backup_if_possible (dview->file[DIFF_LEFT], "~~~");
2985 dview->merged[DIFF_LEFT] = !res;
2986 }
2987 if (dview->merged[DIFF_RIGHT])
2988 {
2989 res = mc_util_unlink_backup_if_possible (dview->file[DIFF_RIGHT], "~~~");
2990 dview->merged[DIFF_RIGHT] = !res;
2991 }
2992 return res;
2993 }
2994
2995
2996
2997 static void
2998 dview_do_save (WDiff * dview)
2999 {
3000 (void) dview_save (dview);
3001 }
3002
3003
3004
3005
3006
3007
3008
3009 static gboolean
3010 dview_ok_to_exit (WDiff * dview)
3011 {
3012 gboolean res = TRUE;
3013 int act;
3014
3015 if (!dview->merged[DIFF_LEFT] && !dview->merged[DIFF_RIGHT])
3016 return res;
3017
3018 act = query_dialog (_("Quit"), !mc_global.midnight_shutdown ?
3019 _("File(s) was modified. Save with exit?") :
3020 _("Midnight Commander is being shut down.\nSave modified file(s)?"),
3021 D_NORMAL, 2, _("&Yes"), _("&No"));
3022
3023
3024 if (mc_global.midnight_shutdown || (act == -1))
3025 act = 1;
3026
3027 switch (act)
3028 {
3029 case -1:
3030 res = FALSE;
3031 break;
3032 case 0:
3033 (void) dview_save (dview);
3034 res = TRUE;
3035 break;
3036 case 1:
3037 if (mc_util_restore_from_backup_if_possible (dview->file[DIFF_LEFT], "~~~"))
3038 res = mc_util_unlink_backup_if_possible (dview->file[DIFF_LEFT], "~~~");
3039 if (mc_util_restore_from_backup_if_possible (dview->file[DIFF_RIGHT], "~~~"))
3040 res = mc_util_unlink_backup_if_possible (dview->file[DIFF_RIGHT], "~~~");
3041 MC_FALLTHROUGH;
3042 default:
3043 res = TRUE;
3044 break;
3045 }
3046 return res;
3047 }
3048
3049
3050
3051 static cb_ret_t
3052 dview_execute_cmd (WDiff * dview, long command)
3053 {
3054 cb_ret_t res = MSG_HANDLED;
3055
3056 switch (command)
3057 {
3058 case CK_ShowSymbols:
3059 dview->display_symbols = !dview->display_symbols;
3060 dview->new_frame = TRUE;
3061 break;
3062 case CK_ShowNumbers:
3063 dview->display_numbers ^= calc_nwidth ((const GArray * const *) dview->a);
3064 dview->new_frame = TRUE;
3065 break;
3066 case CK_SplitFull:
3067 dview->full = !dview->full;
3068 dview->new_frame = TRUE;
3069 break;
3070 case CK_SplitEqual:
3071 if (!dview->full)
3072 {
3073 dview->bias = 0;
3074 dview->new_frame = TRUE;
3075 }
3076 break;
3077 case CK_SplitMore:
3078 if (!dview->full)
3079 {
3080 dview_compute_split (dview, 1);
3081 dview->new_frame = TRUE;
3082 }
3083 break;
3084
3085 case CK_SplitLess:
3086 if (!dview->full)
3087 {
3088 dview_compute_split (dview, -1);
3089 dview->new_frame = TRUE;
3090 }
3091 break;
3092 case CK_Tab2:
3093 dview->tab_size = 2;
3094 break;
3095 case CK_Tab3:
3096 dview->tab_size = 3;
3097 break;
3098 case CK_Tab4:
3099 dview->tab_size = 4;
3100 break;
3101 case CK_Tab8:
3102 dview->tab_size = 8;
3103 break;
3104 case CK_Swap:
3105 dview->ord ^= 1;
3106 break;
3107 case CK_Redo:
3108 dview_redo (dview);
3109 break;
3110 case CK_HunkNext:
3111 dview->skip_rows = dview->search.last_accessed_num_line =
3112 find_next_hunk (dview->a[DIFF_LEFT], dview->skip_rows);
3113 break;
3114 case CK_HunkPrev:
3115 dview->skip_rows = dview->search.last_accessed_num_line =
3116 find_prev_hunk (dview->a[DIFF_LEFT], dview->skip_rows);
3117 break;
3118 case CK_Goto:
3119 dview_goto_cmd (dview, DIFF_RIGHT);
3120 break;
3121 case CK_Edit:
3122 dview_edit (dview, dview->ord);
3123 break;
3124 case CK_Merge:
3125 do_merge_hunk (dview, FROM_LEFT_TO_RIGHT);
3126 dview_redo (dview);
3127 break;
3128 case CK_MergeOther:
3129 do_merge_hunk (dview, FROM_RIGHT_TO_LEFT);
3130 dview_redo (dview);
3131 break;
3132 case CK_EditOther:
3133 dview_edit (dview, dview->ord ^ 1);
3134 break;
3135 case CK_Search:
3136 dview_search_cmd (dview);
3137 break;
3138 case CK_SearchContinue:
3139 dview_continue_search_cmd (dview);
3140 break;
3141 case CK_Top:
3142 dview->skip_rows = dview->search.last_accessed_num_line = 0;
3143 break;
3144 case CK_Bottom:
3145 dview->skip_rows = dview->search.last_accessed_num_line = dview->a[DIFF_LEFT]->len - 1;
3146 break;
3147 case CK_Up:
3148 if (dview->skip_rows > 0)
3149 {
3150 dview->skip_rows--;
3151 dview->search.last_accessed_num_line = dview->skip_rows;
3152 }
3153 break;
3154 case CK_Down:
3155 dview->skip_rows++;
3156 dview->search.last_accessed_num_line = dview->skip_rows;
3157 break;
3158 case CK_PageDown:
3159 if (dview->height > 2)
3160 {
3161 dview->skip_rows += dview->height - 2;
3162 dview->search.last_accessed_num_line = dview->skip_rows;
3163 }
3164 break;
3165 case CK_PageUp:
3166 if (dview->height > 2)
3167 {
3168 dview->skip_rows -= dview->height - 2;
3169 dview->search.last_accessed_num_line = dview->skip_rows;
3170 }
3171 break;
3172 case CK_Left:
3173 dview->skip_cols--;
3174 break;
3175 case CK_Right:
3176 dview->skip_cols++;
3177 break;
3178 case CK_LeftQuick:
3179 dview->skip_cols -= 8;
3180 break;
3181 case CK_RightQuick:
3182 dview->skip_cols += 8;
3183 break;
3184 case CK_Home:
3185 dview->skip_cols = 0;
3186 break;
3187 case CK_Shell:
3188 toggle_subshell ();
3189 break;
3190 case CK_Quit:
3191 dview->view_quit = TRUE;
3192 break;
3193 case CK_Save:
3194 dview_do_save (dview);
3195 break;
3196 case CK_Options:
3197 dview_diff_options (dview);
3198 break;
3199 #ifdef HAVE_CHARSET
3200 case CK_SelectCodepage:
3201 dview_select_encoding (dview);
3202 break;
3203 #endif
3204 case CK_Cancel:
3205
3206 break;
3207 default:
3208 res = MSG_NOT_HANDLED;
3209 }
3210 return res;
3211 }
3212
3213
3214
3215 static cb_ret_t
3216 dview_handle_key (WDiff * dview, int key)
3217 {
3218 long command;
3219
3220 #ifdef HAVE_CHARSET
3221 key = convert_from_input_c (key);
3222 #endif
3223
3224 command = widget_lookup_key (WIDGET (dview), key);
3225 if (command == CK_IgnoreKey)
3226 return MSG_NOT_HANDLED;
3227
3228 return dview_execute_cmd (dview, command);
3229 }
3230
3231
3232
3233 static cb_ret_t
3234 dview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
3235 {
3236 WDiff *dview = (WDiff *) w;
3237 WDialog *h = DIALOG (w->owner);
3238 cb_ret_t i;
3239
3240 switch (msg)
3241 {
3242 case MSG_INIT:
3243 dview_labels (dview);
3244 dview_update (dview);
3245 return MSG_HANDLED;
3246
3247 case MSG_DRAW:
3248 dview->new_frame = TRUE;
3249 dview_update (dview);
3250 return MSG_HANDLED;
3251
3252 case MSG_KEY:
3253 i = dview_handle_key (dview, parm);
3254 if (dview->view_quit)
3255 dlg_close (h);
3256 else
3257 dview_update (dview);
3258 return i;
3259
3260 case MSG_ACTION:
3261 i = dview_execute_cmd (dview, parm);
3262 if (dview->view_quit)
3263 dlg_close (h);
3264 else
3265 dview_update (dview);
3266 return i;
3267
3268 case MSG_RESIZE:
3269 widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
3270 dview_compute_areas (dview);
3271 return MSG_HANDLED;
3272
3273 case MSG_DESTROY:
3274 dview_save_options (dview);
3275 dview_fini (dview);
3276 return MSG_HANDLED;
3277
3278 default:
3279 return widget_default_callback (w, sender, msg, parm, data);
3280 }
3281 }
3282
3283
3284
3285 static void
3286 dview_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
3287 {
3288 WDiff *dview = (WDiff *) w;
3289
3290 (void) event;
3291
3292 switch (msg)
3293 {
3294 case MSG_MOUSE_SCROLL_UP:
3295 case MSG_MOUSE_SCROLL_DOWN:
3296 if (msg == MSG_MOUSE_SCROLL_UP)
3297 dview->skip_rows -= 2;
3298 else
3299 dview->skip_rows += 2;
3300
3301 dview->search.last_accessed_num_line = dview->skip_rows;
3302 dview_update (dview);
3303 break;
3304
3305 default:
3306 break;
3307 }
3308 }
3309
3310
3311
3312 static cb_ret_t
3313 dview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
3314 {
3315 WDiff *dview;
3316 WDialog *h = DIALOG (w);
3317
3318 switch (msg)
3319 {
3320 case MSG_ACTION:
3321
3322
3323
3324
3325 return dview_execute_cmd (NULL, parm);
3326
3327 case MSG_VALIDATE:
3328 dview = (WDiff *) widget_find_by_type (CONST_WIDGET (h), dview_callback);
3329
3330 widget_set_state (w, WST_ACTIVE, TRUE);
3331 if (dview_ok_to_exit (dview))
3332 dlg_close (h);
3333 return MSG_HANDLED;
3334
3335 default:
3336 return dlg_default_callback (w, sender, msg, parm, data);
3337 }
3338 }
3339
3340
3341
3342 static char *
3343 dview_get_title (const WDialog * h, size_t len)
3344 {
3345 const WDiff *dview;
3346 const char *modified = " (*) ";
3347 const char *notmodified = " ";
3348 size_t len1;
3349 GString *title;
3350
3351 dview = (const WDiff *) widget_find_by_type (CONST_WIDGET (h), dview_callback);
3352 len1 = (len - str_term_width1 (_("Diff:")) - strlen (modified) - 3) / 2;
3353
3354 title = g_string_sized_new (len);
3355 g_string_append (title, _("Diff:"));
3356 g_string_append (title, dview->merged[DIFF_LEFT] ? modified : notmodified);
3357 g_string_append (title, str_term_trim (dview->label[DIFF_LEFT], len1));
3358 g_string_append (title, " | ");
3359 g_string_append (title, dview->merged[DIFF_RIGHT] ? modified : notmodified);
3360 g_string_append (title, str_term_trim (dview->label[DIFF_RIGHT], len1));
3361
3362 return g_string_free (title, FALSE);
3363 }
3364
3365
3366
3367 static int
3368 diff_view (const char *file1, const char *file2, const char *label1, const char *label2)
3369 {
3370 int error;
3371 WDiff *dview;
3372 Widget *w;
3373 WDialog *dview_dlg;
3374 Widget *dw;
3375 WRect r;
3376 WGroup *g;
3377
3378
3379 dview_dlg =
3380 dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, NULL, dview_dialog_callback, NULL,
3381 "[Diff Viewer]", NULL);
3382 dw = WIDGET (dview_dlg);
3383 widget_want_tab (dw, TRUE);
3384 r = dw->rect;
3385
3386 g = GROUP (dview_dlg);
3387
3388 dview = g_new0 (WDiff, 1);
3389 w = WIDGET (dview);
3390 r.lines--;
3391 widget_init (w, &r, dview_callback, dview_mouse_callback);
3392 w->options |= WOP_SELECTABLE;
3393 w->keymap = diff_map;
3394 group_add_widget_autopos (g, w, WPOS_KEEP_ALL, NULL);
3395
3396 w = WIDGET (buttonbar_new ());
3397 group_add_widget_autopos (g, w, w->pos_flags, NULL);
3398
3399 dview_dlg->get_title = dview_get_title;
3400
3401 error = dview_init (dview, "-a", file1, file2, label1, label2, DATA_SRC_MEM);
3402
3403 if (error == 0)
3404 dlg_run (dview_dlg);
3405
3406 if (error != 0 || widget_get_state (dw, WST_CLOSED))
3407 widget_destroy (dw);
3408
3409 return error == 0 ? 1 : 0;
3410 }
3411
3412
3413
3414
3415 #define GET_FILE_AND_STAMP(n) \
3416 do \
3417 { \
3418 use_copy##n = 0; \
3419 real_file##n = file##n; \
3420 if (!vfs_file_is_local (file##n)) \
3421 { \
3422 real_file##n = mc_getlocalcopy (file##n); \
3423 if (real_file##n != NULL) \
3424 { \
3425 use_copy##n = 1; \
3426 if (mc_stat (real_file##n, &st##n) != 0) \
3427 use_copy##n = -1; \
3428 } \
3429 } \
3430 } \
3431 while (0)
3432
3433 #define UNGET_FILE(n) \
3434 do \
3435 { \
3436 if (use_copy##n != 0) \
3437 { \
3438 gboolean changed = FALSE; \
3439 if (use_copy##n > 0) \
3440 { \
3441 time_t mtime; \
3442 mtime = st##n.st_mtime; \
3443 if (mc_stat (real_file##n, &st##n) == 0) \
3444 changed = (mtime != st##n.st_mtime); \
3445 } \
3446 mc_ungetlocalcopy (file##n, real_file##n, changed); \
3447 vfs_path_free (real_file##n, TRUE); \
3448 } \
3449 } \
3450 while (0)
3451
3452 gboolean
3453 dview_diff_cmd (const void *f0, const void *f1)
3454 {
3455 int rv = 0;
3456 vfs_path_t *file0 = NULL;
3457 vfs_path_t *file1 = NULL;
3458 gboolean is_dir0 = FALSE;
3459 gboolean is_dir1 = FALSE;
3460
3461 switch (mc_global.mc_run_mode)
3462 {
3463 case MC_RUN_FULL:
3464 {
3465
3466 const WPanel *panel0 = (const WPanel *) f0;
3467 const WPanel *panel1 = (const WPanel *) f1;
3468 const file_entry_t *fe0, *fe1;
3469
3470 fe0 = panel_current_entry (panel0);
3471 file0 = vfs_path_append_new (panel0->cwd_vpath, fe0->fname->str, (char *) NULL);
3472 is_dir0 = S_ISDIR (fe0->st.st_mode);
3473 if (is_dir0)
3474 {
3475 message (D_ERROR, MSG_ERROR, _("\"%s\" is a directory"),
3476 path_trunc (fe0->fname->str, 30));
3477 goto ret;
3478 }
3479
3480 fe1 = panel_current_entry (panel1);
3481 file1 = vfs_path_append_new (panel1->cwd_vpath, fe1->fname->str, (char *) NULL);
3482 is_dir1 = S_ISDIR (fe1->st.st_mode);
3483 if (is_dir1)
3484 {
3485 message (D_ERROR, MSG_ERROR, _("\"%s\" is a directory"),
3486 path_trunc (fe1->fname->str, 30));
3487 goto ret;
3488 }
3489 break;
3490 }
3491
3492 case MC_RUN_DIFFVIEWER:
3493 {
3494
3495 const char *p0 = (const char *) f0;
3496 const char *p1 = (const char *) f1;
3497 struct stat st;
3498
3499 file0 = vfs_path_from_str (p0);
3500 if (mc_stat (file0, &st) == 0)
3501 {
3502 is_dir0 = S_ISDIR (st.st_mode);
3503 if (is_dir0)
3504 {
3505 message (D_ERROR, MSG_ERROR, _("\"%s\" is a directory"), path_trunc (p0, 30));
3506 goto ret;
3507 }
3508 }
3509 else
3510 {
3511 message (D_ERROR, MSG_ERROR, _("Cannot stat \"%s\"\n%s"),
3512 path_trunc (p0, 30), unix_error_string (errno));
3513 goto ret;
3514 }
3515
3516 file1 = vfs_path_from_str (p1);
3517 if (mc_stat (file1, &st) == 0)
3518 {
3519 is_dir1 = S_ISDIR (st.st_mode);
3520 if (is_dir1)
3521 {
3522 message (D_ERROR, MSG_ERROR, _("\"%s\" is a directory"), path_trunc (p1, 30));
3523 goto ret;
3524 }
3525 }
3526 else
3527 {
3528 message (D_ERROR, MSG_ERROR, _("Cannot stat \"%s\"\n%s"),
3529 path_trunc (p1, 30), unix_error_string (errno));
3530 goto ret;
3531 }
3532 break;
3533 }
3534
3535 default:
3536
3537 message (D_ERROR, MSG_ERROR, _("Diff viewer: invalid mode"));
3538 return FALSE;
3539 }
3540
3541 if (rv == 0)
3542 {
3543 rv = -1;
3544 if (file0 != NULL && file1 != NULL)
3545 {
3546 int use_copy0, use_copy1;
3547 struct stat st0, st1;
3548 vfs_path_t *real_file0, *real_file1;
3549
3550 GET_FILE_AND_STAMP (0);
3551 GET_FILE_AND_STAMP (1);
3552
3553 if (real_file0 != NULL && real_file1 != NULL)
3554 rv = diff_view (vfs_path_as_str (real_file0), vfs_path_as_str (real_file1),
3555 vfs_path_as_str (file0), vfs_path_as_str (file1));
3556
3557 UNGET_FILE (1);
3558 UNGET_FILE (0);
3559 }
3560 }
3561
3562 if (rv == 0)
3563 message (D_ERROR, MSG_ERROR, _("Two files are needed to compare"));
3564
3565 ret:
3566 vfs_path_free (file1, TRUE);
3567 vfs_path_free (file0, TRUE);
3568
3569 return (rv != 0);
3570 }
3571
3572 #undef GET_FILE_AND_STAMP
3573 #undef UNGET_FILE
3574
3575