Initial import of files for generating Doxygen documentation.
[ohcount] / src / diff.c
1
2 /*
3  * The bulk of this software is derived from Plan 9 and is thus distributed
4  * under the Lucent Public License, Version 1.02, reproduced below.
5  *
6  * ===================================================================
7  *
8  * Lucent Public License Version 1.02
9  *
10  * THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
11  * LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
12  * PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
13  *
14  * 1. DEFINITIONS
15  *
16  * "Contribution" means:
17  *
18  *   a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
19  *      Program, and
20  *   b. in the case of each Contributor,
21  *
22  *      i. changes to the Program, and
23  *     ii. additions to the Program;
24  *
25  *     where such changes and/or additions to the Program were added to the
26  *     Program by such Contributor itself or anyone acting on such
27  *     Contributor's behalf, and the Contributor explicitly consents, in
28  *     accordance with Section 3C, to characterization of the changes and/or
29  *     additions as Contributions.
30  *
31  * "Contributor" means LUCENT and any other entity that has Contributed a
32  * Contribution to the Program.
33  *
34  * "Distributor" means a Recipient that distributes the Program,
35  * modifications to the Program, or any part thereof.
36  *
37  * "Licensed Patents" mean patent claims licensable by a Contributor
38  * which are necessarily infringed by the use or sale of its Contribution
39  * alone or when combined with the Program.
40  *
41  * "Original Program" means the original version of the software
42  * accompanying this Agreement as released by LUCENT, including source
43  * code, object code and documentation, if any.
44  *
45  * "Program" means the Original Program and Contributions or any part
46  * thereof
47  *
48  * "Recipient" means anyone who receives the Program under this
49  * Agreement, including all Contributors.
50  *
51  * 2. GRANT OF RIGHTS
52  *
53  *  a. Subject to the terms of this Agreement, each Contributor hereby
54  *     grants Recipient a non-exclusive, worldwide, royalty-free copyright
55  *     license to reproduce, prepare derivative works of, publicly display,
56  *     publicly perform, distribute and sublicense the Contribution of such
57  *     Contributor, if any, and such derivative works, in source code and
58  *     object code form.
59  *
60  *  b. Subject to the terms of this Agreement, each Contributor hereby
61  *     grants Recipient a non-exclusive, worldwide, royalty-free patent
62  *     license under Licensed Patents to make, use, sell, offer to sell,
63  *     import and otherwise transfer the Contribution of such Contributor, if
64  *     any, in source code and object code form. The patent license granted
65  *     by a Contributor shall also apply to the combination of the
66  *     Contribution of that Contributor and the Program if, at the time the
67  *     Contribution is added by the Contributor, such addition of the
68  *     Contribution causes such combination to be covered by the Licensed
69  *     Patents. The patent license granted by a Contributor shall not apply
70  *     to (i) any other combinations which include the Contribution, nor to
71  *     (ii) Contributions of other Contributors. No hardware per se is
72  *     licensed hereunder.
73  *
74  *  c. Recipient understands that although each Contributor grants the
75  *     licenses to its Contributions set forth herein, no assurances are
76  *     provided by any Contributor that the Program does not infringe the
77  *     patent or other intellectual property rights of any other entity. Each
78  *     Contributor disclaims any liability to Recipient for claims brought by
79  *     any other entity based on infringement of intellectual property rights
80  *     or otherwise. As a condition to exercising the rights and licenses
81  *     granted hereunder, each Recipient hereby assumes sole responsibility
82  *     to secure any other intellectual property rights needed, if any. For
83  *     example, if a third party patent license is required to allow
84  *     Recipient to distribute the Program, it is Recipient's responsibility
85  *     to acquire that license before distributing the Program.
86  *
87  *  d. Each Contributor represents that to its knowledge it has sufficient
88  *     copyright rights in its Contribution, if any, to grant the copyright
89  *     license set forth in this Agreement.
90  *
91  * 3. REQUIREMENTS
92  *
93  * A. Distributor may choose to distribute the Program in any form under
94  * this Agreement or under its own license agreement, provided that:
95  *
96  *  a. it complies with the terms and conditions of this Agreement;
97  *
98  *  b. if the Program is distributed in source code or other tangible
99  *     form, a copy of this Agreement or Distributor's own license agreement
100  *     is included with each copy of the Program; and
101  *
102  *  c. if distributed under Distributor's own license agreement, such
103  *     license agreement:
104  *
105  *       i. effectively disclaims on behalf of all Contributors all warranties
106  *          and conditions, express and implied, including warranties or
107  *          conditions of title and non-infringement, and implied warranties or
108  *          conditions of merchantability and fitness for a particular purpose;
109  *      ii. effectively excludes on behalf of all Contributors all liability
110  *          for damages, including direct, indirect, special, incidental and
111  *          consequential damages, such as lost profits; and
112  *     iii. states that any provisions which differ from this Agreement are
113  *          offered by that Contributor alone and not by any other party.
114  *
115  * B. Each Distributor must include the following in a conspicuous
116  *    location in the Program:
117  *
118  *    Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
119  *    Reserved.
120  *
121  * C. In addition, each Contributor must identify itself as the
122  * originator of its Contribution in a manner that reasonably allows
123  * subsequent Recipients to identify the originator of the Contribution.
124  * Also, each Contributor must agree that the additions and/or changes
125  * are intended to be a Contribution. Once a Contribution is contributed,
126  * it may not thereafter be revoked.
127  *
128  * 4. COMMERCIAL DISTRIBUTION
129  *
130  * Commercial distributors of software may accept certain
131  * responsibilities with respect to end users, business partners and the
132  * like. While this license is intended to facilitate the commercial use
133  * of the Program, the Distributor who includes the Program in a
134  * commercial product offering should do so in a manner which does not
135  * create potential liability for Contributors. Therefore, if a
136  * Distributor includes the Program in a commercial product offering,
137  * such Distributor ("Commercial Distributor") hereby agrees to defend
138  * and indemnify every Contributor ("Indemnified Contributor") against
139  * any losses, damages and costs (collectively"Losses") arising from
140  * claims, lawsuits and other legal actions brought by a third party
141  * against the Indemnified Contributor to the extent caused by the acts
142  * or omissions of such Commercial Distributor in connection with its
143  * distribution of the Program in a commercial product offering. The
144  * obligations in this section do not apply to any claims or Losses
145  * relating to any actual or alleged intellectual property infringement.
146  * In order to qualify, an Indemnified Contributor must: a) promptly
147  * notify the Commercial Distributor in writing of such claim, and b)
148  * allow the Commercial Distributor to control, and cooperate with the
149  * Commercial Distributor in, the defense and any related settlement
150  * negotiations. The Indemnified Contributor may participate in any such
151  * claim at its own expense.
152  *
153  * For example, a Distributor might include the Program in a commercial
154  * product offering, Product X. That Distributor is then a Commercial
155  * Distributor. If that Commercial Distributor then makes performance
156  * claims, or offers warranties related to Product X, those performance
157  * claims and warranties are such Commercial Distributor's responsibility
158  * alone. Under this section, the Commercial Distributor would have to
159  * defend claims against the Contributors related to those performance
160  * claims and warranties, and if a court requires any Contributor to pay
161  * any damages as a result, the Commercial Distributor must pay those
162  * damages.
163  *
164  * 5. NO WARRANTY
165  *
166  * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
167  * PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
168  * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
169  * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
170  * OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
171  * responsible for determining the appropriateness of using and
172  * distributing the Program and assumes all risks associated with its
173  * exercise of rights under this Agreement, including but not limited to
174  * the risks and costs of program errors, compliance with applicable
175  * laws, damage to or loss of data, programs or equipment, and
176  * unavailability or interruption of operations.
177  *
178  * 6. DISCLAIMER OF LIABILITY
179  *
180  * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
181  * ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
182  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
183  * WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
184  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
185  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
186  * DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
187  * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
188  *
189  * 7. EXPORT CONTROL
190  *
191  * Recipient agrees that Recipient alone is responsible for compliance
192  * with the United States export administration regulations (and the
193  * export control laws and regulation of any other countries).
194  *
195  * 8. GENERAL
196  *
197  * If any provision of this Agreement is invalid or unenforceable under
198  * applicable law, it shall not affect the validity or enforceability of
199  * the remainder of the terms of this Agreement, and without further
200  * action by the parties hereto, such provision shall be reformed to the
201  * minimum extent necessary to make such provision valid and enforceable.
202  *
203  * If Recipient institutes patent litigation against a Contributor with
204  * respect to a patent applicable to software (including a cross-claim or
205  * counterclaim in a lawsuit), then any patent licenses granted by that
206  * Contributor to such Recipient under this Agreement shall terminate as
207  * of the date such litigation is filed. In addition, if Recipient
208  * institutes patent litigation against any entity (including a
209  * cross-claim or counterclaim in a lawsuit) alleging that the Program
210  * itself (excluding combinations of the Program with other software or
211  * hardware) infringes such Recipient's patent(s), then such Recipient's
212  * rights granted under Section 2(b) shall terminate as of the date such
213  * litigation is filed.
214  *
215  * All Recipient's rights under this Agreement shall terminate if it
216  * fails to comply with any of the material terms or conditions of this
217  * Agreement and does not cure such failure in a reasonable period of
218  * time after becoming aware of such noncompliance. If all Recipient's
219  * rights under this Agreement terminate, Recipient agrees to cease use
220  * and distribution of the Program as soon as reasonably practicable.
221  * However, Recipient's obligations under this Agreement and any licenses
222  * granted by Recipient relating to the Program shall continue and
223  * survive.
224  *
225  * LUCENT may publish new versions (including revisions) of this
226  * Agreement from time to time. Each new version of the Agreement will be
227  * given a distinguishing version number. The Program (including
228  * Contributions) may always be distributed subject to the version of the
229  * Agreement under which it was received. In addition, after a new
230  * version of the Agreement is published, Contributor may elect to
231  * distribute the Program (including its Contributions) under the new
232  * version. No one other than LUCENT has the right to modify this
233  * Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
234  * Recipient receives no rights or licenses to the intellectual property
235  * of any Contributor under this Agreement, whether expressly, by
236  * implication, estoppel or otherwise. All rights in the Program not
237  * expressly granted under this Agreement are reserved.
238  *
239  * This Agreement is governed by the laws of the State of New York and
240  * the intellectual property laws of the United States of America. No
241  * party to this Agreement will bring a legal action under this Agreement
242  * more than one year after the cause of action arose. Each party waives
243  * its rights to a jury trial in any resulting litigation.
244  */
245
246 #include <stdlib.h>
247 #include <string.h>
248
249 #include "diff.h"
250
251 struct cand {
252   int x;
253   int y;
254   int pred;
255 } cand;
256
257 struct line {
258   int serial;
259   int value;
260 } *file[2], line;
261
262 int len[2];
263 struct line *sfile[2];  // shortened by pruning common prefix and suffix
264 int slen[2];
265 int pref, suff; // length of prefix and suffix
266 int *class; // will be overlaid on file[0]
267 int *member; // will be overlaid on file[1]
268 int *klist; // will be overlaid on file[0] after class
269 struct cand *clist; // merely a free storage pot for candidates
270 int clen;
271 int *J; // will be overlaid on class
272
273 #define HALFLONG 16
274 #define low(x)  (x&((1L<<HALFLONG)-1))
275 #define high(x) (x>>HALFLONG)
276
277 /**
278  * Returns a computed hash for a given string.
279  * Hashing has the effect of arranging line in 7-bit bytes and then summing 1-s
280  * complement in 16-bit hunks.
281  * @param line The line of a buffer to hash.
282  */
283 static int hash(char *line) {
284   long sum;
285   unsigned shift;
286   char *p;
287   int len;
288
289   sum = 1;
290   shift = 0;
291   len = strlen(line);
292   p = line;
293   while (len--) {
294     sum += (long)*p++ << (shift &= (HALFLONG-1));
295     shift += 7;
296   }
297   sum = low(sum) + high(sum);
298   return ((short)low(sum) + (short)high(sum));
299 }
300
301 /**
302  * Hashes each line in the given string buffer and stores it internally.
303  * @param i 0 for diff 'from', 1 for diff 'to'.
304  * @param buf The string buffer to prepare from.
305  */
306 void prepare(int i, const char *buf) {
307   struct line *p;
308   int j;
309   char bufcpy[strlen(buf)];
310   char *l;
311
312   p = malloc(3*sizeof(struct line));
313   j = 0;
314   strncpy(bufcpy, buf, strlen(buf));
315   bufcpy[strlen(buf)] = 0;
316   l = strtok(bufcpy, "\n");
317   while (l) {
318     p = realloc(p, (++j+3)*sizeof(struct line));
319     p[j].value = hash(l);
320     l = strtok(NULL, "\n");
321   }
322   len[i] = j;
323   file[i] = p;
324 }
325
326 /**
327  * Adds to the count of lines added and removed for this diff.
328  * Diff 'from' chunks are counted as lines removed and diff 'to' chunks are
329  * counted as lines added.
330  * @param a The diff 'from' chunk's beginning line number.
331  * @param b The diff 'from' chunk's ending line number.
332  * @param c The diff 'to' chunk's beginning line number.
333  * @param d The diff 'to' chunk's ending line number.
334  * @param added Int pointer to the running number of lines added for this diff.
335  * @param removed Int pointer to the running number of lines removed for this
336  *   diff.
337  */
338 void change(int a, int b, int c, int d, int *added, int *removed) {
339   if (a > b && c > d)
340     return;
341
342   if(a <= 1)
343     a = 1;
344   if(b > len[0])
345     b = len[0];
346   if(a <= b)
347     *removed += b - a + 1;
348
349   if(c <= 1)
350     c = 1;
351   if(d > len[1])
352     d = len[1];
353   if(c <= d)
354     *added += d - c + 1;
355 }
356
357 /*
358  * diff - differential file comparison
359  *
360  * Uses an algorithm due to Harold Stone, which finds
361  * a pair of longest identical subsequences in the two
362  * files.
363  *
364  * The major goal is to generate the match vector J.
365  * J[i] is the index of the line in file1 corresponding
366  * to line i file0. J[i] = 0 if there is no
367  * such line in file1.
368  *
369  * Lines are hashed so as to work in core. All potential
370  * matches are located by sorting the lines of each file
371  * on the hash (called value). In particular, this
372  * collects the equivalence classes in file1 together.
373  * Subroutine equiv replaces the value of each line in
374  * file0 by the index of the first element of its
375  * matching equivalence in (the reordered) file1.
376  * To save space equiv squeezes file1 into a single
377  * array member in which the equivalence classes
378  * are simply concatenated, except that their first
379  * members are flagged by changing sign.
380  *
381  * Next the indices that point into member are unsorted into
382  * array class according to the original order of file0.
383  *
384  * The cleverness lies in routine stone. This marches
385  * through the lines of file0, developing a vector klist
386  * of "k-candidates". At step i a k-candidate is a matched
387  * pair of lines x,y (x in file0 y in file1) such that
388  * there is a common subsequence of lenght k
389  * between the first i lines of file0 and the first y
390  * lines of file1, but there is no such subsequence for
391  * any smaller y. x is the earliest possible mate to y
392  * that occurs in such a subsequence.
393  *
394  * Whenever any of the members of the equivalence class of
395  * lines in file1 matable to a line in file0 has serial number
396  * less than the y of some k-candidate, that k-candidate
397  * with the smallest such y is replaced. The new
398  * k-candidate is chained (via pred) to the current
399  * k-1 candidate so that the actual subsequence can
400  * be recovered. When a member has serial number greater
401  * that the y of all k-candidates, the klist is extended.
402  * At the end, the longest subsequence is pulled out
403  * and placed in the array J by unravel.
404  *
405  * With J in hand, the matches there recorded are
406  * check'ed against reality to assure that no spurious
407  * matches have crept in due to hashing. If they have,
408  * they are broken, and "jackpot " is recorded--a harmless
409  * matter except that a true match for a spuriously
410  * mated line may now be unnecessarily reported as a change.
411  *
412  * Much of the complexity of the program comes simply
413  * from trying to minimize core utilization and
414  * maximize the range of doable problems by dynamically
415  * allocating what is needed and reusing what is not.
416  * The core requirements for problems larger than somewhat
417  * are (in words) 2*length(file0) + length(file1) +
418  * 3*(number of k-candidates installed),  typically about
419  * 6n words for files of length n.
420  */
421
422 static void sort(struct line *a, int n) { /*shellsort CACM #201*/
423   int m;
424   struct line *ai, *aim, *j, *k;
425   struct line w;
426   int i;
427
428   m = 0;
429   for (i = 1; i <= n; i *= 2)
430     m = 2*i - 1;
431   for (m /= 2; m != 0; m /= 2) {
432     k = a+(n-m);
433     for (j = a+1; j <= k; j++) {
434       ai = j;
435       aim = ai+m;
436       do {
437         if (aim->value > ai->value ||
438            aim->value == ai->value &&
439            aim->serial > ai->serial)
440           break;
441         w = *ai;
442         *ai = *aim;
443         *aim = w;
444
445         aim = ai;
446         ai -= m;
447       } while (ai > a && aim >= ai);
448     }
449   }
450 }
451
452 static void unsort(struct line *f, int l, int *b) {
453   int *a;
454   int i;
455
456   a = malloc((l+1)*sizeof(int));
457   for(i=1;i<=l;i++)
458     a[f[i].serial] = f[i].value;
459   for(i=1;i<=l;i++)
460     b[i] = a[i];
461   free(a);
462 }
463
464 static void prune(void) {
465   int i, j;
466
467   for(pref=0;pref<len[0]&&pref<len[1]&&
468     file[0][pref+1].value==file[1][pref+1].value;
469     pref++ ) ;
470   for(suff=0;suff<len[0]-pref&&suff<len[1]-pref&&
471     file[0][len[0]-suff].value==file[1][len[1]-suff].value;
472     suff++) ;
473   for(j=0;j<2;j++) {
474     sfile[j] = file[j]+pref;
475     slen[j] = len[j]-pref-suff;
476     for(i=0;i<=slen[j];i++)
477       sfile[j][i].serial = i;
478   }
479 }
480
481 static void equiv(struct line *a, int n, struct line *b, int m, int *c) {
482   int i, j;
483
484   i = j = 1;
485   while(i<=n && j<=m) {
486     if(a[i].value < b[j].value)
487       a[i++].value = 0;
488     else if(a[i].value == b[j].value)
489       a[i++].value = j;
490     else
491       j++;
492   }
493   while(i <= n)
494     a[i++].value = 0;
495   b[m+1].value = 0;
496   j = 0;
497   while(++j <= m) {
498     c[j] = -b[j].serial;
499     while(b[j+1].value == b[j].value) {
500       j++;
501       c[j] = b[j].serial;
502     }
503   }
504   c[j] = -1;
505 }
506
507 static int newcand(int x, int  y, int pred) {
508   struct cand *q;
509
510   clist = realloc(clist, (clen+1)*sizeof(struct cand));
511   q = clist + clen;
512   q->x = x;
513   q->y = y;
514   q->pred = pred;
515   return clen++;
516 }
517
518 static int search(int *c, int k, int y) {
519   int i, j, l;
520   int t;
521
522   if(clist[c[k]].y < y)   /*quick look for typical case*/
523     return k+1;
524   i = 0;
525   j = k+1;
526   while((l=(i+j)/2) > i) {
527     t = clist[c[l]].y;
528     if(t > y)
529       j = l;
530     else if(t < y)
531       i = l;
532     else
533       return l;
534   }
535   return l+1;
536 }
537
538 static int stone(int *a, int n, int *b, int *c) {
539   int i, k, y;
540   int j, l;
541   int oldc, tc;
542   int oldl;
543
544   k = 0;
545   c[0] = newcand(0,0,0);
546   for(i=1; i<=n; i++) {
547     j = a[i];
548     if(j==0)
549       continue;
550     y = -b[j];
551     oldl = 0;
552     oldc = c[0];
553     do {
554       if(y <= clist[oldc].y)
555         continue;
556       l = search(c, k, y);
557       if(l!=oldl+1)
558         oldc = c[l-1];
559       if(l<=k) {
560         if(clist[c[l]].y <= y)
561           continue;
562         tc = c[l];
563         c[l] = newcand(i,y,oldc);
564         oldc = tc;
565         oldl = l;
566       } else {
567         c[l] = newcand(i,y,oldc);
568         k++;
569         break;
570       }
571     } while((y=b[++j]) > 0);
572   }
573   return k;
574 }
575
576 static void unravel(int p) {
577   int i;
578   struct cand *q;
579
580   for(i=0; i<=len[0]; i++) {
581     if (i <= pref)
582       J[i] = i;
583     else if (i > len[0]-suff)
584       J[i] = i+len[1]-len[0];
585     else
586       J[i] = 0;
587   }
588   for(q=clist+p;q->y!=0;q=clist+q->pred)
589     J[q->x+pref] = q->y+pref;
590 }
591
592 static void output(int *added, int *removed) {
593   int m, i0, i1, j0, j1;
594
595   m = len[0];
596   J[0] = 0;
597   J[m+1] = len[1]+1;
598   for (i0 = 1; i0 <= m; i0 = i1+1) {
599     while (i0 <= m && J[i0] == J[i0-1]+1)
600       i0++;
601     j0 = J[i0-1]+1;
602     i1 = i0-1;
603     while (i1 < m && J[i1+1] == 0)
604       i1++;
605     j1 = J[i1+1]-1;
606     J[i1] = j1;
607     change(i0, i1, j0, j1, added, removed);
608   }
609   if (m == 0)
610     change(1, 0, 1, len[1], added, removed);
611 }
612
613 void ohcount_calc_diff(const char *from, const char *to, int *added,
614                        int *removed) {
615   int k;
616
617   prepare(0, from);
618   prepare(1, to);
619   clen = 0;
620   prune();
621   sort(sfile[0], slen[0]);
622   sort(sfile[1], slen[1]);
623
624   member = (int *)file[1];
625   equiv(sfile[0], slen[0], sfile[1], slen[1], member);
626   member = realloc(member, (slen[1]+2)*sizeof(int));
627
628   class = (int *)file[0];
629   unsort(sfile[0], slen[0], class);
630   class = realloc(class, (slen[0]+2)*sizeof(int));
631
632   klist = malloc((slen[0]+2)*sizeof(int));
633   clist = malloc(sizeof(struct cand));
634   k = stone(class, slen[0], member, klist);
635   free(member);
636   free(class);
637
638   J = malloc((len[0]+2)*sizeof(int));
639   unravel(klist[k]);
640   free(clist);
641   free(klist);
642
643   *added = *removed = 0;
644   output(added, removed);
645   free(J);
646 }