2 * LibXDiff by Davide Libenzi ( File Differential Library )
3 * Copyright (C) 2003 Davide Libenzi
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
19 * Davide Libenzi <davidel@xmailserver.org>
25 static long xdl_get_rec(xdfile_t
*xdf
, long ri
, char const **rec
) {
27 *rec
= xdf
->recs
[ri
]->ptr
;
29 return xdf
->recs
[ri
]->size
;
33 static int xdl_emit_record(xdfile_t
*xdf
, long ri
, char const *pre
, xdemitcb_t
*ecb
) {
34 long size
, psize
= strlen(pre
);
37 size
= xdl_get_rec(xdf
, ri
, &rec
);
38 if (xdl_emit_diffrec(rec
, size
, pre
, psize
, ecb
) < 0) {
48 * Starting at the passed change atom, find the latest change atom to be included
49 * inside the differential hunk according to the specified configuration.
50 * Also advance xscr if the first changes must be discarded.
52 xdchange_t
*xdl_get_hunk(xdchange_t
**xscr
, xdemitconf_t
const *xecfg
)
54 xdchange_t
*xch
, *xchp
, *lxch
;
55 long max_common
= 2 * xecfg
->ctxlen
+ xecfg
->interhunkctxlen
;
56 long max_ignorable
= xecfg
->ctxlen
;
57 unsigned long ignored
= 0; /* number of ignored blank lines */
59 /* remove ignorable changes that are too far before other changes */
60 for (xchp
= *xscr
; xchp
&& xchp
->ignore
; xchp
= xchp
->next
) {
64 xch
->i1
- (xchp
->i1
+ xchp
->chg1
) >= max_ignorable
)
73 for (xchp
= *xscr
, xch
= xchp
->next
; xch
; xchp
= xch
, xch
= xch
->next
) {
74 long distance
= xch
->i1
- (xchp
->i1
+ xchp
->chg1
);
75 if (distance
> max_common
)
78 if (distance
< max_ignorable
&& (!xch
->ignore
|| lxch
== xchp
)) {
81 } else if (distance
< max_ignorable
&& xch
->ignore
) {
83 } else if (lxch
!= xchp
&&
84 xch
->i1
+ ignored
- (lxch
->i1
+ lxch
->chg1
) > max_common
) {
86 } else if (!xch
->ignore
) {
98 static long def_ff(const char *rec
, long len
, char *buf
, long sz
, void *priv
)
101 (isalpha((unsigned char)*rec
) || /* identifier? */
102 *rec
== '_' || /* also identifier? */
103 *rec
== '$')) { /* identifiers from VMS and other esoterico */
106 while (0 < len
&& isspace((unsigned char)rec
[len
- 1]))
108 memcpy(buf
, rec
, len
);
114 static long match_func_rec(xdfile_t
*xdf
, xdemitconf_t
const *xecfg
, long ri
,
118 long len
= xdl_get_rec(xdf
, ri
, &rec
);
119 if (!xecfg
->find_func
)
120 return def_ff(rec
, len
, buf
, sz
, xecfg
->find_func_priv
);
121 return xecfg
->find_func(rec
, len
, buf
, sz
, xecfg
->find_func_priv
);
124 static int is_func_rec(xdfile_t
*xdf
, xdemitconf_t
const *xecfg
, long ri
)
127 return match_func_rec(xdf
, xecfg
, ri
, dummy
, sizeof(dummy
)) >= 0;
135 static long get_func_line(xdfenv_t
*xe
, xdemitconf_t
const *xecfg
,
136 struct func_line
*func_line
, long start
, long limit
)
138 long l
, size
, step
= (start
> limit
) ? -1 : 1;
141 buf
= func_line
? func_line
->buf
: dummy
;
142 size
= func_line
? sizeof(func_line
->buf
) : sizeof(dummy
);
144 for (l
= start
; l
!= limit
&& 0 <= l
&& l
< xe
->xdf1
.nrec
; l
+= step
) {
145 long len
= match_func_rec(&xe
->xdf1
, xecfg
, l
, buf
, size
);
148 func_line
->len
= len
;
155 static int is_empty_rec(xdfile_t
*xdf
, long ri
)
158 long len
= xdl_get_rec(xdf
, ri
, &rec
);
160 while (len
> 0 && XDL_ISSPACE(*rec
)) {
167 int xdl_emit_diff(xdfenv_t
*xe
, xdchange_t
*xscr
, xdemitcb_t
*ecb
,
168 xdemitconf_t
const *xecfg
) {
169 long s1
, s2
, e1
, e2
, lctx
;
170 xdchange_t
*xch
, *xche
;
171 long funclineprev
= -1;
172 struct func_line func_line
= { 0 };
174 for (xch
= xscr
; xch
; xch
= xche
->next
) {
175 xdchange_t
*xchp
= xch
;
176 xche
= xdl_get_hunk(&xch
, xecfg
);
180 pre_context_calculation
:
181 s1
= XDL_MAX(xch
->i1
- xecfg
->ctxlen
, 0);
182 s2
= XDL_MAX(xch
->i2
- xecfg
->ctxlen
, 0);
184 if (xecfg
->flags
& XDL_EMIT_FUNCCONTEXT
) {
185 long fs1
, i1
= xch
->i1
;
187 /* Appended chunk? */
188 if (i1
>= xe
->xdf1
.nrec
) {
192 * We don't need additional context if
193 * a whole function was added.
195 while (i2
< xe
->xdf2
.nrec
) {
196 if (is_func_rec(&xe
->xdf2
, xecfg
, i2
))
197 goto post_context_calculation
;
202 * Otherwise get more context from the
205 i1
= xe
->xdf1
.nrec
- 1;
208 fs1
= get_func_line(xe
, xecfg
, NULL
, i1
, -1);
209 while (fs1
> 0 && !is_empty_rec(&xe
->xdf1
, fs1
- 1) &&
210 !is_func_rec(&xe
->xdf1
, xecfg
, fs1
- 1))
215 s2
= XDL_MAX(s2
- (s1
- fs1
), 0);
219 * Did we extend context upwards into an
222 while (xchp
!= xch
&&
223 xchp
->i1
+ xchp
->chg1
<= s1
&&
224 xchp
->i2
+ xchp
->chg2
<= s2
)
227 /* If so, show it after all. */
230 goto pre_context_calculation
;
235 post_context_calculation
:
236 lctx
= xecfg
->ctxlen
;
237 lctx
= XDL_MIN(lctx
, xe
->xdf1
.nrec
- (xche
->i1
+ xche
->chg1
));
238 lctx
= XDL_MIN(lctx
, xe
->xdf2
.nrec
- (xche
->i2
+ xche
->chg2
));
240 e1
= xche
->i1
+ xche
->chg1
+ lctx
;
241 e2
= xche
->i2
+ xche
->chg2
+ lctx
;
243 if (xecfg
->flags
& XDL_EMIT_FUNCCONTEXT
) {
244 long fe1
= get_func_line(xe
, xecfg
, NULL
,
245 xche
->i1
+ xche
->chg1
,
247 while (fe1
> 0 && is_empty_rec(&xe
->xdf1
, fe1
- 1))
252 e2
= XDL_MIN(e2
+ (fe1
- e1
), xe
->xdf2
.nrec
);
257 * Overlap with next change? Then include it
258 * in the current hunk and start over to find
262 long l
= XDL_MIN(xche
->next
->i1
,
264 if (l
- xecfg
->ctxlen
<= e1
||
265 get_func_line(xe
, xecfg
, NULL
, l
, e1
) < 0) {
267 goto post_context_calculation
;
273 * Emit current hunk header.
276 if (xecfg
->flags
& XDL_EMIT_FUNCNAMES
) {
277 get_func_line(xe
, xecfg
, &func_line
,
278 s1
- 1, funclineprev
);
279 funclineprev
= s1
- 1;
281 if (!(xecfg
->flags
& XDL_EMIT_NO_HUNK_HDR
) &&
282 xdl_emit_hunk_hdr(s1
+ 1, e1
- s1
, s2
+ 1, e2
- s2
,
283 func_line
.buf
, func_line
.len
, ecb
) < 0)
289 for (; s2
< xch
->i2
; s2
++)
290 if (xdl_emit_record(&xe
->xdf2
, s2
, " ", ecb
) < 0)
293 for (s1
= xch
->i1
, s2
= xch
->i2
;; xch
= xch
->next
) {
295 * Merge previous with current change atom.
297 for (; s1
< xch
->i1
&& s2
< xch
->i2
; s1
++, s2
++)
298 if (xdl_emit_record(&xe
->xdf2
, s2
, " ", ecb
) < 0)
302 * Removes lines from the first file.
304 for (s1
= xch
->i1
; s1
< xch
->i1
+ xch
->chg1
; s1
++)
305 if (xdl_emit_record(&xe
->xdf1
, s1
, "-", ecb
) < 0)
309 * Adds lines from the second file.
311 for (s2
= xch
->i2
; s2
< xch
->i2
+ xch
->chg2
; s2
++)
312 if (xdl_emit_record(&xe
->xdf2
, s2
, "+", ecb
) < 0)
317 s1
= xch
->i1
+ xch
->chg1
;
318 s2
= xch
->i2
+ xch
->chg2
;
324 for (s2
= xche
->i2
+ xche
->chg2
; s2
< e2
; s2
++)
325 if (xdl_emit_record(&xe
->xdf2
, s2
, " ", ecb
) < 0)