1 /*
2 Numdiff - compare putatively similar files,
3 ignoring small numeric differences
4 Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Ivano Primi <ivprimi@libero.it>
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include"numdiff.h"
21 #include<xalloc.h>
22
23 /* Constants and default values */
24 #define CHUNK_ALLOC 20480
25
26 static flg_array internal_table;
27
28 /*
29 `table' must be the address of a `flg_array' structure.
30 */
init_flg_array(flg_array * table)31 static int init_flg_array (flg_array* table)
32 {
33 if ((table))
34 {
35 table->ptr = NULL;
36 table->size = table->len = 0;
37 return 0;
38 }
39 else
40 return -1;
41 }
42
init_flags(void)43 int init_flags (void)
44 {
45 return init_flg_array (&internal_table);
46 }
47
48 /*
49 `table' must be the address of a `flg_array' structure.
50 */
print_flg_array(FILE * fp,const flg_array * table)51 static int print_flg_array (FILE* fp, const flg_array* table)
52 {
53 size_t n;
54 unsigned short i;
55 unsigned char byte, elem;
56
57 if (!table || !table->ptr)
58 return (fputs (_("<The array is empty>\n"), fp) == EOF);
59 else
60 {
61 int outerror = 0;
62
63 for (n = 0; !outerror && n < table->len; n += 4U)
64 {
65 byte = table->ptr[n/4U];
66 for (i = 0; i < 4U; i++)
67 {
68 if ( (elem = (byte & 0x03 << 2*i) >> 2 * i) )
69 {
70 if ( fprintf (fp, "%u", elem) < 0 )
71 {
72 outerror = 1;
73 break;
74 }
75 }
76 else
77 break;
78 }
79 }
80 if (!outerror)
81 outerror = (fputc ('\n', fp) == EOF);
82 return outerror;
83 }
84 }
85
print_flags(FILE * fp)86 int print_flags (FILE* fp)
87 {
88 return print_flg_array (fp, &internal_table);
89 }
90
91 /*
92 array must be the address of a `flg_array' structure.
93 */
addnewelem(flg_array * array,unsigned char elem)94 static void addnewelem (flg_array* array, unsigned char elem)
95 {
96 if (!array)
97 return;
98 if ( !array->ptr )
99 {
100 array->ptr = xcalloc (CHUNK_ALLOC, sizeof (unsigned char));
101 array->size = CHUNK_ALLOC;
102 array->ptr[0] = elem;
103 array->len = 1;
104 #ifdef __MEMDEBUG__
105 fprintf (stderr, "size = %6zu, len = %6zu, string:",
106 array->size, array->len);
107 print_flg_array (stderr, array);
108 #endif
109 }
110 else
111 {
112 if (array->len == 4 * array->size - 1)
113 {
114 unsigned char* p;
115
116 array->ptr = xrealloc (array->ptr, array->size + CHUNK_ALLOC);
117 array->size += CHUNK_ALLOC;
118 array->ptr[array->len / 4U] |= elem << 2 * (array->len % 4U);
119 array->len++; /* Now array->len == 4 * array->"old"size */
120 for (p = array->ptr + array->len / 4; p < array->ptr + array->size; *p = 0, p++);
121 #ifdef __MEMDEBUG__
122 fprintf (stderr, "size = %6zu, len = %6zu, string:",
123 array->size, array->len);
124 print_flg_array (stderr, array);
125 #endif
126 }
127 else
128 {
129 array->ptr[array->len / 4U] |= elem << 2 * (array->len % 4U);
130 array->len++;
131 #ifdef __MEMDEBUG__
132 fprintf (stderr, "size = %6zu, len = %6zu, string:",
133 array->size, array->len);
134 print_flg_array (stderr, array);
135 #endif
136 }
137 }
138 }
139
copy_of_intflagtab(void)140 flg_array copy_of_intflagtab (void)
141 {
142 return internal_table;
143 }
144
145 /*
146 array must be the address of a `flg_array' structure.
147 */
destroy_flg_array(flg_array * array)148 static void destroy_flg_array (flg_array* array)
149 {
150 if ((array) && (array->ptr))
151 {
152 free ((void*)array->ptr);
153 array->ptr = NULL;
154 array->size = array->len = 0;
155 }
156 }
157
erase_flags(void)158 void erase_flags (void)
159 {
160 destroy_flg_array (&internal_table);
161 }
162
163 static void notedown_sdiff_common_lines (lin, lin);
164 static void notedown_sdiff_hunk (struct change *);
165
166 /* Next line number to be printed in the two input files. */
167 static lin next0, next1;
168
169 /*
170 * Note down the edit-script SCRIPT in the INTERNAL_TABLE.
171 */
172
173 void
notedown_sdiff_script(struct change * script)174 notedown_sdiff_script (struct change *script)
175 {
176 next0 = next1 = - files[0].prefix_lines;
177 print_script (script, notedown_sdiff_hunk);
178
179 notedown_sdiff_common_lines (files[0].valid_lines, files[1].valid_lines);
180 #ifdef _DEBUG_FLAGSTABLE_
181 print_flg_array (stderr, &internal_table);
182 #endif
183 }
184
185 /* Print lines common to both files in side-by-side format. */
186 static void
notedown_sdiff_common_lines(lin limit0,lin limit1)187 notedown_sdiff_common_lines (lin limit0, lin limit1)
188 {
189 lin i0 = next0, i1 = next1;
190
191 if (i0 != limit0 || i1 != limit1)
192 {
193 for (; i0 != limit0 && i1 != limit1; i0++, i1++)
194 addnewelem (&internal_table, 3);
195
196 for (; i1 != limit1; i1++)
197 addnewelem (&internal_table, 2);
198
199 for (; i0 != limit0; i0++)
200 addnewelem (&internal_table, 1);
201 }
202
203 next0 = limit0;
204 next1 = limit1;
205 }
206
207 /* Note down a hunk of an sdiff diff.
208 This is a contiguous portion of a complete edit script,
209 describing changes in consecutive lines. */
210
211 static void
notedown_sdiff_hunk(struct change * hunk)212 notedown_sdiff_hunk (struct change *hunk)
213 {
214 lin first0, last0, first1, last1;
215 register lin i, j;
216
217 /* Determine range of line numbers involved in each file. */
218 enum changes changes =
219 analyze_hunk (hunk, &first0, &last0, &first1, &last1);
220 if (!changes)
221 return;
222
223 /* Note down lines up to this change. */
224 notedown_sdiff_common_lines (first0, first1);
225
226 /* Note down ``xxx | xxx '' lines */
227 if (changes == CHANGED)
228 {
229 for (i = first0, j = first1; i <= last0 && j <= last1; i++, j++)
230 addnewelem (&internal_table, 3);
231 changes = (i <= last0 ? OLD : 0) + (j <= last1 ? NEW : 0);
232 next0 = first0 = i;
233 next1 = first1 = j;
234 }
235
236 /* Note down `` > xxx '' lines */
237 if (changes & NEW)
238 {
239 for (j = first1; j <= last1; ++j)
240 addnewelem (&internal_table, 2);
241 next1 = j;
242 }
243
244 /* Note down ``xxx < '' lines */
245 if (changes & OLD)
246 {
247 for (i = first0; i <= last0; ++i)
248 addnewelem (&internal_table, 1);
249 next0 = i;
250 }
251 }
252