2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27 SubHunk() : start(-1), length(0), accepted(Vng::Undecided
), added(0), removed(0) { }
29 Vng::Acceptance accepted
;
37 Private() : lineNumber(-1), ref(1), linesBefore(0), linesAfter(0)
39 SubHunk
*sh
= new SubHunk();
49 #if QT_VERSION >= 0x040400
54 int linesBefore
, linesAfter
;
56 QList
<SubHunk
*> subhunks
;
58 QByteArray
patchForAccepted(bool inverse
);
66 Hunk::Hunk(const Hunk
&other
)
69 #if QT_VERSION >= 0x040400
78 #if QT_VERSION >= 0x040400
86 void Hunk::addLine(const QByteArray
&line
)
90 if(d
->header
.isEmpty()) {
93 QRegExp
regexp("^@@ -[\\d,]+ \\+(\\d+)\\b");
94 if (regexp
.indexIn(header
) != -1)
95 d
->lineNumber
= regexp
.cap(1).toInt();
98 if (line
[0] == '\\') { // "\ No newline at end of file"
100 // check if we removed something from the last hunk and adjust its size
101 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
102 if (last
->start
+ last
->length
== d
->diff
.size())
104 d
->diff
.chop(1); // TODO should that be 2 on Windows?
108 else if (line
[0] != ' ') {
109 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
110 if (last
->start
< 0) {
111 last
->start
= d
->diff
.size();
112 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
114 else if (last
->start
+ last
->length
< d
->diff
.size()) {
115 last
= new SubHunk();
116 d
->subhunks
.append(last
);
117 last
->start
= d
->diff
.size();
118 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
120 last
->length
+=line
.length();
121 if (line
[0] == '-') {
134 d
->diff
.append(line
);
137 Hunk
& Hunk::operator=(const Hunk
&other
)
139 #if QT_VERSION >= 0x040400
141 if (! d
->ref
.deref())
151 int Hunk::lineNumber() const
153 return d
->lineNumber
;
156 int Hunk::lineNumber(int subHunk
) const
158 Q_ASSERT(subHunk
< d
->subhunks
.count());
159 SubHunk
*sh
= d
->subhunks
[subHunk
];
160 return sh
->lineNumber
;
163 QByteArray
Hunk::patch() const
168 bool Hunk::isEmpty() const
170 return d
->diff
.isEmpty();
173 Vng::Acceptance
Hunk::acceptance() const
175 Vng::Acceptance a
= Vng::Undecided
;
176 for (int i
= 0; i
< d
->subhunks
.count(); i
++) {
177 SubHunk
*sh
= d
->subhunks
[i
];
178 if (a
!= sh
->accepted
) {
179 if (a
== Vng::Undecided
)
182 return Vng::MixedAcceptance
;
188 void Hunk::setAcceptance(Vng::Acceptance acceptance
)
190 foreach(SubHunk
*sh
, d
->subhunks
)
191 sh
->accepted
= acceptance
;
194 Vng::Acceptance
Hunk::acceptance(int subHunk
) const
196 Q_ASSERT(subHunk
< d
->subhunks
.count());
197 SubHunk
*sh
= d
->subhunks
[subHunk
];
201 void Hunk::setAcceptance(int subhunk
, Vng::Acceptance accepted
)
203 Q_ASSERT(subhunk
< d
->subhunks
.count());
204 SubHunk
*sh
= d
->subhunks
[subhunk
];
205 sh
->accepted
= accepted
;
208 QByteArray
Hunk::header() const
213 QByteArray
Hunk::subHunk(int index
) const
215 if (d
->subhunks
.count() == 0)
217 Q_ASSERT(index
>= 0);
218 Q_ASSERT(index
< d
->subhunks
.count());
219 SubHunk
*sh
= d
->subhunks
[index
];
220 return d
->diff
.mid(sh
->start
, sh
->length
);
223 int Hunk::subHunkCount() const
225 return d
->subhunks
.count();
228 QByteArray
Hunk::rejectedPatch() const
230 return d
->patchForAccepted(true);
233 QByteArray
Hunk::acceptedPatch() const
235 return d
->patchForAccepted(false);
238 QByteArray
Hunk::Private::patchForAccepted(bool inverse
)
241 QDataStream
out (&patch
, QIODevice::WriteOnly
);
242 const char *myDiff
= diff
.data();
243 const char *space
= " ";
244 int offsetInDiff
= 0; // position in diff
245 int before
= linesBefore
; // for the header
246 foreach(SubHunk
*sh
, subhunks
) {
247 out
.writeRawData(myDiff
+ offsetInDiff
, sh
->start
- offsetInDiff
); // write until start
248 if ((!inverse
&& sh
->accepted
== Vng::Accepted
) || (inverse
&& sh
->accepted
!= Vng::Accepted
)) {
249 out
.writeRawData(myDiff
+ sh
->start
, sh
->length
);
252 const int end
= sh
->start
+ sh
->length
;
253 bool startOfLine
= true;
254 bool skipLine
= false;
255 int lastLineStart
= 0;
256 for (int x
= sh
->start
; x
< end
; x
++) {
259 skipLine
= (myDiff
[x
] == '-');
261 out
.writeRawData(space
, 1);
262 lastLineStart
= x
+ 1;
266 if (myDiff
[x
] == '\n') {
269 out
.writeRawData(myDiff
+ lastLineStart
, x
- lastLineStart
+ 1);
272 before
+= sh
->added
- sh
->removed
;
274 offsetInDiff
= sh
->start
+ sh
->length
;
276 Q_ASSERT(offsetInDiff
<= diff
.size());
277 out
.writeRawData(myDiff
+ offsetInDiff
, diff
.size() - offsetInDiff
);
278 if (patch
[patch
.size() -1] != '\n') {
279 const char *noNewLine
= "\n\\ No newline at end of file\n";;
280 out
.writeRawData(noNewLine
, strlen(noNewLine
));
284 QString header
= "@@ -"+ QString::number(lineNumber
) +","+ QString::number(before
)
285 +" +"+ QString::number(lineNumber
) +","+ QString::number(linesAfter
) + " @@\n";
288 answer
.append(header
.toLocal8Bit());
289 answer
.append(patch
);
293 int Hunk::linesAdded() const
296 foreach(SubHunk
*sh
, d
->subhunks
)
301 int Hunk::linesRemoved() const
304 foreach(SubHunk
*sh
, d
->subhunks
)
305 total
+= sh
->removed
;