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