OSDN Git Service

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