-
Notifications
You must be signed in to change notification settings - Fork 8
/
wiggle.h
217 lines (198 loc) · 6.75 KB
/
wiggle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/*
* wiggle - apply rejected patches
*
* Copyright (C) 2003-2013 Neil Brown <[email protected]>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* Author: Neil Brown
* Email: <[email protected]>
*/
#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <string.h>
#include <memory.h>
#include <getopt.h>
#include <stdlib.h>
static inline void assert(int a)
{
if (!a)
abort();
}
struct stream {
char *body;
int len;
};
/* an 'elmnt' is a word or a line from the file.
* 'start' points into a 'body' in a stream.
* When a stream is made of 'diff' hunks, there is a special
* elmnt at the start of each hunk which starts with '\0' and
* records the line offsets of the hunk. These are 20+ bytes long.
* "\0\d{5} \d{5} \d{5}{SP funcname}?\n\0"
* The 3 numbers are: chunk number, starting line, number of lines.
* An element with len==0 marks EOF.
*/
struct elmnt {
char *start;
int hash;
short len, plen, prefix;
};
static inline int match(struct elmnt *a, struct elmnt *b)
{
return
a->hash == b->hash &&
((a->start[0] == 0 && b->start[0] == 0)
||
(a->len == b->len &&
strncmp(a->start, b->start, a->len) == 0));
}
/* end-of-line is important for narrowing conflicts.
* In line mode, every element is a line and 'ends a line'
* In word mode, the newline element and the diff-hunk element
* end a line.
*/
static inline int ends_line(struct elmnt e)
{
if (e.len >= 20 && e.start[0] == 0)
return 1;
return e.len && e.start[e.plen-1] == '\n';
}
struct csl {
int a, b;
int len;
};
struct file {
struct elmnt *list;
int elcnt;
};
/* The result of a merger is a series of text sections.
* Each section may occur in one or more of the three stream,
* and may be different in different stream (e.g. for changed text)
* or the same.
* When a conflict occurs we need to treat some surrounding
* sections as being involved in that conflict. For
* line-based merging, all surrounding sections until an Unchanged
* section are part of the conflict - the Unchanged isn't.
* For word-based merging, we need to find Unchanged sections
* that include a newline. Further, text within the unchanged
* section upto the newline (in whichever direction) is treated
* as part of the whole conflict.
* Actually... it is possibly for a 'Changed' section to bound
* a conflict as it indicates a successful match of A and B.
* For line-wise merges, any Changed or Unchanged section bounds a conflict
* For word-wise merges, any Changed or Unchanged section that matches
* a newline, or immediately follows a newline (in all files) can bound
* a conflict.
*/
struct merge {
enum mergetype {
End, Unmatched, Unchanged, Extraneous,
Changed, Conflict, AlreadyApplied,
} type, oldtype;
int a, b, c; /* start of ranges */
int al, bl, cl; /* length of ranges */
int c1, c2; /* this or next common-sequence */
int in_conflict;
int lo, hi; /* region of a Changed or Unchanged that is not involved
* in a conflict.
* These are distances from start of the "before" section,
* not indexes into any file.
*/
};
/* plist stores a list of patched files in an array
* Each entry identifies a file, the range of the
* original patch which applies to this file, some
* statistics concerning how many conflicts etc, and
* some linkage information so the list can be viewed
* as a directory-tree.
*/
struct plist {
char *file, *outfile;
unsigned int start, end;
int parent;
int next, prev, last;
int open;
int chunks, wiggles, conflicts;
int calced;
int is_merge;
char *before, *after;
};
extern struct plist *wiggle_sort_patches(struct plist *pl, int *np);
extern void wiggle_plist_free(struct plist *pl, int num);
extern struct plist *wiggle_parse_patch(FILE *f, FILE *of, int *np);
extern struct stream wiggle_load_segment(FILE *f, unsigned int start,
unsigned int end);
extern int wiggle_set_prefix(struct plist *pl, int n, int strip);
extern struct stream wiggle_load_file(char *name);
extern int wiggle_split_patch(struct stream, struct stream*, struct stream*);
extern int wiggle_split_merge(struct stream, struct stream*, struct stream*,
struct stream*);
extern struct file wiggle_split_stream(struct stream s, int type);
extern struct csl *wiggle_pdiff(struct file a, struct file b, int chunks);
extern struct csl *wiggle_diff(struct file a, struct file b, int shortest);
extern struct csl *wiggle_diff_patch(struct file a, struct file b, int shortest);
extern struct csl *wiggle_diff_partial(struct file a, struct file b,
int alo, int ahi, int blo, int bhi);
extern struct csl *worddiff(struct stream f1, struct stream f2,
struct file *fl1p, struct file *fl2p);
extern struct csl *wiggle_csl_join(struct csl *c1, struct csl *c2);
struct ci {
int conflicts, wiggles, ignored;
struct merge *merger;
};
extern int wiggle_print_merge(FILE *out,
struct file *a, struct file *b, struct file *c,
int words, struct merge *merger,
struct merge *mpos, int streampos, int offsetpos);
extern void wiggle_printword(FILE *f, struct elmnt e);
extern int wiggle_isolate_conflicts(struct file af, struct file bf, struct file cf,
struct csl *csl1, struct csl *csl2, int words,
struct merge *m, int show_wiggles, int *wigglesp);
extern struct ci wiggle_make_merger(struct file a, struct file b, struct file c,
struct csl *c1, struct csl *c2, int words,
int ignore_already, int show_wiggles);
extern void wiggle_die(char *reason);
extern void wiggle_check_dir(char *name, int fd);
extern void *wiggle_xmalloc(int len);
extern int wiggle_do_trace;
extern int vpatch(int argc, char *argv[], int patch, int strip,
int reverse, int replace, char *outfile,
int selftest,
int ignore_blanks, int backup);
extern char *wiggle_Cmd;
extern char Version[];
extern char short_options[];
extern struct option long_options[];
enum other_options {
SELF_TEST = 300,
REPORT_WIGGLES,
NO_BACKUP,
NON_SPACE,
SHORTEST,
};
extern char Usage[];
extern char Help[];
extern char HelpExtract[];
extern char HelpDiff[];
extern char HelpMerge[];
extern char HelpBrowse[];
extern void cleanlist(struct file a, struct file b, struct csl *list);
enum {
ByLine = 0,
ByWord = 1,
ByMask = 3,
IgnoreBlanks = 8, /* 'or'ed in */
WholeWord = 16,
};