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/>.
26 SubHunk() : start(-1), length(0), accepted(Vng::Undecided
), added(0), removed(0) { }
28 Vng::Acceptance accepted
;
35 Private() : lineNumber(-1), ref(1), linesBefore(0), linesAfter(0)
37 SubHunk
*sh
= new SubHunk();
47 #if QT_VERSION >= 0x040400
52 int linesBefore
, linesAfter
;
54 QList
<SubHunk
*> subhunks
;
56 QByteArray
patchForAccepted(bool inverse
);
64 Hunk::Hunk(const Hunk
&other
)
67 #if QT_VERSION >= 0x040400
76 #if QT_VERSION >= 0x040400
84 void Hunk::addLine(const QByteArray
&line
)
88 if(d
->header
.isEmpty()) {
91 QRegExp
regexp("^@@ -[\\d,]+ \\+(\\d+)\\b");
92 if (regexp
.indexIn(header
) != -1)
93 d
->lineNumber
= regexp
.cap(1).toInt();
96 if (line
[0] == '\\') { // "\ No newline at end of file"
98 // check if we removed something from the last hunk and adjust its size
99 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
100 if (last
->start
+ last
->length
== d
->diff
.size())
102 d
->diff
.chop(1); // TODO should that be 2 on Windows?
106 else if (line
[0] != ' ') {
107 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
108 if (last
->start
< 0) {
109 last
->start
= d
->diff
.size();
110 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
112 else if (last
->start
+ last
->length
< d
->diff
.size()) {
113 last
= new SubHunk();
114 d
->subhunks
.append(last
);
115 last
->start
= d
->diff
.size();
116 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
118 last
->length
+=line
.length();
119 if (line
[0] == '-') {
132 d
->diff
.append(line
);
135 Hunk
& Hunk::operator=(const Hunk
&other
)
137 #if QT_VERSION >= 0x040400
139 if (! d
->ref
.deref())
149 int Hunk::lineNumber() const
151 return d
->lineNumber
;
154 int Hunk::lineNumber(int subHunk
) const
156 Q_ASSERT(subHunk
< d
->subhunks
.count());
157 SubHunk
*sh
= d
->subhunks
[subHunk
];
158 return sh
->lineNumber
;
161 QByteArray
Hunk::patch() const
166 bool Hunk::isEmpty() const
168 return d
->diff
.isEmpty();
171 Vng::Acceptance
Hunk::acceptance() const
173 Vng::Acceptance a
= Vng::Undecided
;
174 for (int i
= 0; i
< d
->subhunks
.count(); i
++) {
175 SubHunk
*sh
= d
->subhunks
[i
];
176 if (a
!= sh
->accepted
) {
177 if (a
== Vng::Undecided
)
180 return Vng::MixedAcceptance
;
186 void Hunk::setAcceptance(Vng::Acceptance acceptance
)
188 foreach(SubHunk
*sh
, d
->subhunks
)
189 sh
->accepted
= acceptance
;
192 Vng::Acceptance
Hunk::acceptance(int subHunk
) const
194 Q_ASSERT(subHunk
< d
->subhunks
.count());
195 SubHunk
*sh
= d
->subhunks
[subHunk
];
199 void Hunk::setAcceptance(int subhunk
, Vng::Acceptance accepted
)
201 Q_ASSERT(subhunk
< d
->subhunks
.count());
202 SubHunk
*sh
= d
->subhunks
[subhunk
];
203 sh
->accepted
= accepted
;
206 QByteArray
Hunk::header() const
211 QByteArray
Hunk::subHunk(int index
) const
213 if (d
->subhunks
.count() == 0)
215 Q_ASSERT(index
>= 0);
216 Q_ASSERT(index
< d
->subhunks
.count());
217 SubHunk
*sh
= d
->subhunks
[index
];
218 return d
->diff
.mid(sh
->start
, sh
->length
);
221 int Hunk::subHunkCount() const
223 return d
->subhunks
.count();
226 QByteArray
Hunk::rejectedPatch() const
228 return d
->patchForAccepted(true);
231 QByteArray
Hunk::acceptedPatch() const
233 return d
->patchForAccepted(false);
236 QByteArray
Hunk::Private::patchForAccepted(bool inverse
)
239 QDataStream
out (&patch
, QIODevice::WriteOnly
);
240 const char *myDiff
= diff
.data();
241 const char *space
= " ";
242 int offsetInDiff
= 0; // position in diff
243 int before
= linesBefore
; // for the header
244 foreach(SubHunk
*sh
, subhunks
) {
245 out
.writeRawData(myDiff
+ offsetInDiff
, sh
->start
- offsetInDiff
); // write until start
246 if (!inverse
&& sh
->accepted
== Vng::Accepted
|| inverse
&& sh
->accepted
!= Vng::Accepted
) {
247 out
.writeRawData(myDiff
+ sh
->start
, sh
->length
);
250 const int end
= sh
->start
+ sh
->length
;
251 bool startOfLine
= true;
253 int lastLineStart
= 0;
254 for (int x
= sh
->start
; x
< end
; x
++) {
257 skipLine
= myDiff
[x
] == '-';
259 out
.writeRawData(space
, 1);
260 lastLineStart
= x
+ 1;
264 if (myDiff
[x
] == '\n') {
267 out
.writeRawData(myDiff
+ lastLineStart
, x
- lastLineStart
+ 1);
270 before
+= sh
->added
- sh
->removed
;
272 offsetInDiff
= sh
->start
+ sh
->length
;
274 Q_ASSERT(offsetInDiff
<= diff
.size());
275 out
.writeRawData(myDiff
+ offsetInDiff
, diff
.size() - offsetInDiff
);
276 if (patch
[patch
.size() -1] != '\n') {
277 const char *noNewLine
= "\n\\ No newline at end of file\n";;
278 out
.writeRawData(noNewLine
, strlen(noNewLine
));
282 QString header
= "@@ -"+ QString::number(lineNumber
) +","+ QString::number(before
)
283 +" +"+ QString::number(lineNumber
) +","+ QString::number(linesAfter
) + " @@\n";
286 answer
.append(header
);
287 answer
.append(patch
);
291 int Hunk::linesAdded() const
294 foreach(SubHunk
*sh
, d
->subhunks
)
299 int Hunk::linesRemoved() const
302 foreach(SubHunk
*sh
, d
->subhunks
)
303 total
+= sh
->removed
;