2 Description: interface to git programs
4 Author: Marco Costalba (C) 2005-2007
6 Copyright: See COPYING file that comes with this distribution
10 #include <QDataStream>
13 const QString
Rev::mid(int start
, int len
) const {
15 // warning no sanity check is done on arguments
16 const char* data
= ba
.constData();
17 return QString::fromLocal8Bit(data
+ start
, len
);
20 const QString
Rev::midSha(int start
, int len
) const {
22 // warning no sanity check is done on arguments
23 const char* data
= ba
.constData();
24 return QString::fromLatin1(data
+ start
, len
); // faster then formAscii
27 const ShaString
Rev::parent(int idx
) const {
29 return ShaString(ba
.constData() + shaStart
+ 41 + 41 * idx
);
32 const QStringList
Rev::parents() const {
35 int idx
= shaStart
+ 41;
37 for (int i
= 0; i
< parentsCnt
; i
++) {
38 p
.append(midSha(idx
, 40));
44 int Rev::indexData(bool quick
, bool withDiff
) const {
46 This is what 'git log' produces:
48 - a possible one line with "Final output:\n" in case of --early-output option
49 - one line with "log size" + len of this record
50 - one line with boundary info + sha + an arbitrary amount of parent's sha
51 - one line with committer name + e-mail
52 - one line with author name + e-mail
53 - one line with author date as unix timestamp
54 - zero or more non blank lines with other info, as the encoding FIXME
56 - zero or one line with log title
57 - zero or more lines with log message
58 - zero or more lines with diff content (only for file history)
61 static int error
= -1;
62 static int shaLength
= 40; // from git ref. spec.
63 static int shaEndlLength
= shaLength
+ 1; // an sha key + \n
64 static int shaXEndlLength
= shaLength
+ 2; // an sha key + X marker + \n
65 static char finalOutputMarker
= 'F'; // marks the beginning of "Final output" string
66 static char logSizeMarker
= 'l'; // marks the beginning of "log size" string
67 static int logSizeStrLength
= 9; // "log size"
68 static int asciiPosOfZeroChar
= 48; // char "0" has value 48 in ascii table
70 const int last
= ba
.size() - 1;
71 int logSize
= 0, idx
= start
;
74 // direct access is faster then QByteArray.at()
75 const char* data
= ba
.constData();
76 char* fixup
= const_cast<char*>(data
); // to build '\0' terminating strings
78 if (start
+ shaXEndlLength
> last
) // at least sha header must be present
81 if (data
[start
] == finalOutputMarker
) // "Final output", let caller handle this
82 return (ba
.indexOf('\n', start
) != -1 ? -2 : -1);
84 // parse 'log size xxx\n' if present -- from git ref. spec.
85 if (data
[idx
] == logSizeMarker
) {
86 idx
+= logSizeStrLength
; // move idx to beginning of log size value
88 // parse log size value
90 while ((digit
= data
[idx
++]) != '\n')
91 logSize
= logSize
* 10 + digit
- asciiPosOfZeroChar
;
93 // idx points to the boundary information, which has the same length as an sha header.
94 if (++idx
+ shaXEndlLength
> last
)
99 // ok, now shaStart is valid but msgSize could be still 0 if not available
100 logEnd
= shaStart
- 1 + logSize
;
104 idx
+= shaLength
; // now points to 'X' place holder
106 fixup
[idx
] = '\0'; // we want sha to be a '\0' terminated ascii string
110 if (data
[idx
+ 2] == '\n') // initial revision
114 idx
+= shaEndlLength
;
119 fixup
[idx
] = '\0'; // we want parents '\0' terminated
121 } while (data
[idx
+ 1] != '\n');
123 ++idx
; // now points to the trailing '\n' of sha line
125 // check for !msgSize
126 if (withDiff
|| !logSize
) {
128 revEnd
= (logEnd
> idx
) ? logEnd
- 1: idx
;
129 revEnd
= ba
.indexOf('\0', revEnd
+ 1);
136 if (revEnd
> last
) // after this point we know to have the whole record
139 // ok, now revEnd is valid but logEnd could be not if !logSize
140 // in case of diff we are sure content will be consumed so
142 if (quick
&& !withDiff
)
147 idx
= ba
.indexOf('\n', idx
); // committer line end
149 dbs("ASSERT in indexData: unexpected end of data");
155 idx
= ba
.indexOf('\n', idx
); // author line end
157 dbs("ASSERT in indexData: unexpected end of data");
161 // author date in Unix format (seconds since epoch)
162 autDateStart
= ++idx
;
163 idx
= ba
.indexOf('\n', idx
); // author date end without '\n'
165 dbs("ASSERT in indexData: unexpected end of data");
168 // if no error, point to trailing \n
171 diffStart
= diffLen
= 0;
173 diffStart
= logSize
? logEnd
: ba
.indexOf("\ndiff ", idx
);
175 if (diffStart
!= -1 && diffStart
< revEnd
)
176 diffLen
= revEnd
- ++diffStart
;
181 logEnd
= diffStart
? diffStart
: revEnd
;
183 // ok, now logEnd is valid and we can handle the log
186 if (logEnd
< sLogStart
) { // no shortlog no longLog
188 sLogStart
= sLogLen
= 0;
189 lLogStart
= lLogLen
= 0;
191 lLogStart
= ba
.indexOf('\n', sLogStart
);
192 if (lLogStart
!= -1 && lLogStart
< logEnd
- 1) {
194 sLogLen
= lLogStart
- sLogStart
; // skip sLog trailing '\n'
195 lLogLen
= logEnd
- lLogStart
; // include heading '\n' in long log
197 } else { // no longLog
198 sLogLen
= logEnd
- sLogStart
;
199 if (data
[sLogStart
+ sLogLen
- 1] == '\n')
200 sLogLen
--; // skip trailing '\n' if any
202 lLogStart
= lLogLen
= 0;
211 * RevFile streaming out
213 const RevFile
& RevFile::operator>>(QDataStream
& stream
) const {
217 // skip common case of only modified files
218 bool isEmpty
= onlyModified
;
219 stream
<< (quint32
)isEmpty
;
223 // skip common case of just one parent
224 isEmpty
= (mergeParent
.isEmpty() || mergeParent
.last() == 1);
225 stream
<< (quint32
)isEmpty
;
227 stream
<< mergeParent
;
229 // skip common case of no rename/copies
230 isEmpty
= extStatus
.isEmpty();
231 stream
<< (quint32
)isEmpty
;
239 * RevFile streaming in
241 RevFile
& RevFile::operator<<(QDataStream
& stream
) {
249 onlyModified
= (bool)tmp
;
256 stream
>> mergeParent
;
266 QString
qt4and5escaping(QString toescape
) {
267 #if QT_VERSION >= 0x050000
268 return toescape
.toHtmlEscaped();
270 return Qt::escape(toescape
);