OSDN Git Service

Bump revision to 2.16.32+-jp-2
[winmerge-jp/winmerge-jp.git] / Src / xdiff_gnudiff_compat.cpp
1 #include "pch.h"\r
2 #include "cio.h"\r
3 #include "CompareOptions.h"\r
4 extern "C" {\r
5 #include "../Externals/xdiff/xinclude.h"\r
6 }\r
7 \r
8 static bool read_mmfile(int fd, mmfile_t& mmfile)\r
9 {\r
10         cio::stat st;\r
11         if (cio::fstat(fd, &st) == -1)\r
12                 return false;\r
13         if (st.st_size < 0 || st.st_size > INT32_MAX)\r
14                 return false;\r
15         size_t sz = static_cast<size_t>(st.st_size);\r
16         mmfile.ptr = static_cast<char *>(malloc(sz ? sz : 1));\r
17         if (sz && cio::read(fd, mmfile.ptr, sz) == -1) {\r
18                 return false;\r
19         }\r
20         mmfile.size = static_cast<long>(sz);\r
21         return true;\r
22 }\r
23 \r
24 unsigned long make_xdl_flags(const DiffutilsOptions& options)\r
25 {\r
26         unsigned long xdl_flags = 0;\r
27         switch (options.m_diffAlgorithm)\r
28         {\r
29         case DIFF_ALGORITHM_MINIMAL:\r
30                 xdl_flags |= XDF_NEED_MINIMAL;\r
31                 break;\r
32         case DIFF_ALGORITHM_PATIENCE:\r
33                 xdl_flags |= XDF_PATIENCE_DIFF;\r
34                 break;\r
35         case DIFF_ALGORITHM_HISTOGRAM:\r
36                 xdl_flags |= XDF_HISTOGRAM_DIFF;\r
37                 break;\r
38         case DIFF_ALGORITHM_NONE:\r
39                 xdl_flags |= XDF_NONE_DIFF;\r
40                 break;\r
41         default:\r
42                 break;\r
43         }\r
44         if (options.m_bIgnoreCase)\r
45                 xdl_flags |= XDF_IGNORE_CASE;\r
46         if (options.m_bIgnoreNumbers)\r
47                 xdl_flags |= XDF_IGNORE_NUMBERS;\r
48         if (options.m_bIgnoreBlankLines)\r
49                 xdl_flags |= XDF_IGNORE_BLANK_LINES;\r
50         if (options.m_bIgnoreEOLDifference)\r
51                 xdl_flags |= XDF_IGNORE_CR_AT_EOL;\r
52         switch (options.m_ignoreWhitespace)\r
53         {\r
54         case WHITESPACE_IGNORE_CHANGE:\r
55                 xdl_flags |= XDF_IGNORE_WHITESPACE_CHANGE;\r
56                 break;\r
57         case WHITESPACE_IGNORE_ALL:\r
58                 xdl_flags |= XDF_IGNORE_WHITESPACE;\r
59                 break;\r
60         default:\r
61                 break;\r
62         }\r
63         if (options.m_bIndentHeuristic)\r
64                 xdl_flags |= XDF_INDENT_HEURISTIC;\r
65         return xdl_flags;\r
66 }\r
67 \r
68 static int hunk_func(long start_a, long count_a, long start_b, long count_b, void *cb_data)\r
69 {\r
70         return 0;\r
71 }\r
72 \r
73 static void append_equivs(const xdfile_t& xdf, struct file_data& filevec, std::vector<xrecord_t *>& equivs, unsigned xdl_flags)\r
74 {\r
75         std::unordered_map<unsigned long, std::vector<int>> equivs_map;\r
76         for (int i = 0; i < static_cast<int>(equivs.size()); ++i)\r
77         {\r
78                 unsigned long ha = equivs[i]->ha;\r
79                 if (equivs_map.find(ha) != equivs_map.end())\r
80                         equivs_map[ha].push_back(i);\r
81                 else\r
82                         equivs_map.emplace(ha, std::vector<int>{i});\r
83         }\r
84 \r
85         for (int i = 0; i < xdf.nrec; ++i)\r
86         {\r
87                 unsigned long ha = xdf.recs[i]->ha;\r
88                 if (equivs_map.find(ha) != equivs_map.end())\r
89                 {\r
90                         bool found = false;\r
91                         for (auto j: equivs_map[ha])\r
92                         {\r
93                                 if (xdl_recmatch(equivs[j]->ptr, equivs[j]->size, xdf.recs[i]->ptr, xdf.recs[i]->size, xdl_flags))\r
94                                 {\r
95                                         found = true;\r
96                                         filevec.equivs[i] = j;\r
97                                         equivs_map.emplace(ha, std::vector<int>{j});\r
98                                         break;\r
99                                 }\r
100                         }\r
101                         if (!found)\r
102                         {\r
103                                 filevec.equivs[i] = static_cast<int>(equivs.size());\r
104                                 equivs_map[ha].push_back(filevec.equivs[i]);\r
105                                 equivs.push_back(xdf.recs[i]);\r
106                         }\r
107                 }\r
108                 else\r
109                 {\r
110                         filevec.equivs[i] = static_cast<int>(equivs.size());\r
111                         equivs_map.emplace(ha, std::vector<int>{filevec.equivs[i]});\r
112                         equivs.push_back(xdf.recs[i]);\r
113                 }\r
114         }\r
115 }\r
116 \r
117 static int is_missing_newline(const mmfile_t& mmfile)\r
118 {\r
119         if (mmfile.size == 0 || mmfile.ptr[mmfile.size - 1] == '\r' || mmfile.ptr[mmfile.size - 1] == '\n')\r
120                 return 0;\r
121         return 1;\r
122 }\r
123 \r
124 struct change * diff_2_files_xdiff (struct file_data filevec[], int bMoved_blocks_flag, unsigned xdl_flags)\r
125 {\r
126         mmfile_t mmfile1 = { 0 }, mmfile2 = { 0 };\r
127         change *script = nullptr;\r
128         xdfenv_t xe;\r
129         xdchange_t *xscr;\r
130         xpparam_t xpp = { 0 };\r
131         xdemitconf_t xecfg = { 0 };\r
132         xdemitcb_t ecb = { 0 };\r
133 \r
134         if (!read_mmfile(filevec[0].desc, mmfile1))\r
135                 goto abort;\r
136         if (!read_mmfile(filevec[1].desc, mmfile2))\r
137                 goto abort;\r
138 \r
139         xpp.flags = xdl_flags;\r
140         xecfg.hunk_func = hunk_func;\r
141         if (xdl_diff_modified(&mmfile1, &mmfile2, &xpp, &xecfg, &ecb, &xe, &xscr) == 0)\r
142         {\r
143                 filevec[0].buffer = mmfile1.ptr;\r
144                 filevec[1].buffer = mmfile2.ptr;\r
145                 filevec[0].bufsize = mmfile1.size;\r
146                 filevec[1].bufsize = mmfile2.size;\r
147                 filevec[0].buffered_chars = mmfile1.size;\r
148                 filevec[1].buffered_chars = mmfile2.size;\r
149                 filevec[0].linbuf_base = 0;\r
150                 filevec[1].linbuf_base = 0;\r
151                 filevec[0].valid_lines = xe.xdf1.nrec;\r
152                 filevec[1].valid_lines = xe.xdf2.nrec;\r
153                 filevec[0].linbuf = static_cast<const char **>(malloc(sizeof(char *) * (xe.xdf1.nrec + 1)));\r
154                 if (!filevec[0].linbuf)\r
155                         goto abort;\r
156                 filevec[1].linbuf = static_cast<const char **>(malloc(sizeof(char *) * (xe.xdf2.nrec + 1)));\r
157                 if (!filevec[1].linbuf)\r
158                         goto abort;\r
159                 filevec[0].equivs = static_cast<int *>(malloc(sizeof(int) * xe.xdf1.nrec));\r
160                 if (!filevec[0].equivs)\r
161                         goto abort;\r
162                 filevec[1].equivs = static_cast<int *>(malloc(sizeof(int) * xe.xdf2.nrec));\r
163                 if (!filevec[1].equivs)\r
164                         goto abort;\r
165                 for (int i = 0; i < xe.xdf1.nrec; ++i)\r
166                 {\r
167                         filevec[0].linbuf[i] = xe.xdf1.recs[i]->ptr;\r
168                         filevec[0].equivs[i] = -1;\r
169                 }\r
170                 if (xe.xdf1.nrec > 0)\r
171                         filevec[0].linbuf[xe.xdf1.nrec] = xe.xdf1.recs[xe.xdf1.nrec - 1]->ptr + xe.xdf1.recs[xe.xdf1.nrec - 1]->size;\r
172                 for (int i = 0; i < xe.xdf2.nrec; ++i)\r
173                 {\r
174                         filevec[1].linbuf[i] = xe.xdf2.recs[i]->ptr;\r
175                         filevec[1].equivs[i] = -1;\r
176                 }\r
177                 if (xe.xdf2.nrec > 0)\r
178                         filevec[1].linbuf[xe.xdf2.nrec] = xe.xdf2.recs[xe.xdf2.nrec - 1]->ptr + xe.xdf2.recs[xe.xdf2.nrec - 1]->size;\r
179                 filevec[0].missing_newline = is_missing_newline(mmfile1);\r
180                 filevec[1].missing_newline = is_missing_newline(mmfile2);\r
181 \r
182                 change *prev = nullptr;\r
183                 for (xdchange_t* xcur = xscr; xcur; xcur = xcur->next)\r
184                 {\r
185                         change* e = static_cast<change*>(malloc(sizeof(change)));\r
186                         if (!e)\r
187                                 goto abort;\r
188                         if (!script)\r
189                                 script = e;\r
190                         e->line0 = xcur->i1;\r
191                         e->line1 = xcur->i2;\r
192                         e->deleted = xcur->chg1;\r
193                         e->inserted = xcur->chg2;\r
194                         e->match0 = -1;\r
195                         e->match1 = -1;\r
196                         e->trivial = static_cast<char>(xcur->ignore);\r
197                         e->link = nullptr;\r
198                         e->ignore = 0;\r
199                         if (prev)\r
200                                 prev->link = e;\r
201                         prev = e;\r
202                 }\r
203 \r
204                 if (bMoved_blocks_flag)\r
205                 {\r
206                         std::vector<xrecord_t *> equivs;\r
207                         append_equivs(xe.xdf1, filevec[0], equivs, xdl_flags);\r
208                         append_equivs(xe.xdf2, filevec[1], equivs, xdl_flags);\r
209                         moved_block_analysis(&script, filevec);\r
210                 }\r
211 \r
212                 xdl_free_script(xscr);\r
213                 xdl_free_env(&xe);\r
214         }\r
215 \r
216         return script;\r
217 \r
218 abort:\r
219         free(mmfile1.ptr);\r
220         free(mmfile2.ptr);\r
221         return nullptr;\r
222 }\r