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