Bug Summary

File:libgui/qterminal/libqterminal/unix/Filter.cpp
Location:line 210, column 26
Description:Called C++ object pointer is null

Annotated Source Code

1/*
2 Copyright (C) 2007, 2013 by Robert Knight <robertknight@gmail.com>
3
4 Rewritten for QT4 by e_k <e_k at users.sourceforge.net>, Copyright (C)2008
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20*/
21
22// Own
23#include "unix/Filter.h"
24
25// System
26#include <iostream>
27
28// Qt
29#include <QAction>
30#include <QApplication>
31#include <QClipboard>
32#include <QtCore/QString>
33
34#include <QtCore/QSharedData>
35#include <QtCore>
36
37// Konsole
38#include "unix/TerminalCharacterDecoder.h"
39
40FilterChain::~FilterChain()
41{
42 QMutableListIterator<Filter*> iter(*this);
43
44 while ( iter.hasNext() )
45 {
46 Filter* filter = iter.next();
47 iter.remove();
48 delete filter;
49 }
50}
51
52void FilterChain::addFilter(Filter* filter)
53{
54 append(filter);
55}
56void FilterChain::removeFilter(Filter* filter)
57{
58 removeAll(filter);
59}
60bool FilterChain::containsFilter(Filter* filter)
61{
62 return contains(filter);
63}
64void FilterChain::reset()
65{
66 QListIterator<Filter*> iter(*this);
67 while (iter.hasNext())
68 iter.next()->reset();
69}
70void FilterChain::setBuffer(const QString* buffer , const QList<int>* linePositions)
71{
72 QListIterator<Filter*> iter(*this);
73 while (iter.hasNext())
74 iter.next()->setBuffer(buffer,linePositions);
75}
76void FilterChain::process()
77{
78 QListIterator<Filter*> iter(*this);
79 while (iter.hasNext())
80 iter.next()->process();
81}
82void FilterChain::clear()
83{
84 QList<Filter*>::clear();
85}
86Filter::HotSpot* FilterChain::hotSpotAt(int line , int column) const
87{
88 QListIterator<Filter*> iter(*this);
89 while (iter.hasNext())
90 {
91 Filter* filter = iter.next();
92 Filter::HotSpot* spot = filter->hotSpotAt(line,column);
93 if ( spot != 0 )
94 {
95 return spot;
96 }
97 }
98
99 return 0;
100}
101
102QList<Filter::HotSpot*> FilterChain::hotSpots() const
103{
104 QList<Filter::HotSpot*> list;
105 QListIterator<Filter*> iter(*this);
106 while (iter.hasNext())
107 {
108 Filter* filter = iter.next();
109 list << filter->hotSpots();
110 }
111 return list;
112}
113
114TerminalImageFilterChain::TerminalImageFilterChain()
115: _buffer(0)
116, _linePositions(0)
117{
118}
119
120TerminalImageFilterChain::~TerminalImageFilterChain()
121{
122 delete _buffer;
123 delete _linePositions;
124}
125
126void TerminalImageFilterChain::setImage(const Character* const image , int lines , int columns, const QVector<LineProperty>& lineProperties)
127{
128//qDebug("%s %d", __FILE__, __LINE__);
129 if (empty())
130 return;
131//qDebug("%s %d", __FILE__, __LINE__);
132
133 // reset all filters and hotspots
134 reset();
135//qDebug("%s %d", __FILE__, __LINE__);
136
137 PlainTextDecoder decoder;
138 decoder.setTrailingWhitespace(false);
139
140//qDebug("%s %d", __FILE__, __LINE__);
141 // setup new shared buffers for the filters to process on
142 QString* newBuffer = new QString();
143 QList<int>* newLinePositions = new QList<int>();
144 setBuffer( newBuffer , newLinePositions );
145
146 // free the old buffers
147 delete _buffer;
148 delete _linePositions;
149
150 _buffer = newBuffer;
151 _linePositions = newLinePositions;
152
153 QTextStream lineStream(_buffer);
154 decoder.begin(&lineStream);
155
156 for (int i=0 ; i < lines ; i++)
157 {
158 _linePositions->append(_buffer->length());
159 decoder.decodeLine(image + i*columns,columns,LINE_DEFAULT);
160
161 // pretend that each line ends with a newline character.
162 // this prevents a link that occurs at the end of one line
163 // being treated as part of a link that occurs at the start of the next line
164 //
165 // the downside is that links which are spread over more than one line are not
166 // highlighted.
167 //
168 // TODO - Use the "line wrapped" attribute associated with lines in a
169 // terminal image to avoid adding this imaginary character for wrapped
170 // lines
171 if ( !(lineProperties.value(i,LINE_DEFAULT) & LINE_WRAPPED) )
172 lineStream << QChar('\n');
173 }
174 decoder.end();
175// qDebug("%s %d", __FILE__, __LINE__);
176}
177
178Filter::Filter() :
179_linePositions(0),
180_buffer(0)
181{
182}
183
184Filter::~Filter()
185{
186 QListIterator<HotSpot*> iter(_hotspotList);
187 while (iter.hasNext())
188 {
189 delete iter.next();
190 }
191}
192void Filter::reset()
193{
194 _hotspots.clear();
195 _hotspotList.clear();
196}
197
198void Filter::setBuffer(const QString* buffer , const QList<int>* linePositions)
199{
200 _buffer = buffer;
201 _linePositions = linePositions;
202}
203
204void Filter::getLineColumn(int position , int& startLine , int& startColumn)
205{
206 Q_ASSERT( _linePositions )((!(_linePositions)) ? qt_assert("_linePositions","qterminal/libqterminal/unix/Filter.cpp"
,206) : qt_noop())
;
11
Within the expansion of the macro 'Q_ASSERT':
a
Assuming pointer value is null
207 Q_ASSERT( _buffer )((!(_buffer)) ? qt_assert("_buffer","qterminal/libqterminal/unix/Filter.cpp"
,207) : qt_noop())
;
208
209
210 for (int i = 0 ; i < _linePositions->count() ; i++)
12
Called C++ object pointer is null
211 {
212 //kDebug() << "line position at " << i << " = " << _linePositions[i];
213 int nextLine = 0;
214
215 if ( i == _linePositions->count()-1 )
216 {
217 nextLine = _buffer->length() + 1;
218 }
219 else
220 {
221 nextLine = _linePositions->value(i+1);
222 }
223
224 // kDebug() << "pos - " << position << " line pos(" << i<< ") " << _linePositions->value(i) <<
225 // " next = " << nextLine << " buffer len = " << _buffer->length();
226
227 if ( _linePositions->value(i) <= position && position < nextLine )
228 {
229 startLine = i;
230 startColumn = position - _linePositions->value(i);
231 return;
232 }
233 }
234}
235
236
237/*void Filter::addLine(const QString& text)
238{
239 _linePositions << _buffer.length();
240 _buffer.append(text);
241}*/
242
243const QString* Filter::buffer()
244{
245 return _buffer;
246}
247Filter::HotSpot::~HotSpot()
248{
249}
250void Filter::addHotSpot(HotSpot* spot)
251{
252 _hotspotList << spot;
253
254 for (int line = spot->startLine() ; line <= spot->endLine() ; line++)
255 {
256 _hotspots.insert(line,spot);
257 }
258}
259QList<Filter::HotSpot*> Filter::hotSpots() const
260{
261 return _hotspotList;
262}
263QList<Filter::HotSpot*> Filter::hotSpotsAtLine(int line) const
264{
265 return _hotspots.values(line);
266}
267
268Filter::HotSpot* Filter::hotSpotAt(int line , int column) const
269{
270 QListIterator<HotSpot*> spotIter(_hotspots.values(line));
271
272 while (spotIter.hasNext())
273 {
274 HotSpot* spot = spotIter.next();
275
276 if ( spot->startLine() == line && spot->startColumn() > column )
277 continue;
278 if ( spot->endLine() == line && spot->endColumn() < column )
279 continue;
280
281 return spot;
282 }
283
284 return 0;
285}
286
287Filter::HotSpot::HotSpot(int startLine , int startColumn , int endLine , int endColumn)
288 : _startLine(startLine)
289 , _startColumn(startColumn)
290 , _endLine(endLine)
291 , _endColumn(endColumn)
292 , _type(NotSpecified)
293{
294}
295QString Filter::HotSpot::tooltip() const
296{
297 return QString();
298}
299QList<QAction*> Filter::HotSpot::actions()
300{
301 return QList<QAction*>();
302}
303int Filter::HotSpot::startLine() const
304{
305 return _startLine;
306}
307int Filter::HotSpot::endLine() const
308{
309 return _endLine;
310}
311int Filter::HotSpot::startColumn() const
312{
313 return _startColumn;
314}
315int Filter::HotSpot::endColumn() const
316{
317 return _endColumn;
318}
319Filter::HotSpot::Type Filter::HotSpot::type() const
320{
321 return _type;
322}
323void Filter::HotSpot::setType(Type type)
324{
325 _type = type;
326}
327
328RegExpFilter::RegExpFilter()
329{
330}
331
332RegExpFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
333 : Filter::HotSpot(startLine,startColumn,endLine,endColumn)
334{
335 setType(Marker);
336}
337
338void RegExpFilter::HotSpot::activate(QObject*)
339{
340}
341
342void RegExpFilter::HotSpot::setCapturedTexts(const QStringList& texts)
343{
344 _capturedTexts = texts;
345}
346QStringList RegExpFilter::HotSpot::capturedTexts() const
347{
348 return _capturedTexts;
349}
350
351void RegExpFilter::setRegExp(const QRegExp& regExp)
352{
353 _searchText = regExp;
354}
355QRegExp RegExpFilter::regExp() const
356{
357 return _searchText;
358}
359/*void RegExpFilter::reset(int)
360{
361 _buffer = QString();
362}*/
363void RegExpFilter::process()
364{
365 int pos = 0;
366 const QString* text = buffer();
367
368 Q_ASSERT( text )((!(text)) ? qt_assert("text","qterminal/libqterminal/unix/Filter.cpp"
,368) : qt_noop())
;
369
370 // ignore any regular expressions which match an empty string.
371 // otherwise the while loop below will run indefinitely
372 static const QString emptyString("");
373 if ( _searchText.exactMatch(emptyString) )
1
Taking false branch
374 return;
375
376 while(pos >= 0)
2
Loop condition is true. Entering loop body
5
Assuming 'pos' is >= 0
6
Loop condition is true. Entering loop body
377 {
378 pos = _searchText.indexIn(*text,pos);
379
380 if ( pos >= 0 )
3
Assuming 'pos' is >= 0
4
Taking true branch
7
Assuming 'pos' is >= 0
8
Taking true branch
381 {
382
383 int startLine = 0;
384 int endLine = 0;
385 int startColumn = 0;
386 int endColumn = 0;
387
388
389 //kDebug() << "pos from " << pos << " to " << pos + _searchText.matchedLength();
390
391 getLineColumn(pos,startLine,startColumn);
392 getLineColumn(pos + _searchText.matchedLength(),endLine,endColumn);
9
Value assigned to field '_linePositions'
10
Calling 'Filter::getLineColumn'
393
394 //kDebug() << "start " << startLine << " / " << startColumn;
395 //kDebug() << "end " << endLine << " / " << endColumn;
396
397 RegExpFilter::HotSpot* spot = newHotSpot(startLine,startColumn,
398 endLine,endColumn);
399 spot->setCapturedTexts(_searchText.capturedTexts());
400
401 addHotSpot( spot );
402 pos += _searchText.matchedLength();
403
404 // if matchedLength == 0, the program will get stuck in an infinite loop
405 Q_ASSERT( _searchText.matchedLength() > 0 )((!(_searchText.matchedLength() > 0)) ? qt_assert("_searchText.matchedLength() > 0"
,"qterminal/libqterminal/unix/Filter.cpp",405) : qt_noop())
;
406 }
407 }
408}
409
410RegExpFilter::HotSpot* RegExpFilter::newHotSpot(int startLine,int startColumn,
411 int endLine,int endColumn)
412{
413 return new RegExpFilter::HotSpot(startLine,startColumn,
414 endLine,endColumn);
415}
416RegExpFilter::HotSpot* UrlFilter::newHotSpot(int startLine,int startColumn,int endLine,
417 int endColumn)
418{
419 return new UrlFilter::HotSpot(startLine,startColumn,
420 endLine,endColumn);
421}
422UrlFilter::HotSpot::HotSpot(int startLine,int startColumn,int endLine,int endColumn)
423: RegExpFilter::HotSpot(startLine,startColumn,endLine,endColumn)
424, _urlObject(new FilterObject(this))
425{
426 setType(Link);
427}
428QString UrlFilter::HotSpot::tooltip() const
429{
430 QString url = capturedTexts().first();
431
432 const UrlType kind = urlType();
433
434 if ( kind == StandardUrl )
435 return QString();
436 else if ( kind == Email )
437 return QString();
438 else
439 return QString();
440}
441UrlFilter::HotSpot::UrlType UrlFilter::HotSpot::urlType() const
442{
443 QString url = capturedTexts().first();
444
445 if ( FullUrlRegExp.exactMatch(url) )
446 return StandardUrl;
447 else if ( EmailAddressRegExp.exactMatch(url) )
448 return Email;
449 else
450 return Unknown;
451}
452
453void UrlFilter::HotSpot::activate(QObject* object)
454{
455 QString url = capturedTexts().first();
456
457 const UrlType kind = urlType();
458
459 const QString& actionName = object ? object->objectName() : QString();
460
461 if ( actionName == "copy-action" )
462 {
463 //kDebug() << "Copying url to clipboard:" << url;
464
465 QApplication::clipboard()->setText(url);
466 return;
467 }
468
469 if ( !object || actionName == "open-action" )
470 {
471 if ( kind == StandardUrl )
472 {
473 // if the URL path does not include the protocol ( eg. "www.kde.org" ) then
474 // prepend http:// ( eg. "www.kde.org" --> "http://www.kde.org" )
475 if (!url.contains("://"))
476 {
477 url.prepend("http://");
478 }
479 }
480 else if ( kind == Email )
481 {
482 url.prepend("mailto:");
483 }
484
485// new KRun(url,QApplication::activeWindow());
486 }
487}
488
489// Note: Altering these regular expressions can have a major effect on the performance of the filters
490// used for finding URLs in the text, especially if they are very general and could match very long
491// pieces of text.
492// Please be careful when altering them.
493
494//regexp matches:
495// full url:
496// protocolname:// or www. followed by anything other than whitespaces, <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, comma and dot
497const QRegExp UrlFilter::FullUrlRegExp("(www\\.(?!\\.)|[a-z][a-z0-9+.-]*://)[^\\s<>'\"]+[^!,\\.\\s<>'\"\\]]");
498// email address:
499// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
500const QRegExp UrlFilter::EmailAddressRegExp("\\b(\\w|\\.|-)+@(\\w|\\.|-)+\\.\\w+\\b");
501
502// matches full url or email address
503const QRegExp UrlFilter::CompleteUrlRegExp('('+FullUrlRegExp.pattern()+'|'+
504 EmailAddressRegExp.pattern()+')');
505
506UrlFilter::UrlFilter()
507{
508 setRegExp( CompleteUrlRegExp );
509}
510UrlFilter::HotSpot::~HotSpot()
511{
512 delete _urlObject;
513}
514void FilterObject::activated()
515{
516 _filter->activate(sender());
517}
518QList<QAction*> UrlFilter::HotSpot::actions()
519{
520 QList<QAction*> list;
521
522 const UrlType kind = urlType();
523
524 QAction* openAction = new QAction(_urlObject);
525 QAction* copyAction = new QAction(_urlObject);;
526
527 Q_ASSERT( kind == StandardUrl || kind == Email )((!(kind == StandardUrl || kind == Email)) ? qt_assert("kind == StandardUrl || kind == Email"
,"qterminal/libqterminal/unix/Filter.cpp",527) : qt_noop())
;
528
529 if ( kind == StandardUrl )
530 {
531 openAction->setText(("Open Link"));
532 copyAction->setText(("Copy Link Address"));
533 }
534 else if ( kind == Email )
535 {
536 openAction->setText(("Send Email To..."));
537 copyAction->setText(("Copy Email Address"));
538 }
539
540 // object names are set here so that the hotspot performs the
541 // correct action when activated() is called with the triggered
542 // action passed as a parameter.
543 openAction->setObjectName("open-action");
544 copyAction->setObjectName("copy-action");
545
546 QObject::connect( openAction , SIGNAL(triggered())qFlagLocation("2""triggered()" "\0" "qterminal/libqterminal/unix/Filter.cpp"
":" "546")
, _urlObject , SLOT(activated())qFlagLocation("1""activated()" "\0" "qterminal/libqterminal/unix/Filter.cpp"
":" "546")
);
547 QObject::connect( copyAction , SIGNAL(triggered())qFlagLocation("2""triggered()" "\0" "qterminal/libqterminal/unix/Filter.cpp"
":" "547")
, _urlObject , SLOT(activated())qFlagLocation("1""activated()" "\0" "qterminal/libqterminal/unix/Filter.cpp"
":" "547")
);
548
549 list << openAction;
550 list << copyAction;
551
552 return list;
553}
554
555//#include "moc_Filter.cpp"