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();
48 int linesBefore
, linesAfter
;
50 QList
<SubHunk
*> subhunks
;
52 QByteArray
patchForAccepted(bool inverse
);
60 Hunk::Hunk(const Hunk
&other
)
72 void Hunk::addLine(const QByteArray
&line
)
76 if(d
->header
.isEmpty()) {
79 QRegExp
regexp("^@@ -[\\d,]+ \\+(\\d+)\\b");
80 if (regexp
.indexIn(header
) != -1)
81 d
->lineNumber
= regexp
.cap(1).toInt();
84 if (line
[0] == '\\') { // "\ No newline at end of file"
86 // check if we removed something from the last hunk and adjust its size
87 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
88 if (last
->start
+ last
->length
== d
->diff
.size())
90 d
->diff
.chop(1); // TODO should that be 2 on Windows?
94 else if (line
[0] != ' ') {
95 SubHunk
*last
= d
->subhunks
[d
->subhunks
.count()-1];
96 if (last
->start
< 0) {
97 last
->start
= d
->diff
.size();
98 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
100 else if (last
->start
+ last
->length
< d
->diff
.size()) {
101 last
= new SubHunk();
102 d
->subhunks
.append(last
);
103 last
->start
= d
->diff
.size();
104 last
->lineNumber
= d
->lineNumber
+ qMax(d
->linesBefore
, d
->linesAfter
);
106 last
->length
+=line
.length();
107 if (line
[0] == '-') {
120 d
->diff
.append(line
);
123 Hunk
& Hunk::operator=(const Hunk
&other
)
126 if (! d
->ref
.deref())
132 int Hunk::lineNumber() const
134 return d
->lineNumber
;
137 int Hunk::lineNumber(int subHunk
) const
139 Q_ASSERT(subHunk
< d
->subhunks
.count());
140 SubHunk
*sh
= d
->subhunks
[subHunk
];
141 return sh
->lineNumber
;
144 QByteArray
Hunk::patch() const
149 bool Hunk::isEmpty() const
151 return d
->diff
.isEmpty();
154 Vng::Acceptance
Hunk::acceptance() const
156 Vng::Acceptance a
= Vng::Undecided
;
157 for (int i
= 0; i
< d
->subhunks
.count(); i
++) {
158 SubHunk
*sh
= d
->subhunks
[i
];
159 if (a
!= sh
->accepted
) {
160 if (a
== Vng::Undecided
)
163 return Vng::MixedAcceptance
;
169 void Hunk::setAcceptance(Vng::Acceptance acceptance
)
171 foreach(SubHunk
*sh
, d
->subhunks
)
172 sh
->accepted
= acceptance
;
175 Vng::Acceptance
Hunk::acceptance(int subHunk
) const
177 Q_ASSERT(subHunk
< d
->subhunks
.count());
178 SubHunk
*sh
= d
->subhunks
[subHunk
];
182 void Hunk::setAcceptance(int subhunk
, Vng::Acceptance accepted
)
184 Q_ASSERT(subhunk
< d
->subhunks
.count());
185 SubHunk
*sh
= d
->subhunks
[subhunk
];
186 sh
->accepted
= accepted
;
189 QByteArray
Hunk::header() const
194 QByteArray
Hunk::subHunk(int index
) const
196 if (d
->subhunks
.count() == 0)
198 Q_ASSERT(index
>= 0);
199 Q_ASSERT(index
< d
->subhunks
.count());
200 SubHunk
*sh
= d
->subhunks
[index
];
201 return d
->diff
.mid(sh
->start
, sh
->length
);
204 int Hunk::subHunkCount() const
206 return d
->subhunks
.count();
209 QByteArray
Hunk::rejectedPatch() const
211 return d
->patchForAccepted(true);
214 QByteArray
Hunk::acceptedPatch() const
216 return d
->patchForAccepted(false);
219 QByteArray
Hunk::Private::patchForAccepted(bool inverse
)
222 QDataStream
out (&patch
, QIODevice::WriteOnly
);
223 const char *myDiff
= diff
.data();
224 const char *space
= " ";
225 int offsetInDiff
= 0; // position in diff
226 int before
= linesBefore
; // for the header
227 foreach(SubHunk
*sh
, subhunks
) {
228 out
.writeRawData(myDiff
+ offsetInDiff
, sh
->start
- offsetInDiff
); // write until start
229 if (!inverse
&& sh
->accepted
== Vng::Accepted
|| inverse
&& sh
->accepted
!= Vng::Accepted
) {
230 out
.writeRawData(myDiff
+ sh
->start
, sh
->length
);
233 const int end
= sh
->start
+ sh
->length
;
234 bool startOfLine
= true;
236 int lastLineStart
= 0;
237 for (int x
= sh
->start
; x
< end
; x
++) {
240 skipLine
= myDiff
[x
] == '-';
242 out
.writeRawData(space
, 1);
243 lastLineStart
= x
+ 1;
247 if (myDiff
[x
] == '\n') {
250 out
.writeRawData(myDiff
+ lastLineStart
, x
- lastLineStart
+ 1);
253 before
+= sh
->added
- sh
->removed
;
255 offsetInDiff
= sh
->start
+ sh
->length
;
257 Q_ASSERT(offsetInDiff
<= diff
.size());
258 out
.writeRawData(myDiff
+ offsetInDiff
, diff
.size() - offsetInDiff
);
259 if (patch
[patch
.size() -1] != '\n') {
260 const char *noNewLine
= "\n\\ No newline at end of file\n";;
261 out
.writeRawData(noNewLine
, strlen(noNewLine
));
265 QString header
= "@@ -"+ QString::number(lineNumber
) +","+ QString::number(before
)
266 +" +"+ QString::number(lineNumber
) +","+ QString::number(linesAfter
) + " @@\n";
269 answer
.append(header
);
270 answer
.append(patch
);
274 int Hunk::linesAdded() const
277 foreach(SubHunk
*sh
, d
->subhunks
)
282 int Hunk::linesRemoved() const
285 foreach(SubHunk
*sh
, d
->subhunks
)
286 total
+= sh
->removed
;