File indexing completed on 2024-04-28 09:36:50

0001 /*
0002     This file is part of KCachegrind.
0003 
0004     SPDX-FileCopyrightText: 2003-2016 Josef Weidendorfer <Josef.Weidendorfer@gmx.de>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only
0007 */
0008 
0009 /*
0010  * Utility classes for KCachegrind
0011  */
0012 
0013 #include "utils.h"
0014 
0015 #include <errno.h>
0016 
0017 #include <QIODevice>
0018 #include <QFile>
0019 
0020 
0021 
0022 // class FixString
0023 
0024 FixString::FixString(const char* str, int len)
0025 {
0026     _str = str;
0027     _len = len;
0028 }
0029 
0030 bool FixString::stripFirst(char& c)
0031 {
0032     if (!_len) {
0033         c = 0;
0034         return false;
0035     }
0036 
0037     c = *_str;
0038     _str++;
0039     _len--;
0040     return true;
0041 }
0042 
0043 bool FixString::stripPrefix(const char* p)
0044 {
0045     if (_len == 0) return false;
0046     if (!p || (*p != *_str)) return false;
0047 
0048     const char* s = _str+1;
0049     int l = _len-1;
0050     p++;
0051     while(*p) {
0052         if (l==0) return false;
0053         if (*s != *p) return false;
0054         p++;
0055         s++;
0056         l--;
0057     }
0058     _str = s;
0059     _len = l;
0060     return true;
0061 }
0062 
0063 
0064 // this parses hexadecimal (with prefix '0x' too)
0065 bool FixString::stripUInt(unsigned int& v, bool stripSpaces)
0066 {
0067     if (_len==0) {
0068         v = 0;
0069         return false;
0070     }
0071 
0072     char c = *_str;
0073     if (c<'0' || c>'9') {
0074         v = 0;
0075         return false;
0076     }
0077 
0078     v = c-'0';
0079     const char* s = _str+1;
0080     int l = _len-1;
0081     c = *s;
0082 
0083     if ((l>0) && (c == 'x') && (v==0)) {
0084         // hexadecimal
0085         s++;
0086         c = *s;
0087         l--;
0088 
0089         while(l>0) {
0090             if (c>='0' && c<='9')
0091                 v = 16*v + (c-'0');
0092             else if (c>='a' && c<='f')
0093                 v = 16*v + 10 + (c-'a');
0094             else if (c>='A' && c<='F')
0095                 v = 16*v + 10 + (c-'A');
0096             else
0097                 break;
0098             s++;
0099             c = *s;
0100             l--;
0101         }
0102     }
0103     else {
0104         // decimal
0105 
0106         while(l>0) {
0107             if (c<'0' || c>'9') break;
0108             v = 10*v + (c-'0');
0109             s++;
0110             c = *s;
0111             l--;
0112         }
0113     }
0114 
0115     if (stripSpaces)
0116         while(l>0) {
0117             if (c != ' ') break;
0118             s++;
0119             c = *s;
0120             l--;
0121         }
0122 
0123     _str = s;
0124     _len = l;
0125     return true;
0126 }
0127 
0128 
0129 void FixString::stripSurroundingSpaces()
0130 {
0131     if (_len==0) return;
0132 
0133     // leading spaces
0134     while((_len>0) && (*_str==' ')) {
0135         _len--;
0136         _str++;
0137     }
0138 
0139     // trailing spaces
0140     while((_len>0) && (_str[_len-1]==' ')) {
0141         _len--;
0142     }
0143 }
0144 
0145 void FixString::stripSpaces()
0146 {
0147     while((_len>0) && (*_str==' ')) {
0148         _len--;
0149         _str++;
0150     }
0151 }
0152 
0153 bool FixString::stripName(FixString& s)
0154 {
0155     if (_len==0) return false;
0156 
0157     // first char has to be a letter or "_"
0158     if (!QChar(*_str).isLetter() && (*_str != '_')) return false;
0159 
0160     int newLen = 1;
0161     const char* newStr = _str;
0162 
0163     _str++;
0164     _len--;
0165 
0166     while(_len>0) {
0167         if (!QChar(*_str).isLetterOrNumber()
0168             && (*_str != '_')) break;
0169 
0170         newLen++;
0171         _str++;
0172         _len--;
0173     }
0174 
0175     s.set(newStr, newLen);
0176     return true;
0177 }
0178 
0179 FixString FixString::stripUntil(char c)
0180 {
0181     if (_len == 0) return FixString();
0182 
0183     const char* newStr = _str;
0184     int newLen = 0;
0185 
0186     while(_len>0) {
0187         if (*_str == c) {
0188             _str++;
0189             _len--;
0190             break;
0191         }
0192 
0193         _str++;
0194         _len--;
0195         newLen++;
0196     }
0197     return FixString(newStr, newLen);
0198 }
0199 
0200 bool FixString::stripUInt64(uint64& v, bool stripSpaces)
0201 {
0202     if (_len==0) {
0203         v = 0;
0204         return false;
0205     }
0206 
0207     char c = *_str;
0208     if (c<'0' || c>'9') {
0209         v = 0;
0210         return false;
0211     }
0212 
0213     v = c-'0';
0214     const char* s = _str+1;
0215     int l = _len-1;
0216     c = *s;
0217 
0218     if ((l>0) && (c == 'x') && (v==0)) {
0219         // hexadecimal
0220         s++;
0221         c = *s;
0222         l--;
0223 
0224         while(l>0) {
0225             if (c>='0' && c<='9')
0226                 v = 16*v + (c-'0');
0227             else if (c>='a' && c<='f')
0228                 v = 16*v + 10 + (c-'a');
0229             else if (c>='A' && c<='F')
0230                 v = 16*v + 10 + (c-'A');
0231             else
0232                 break;
0233             s++;
0234             c = *s;
0235             l--;
0236         }
0237     }
0238     else {
0239         // decimal
0240         while(l>0) {
0241             if (c<'0' || c>'9') break;
0242             v = 10*v + (c-'0');
0243             s++;
0244             c = *s;
0245             l--;
0246         }
0247     }
0248 
0249     if (stripSpaces)
0250         while(l>0) {
0251             if (c != ' ') break;
0252             s++;
0253             c = *s;
0254             l--;
0255         }
0256 
0257     _str = s;
0258     _len = l;
0259     return true;
0260 }
0261 
0262 
0263 bool FixString::stripInt64(int64& v, bool stripSpaces)
0264 {
0265     if (_len==0) {
0266         v = 0;
0267         return false;
0268     }
0269 
0270     char c = *_str;
0271     bool negative = false;
0272     if (c == '-') {
0273         negative = true;
0274         _str++;
0275         _len--;
0276     }
0277     if (_len==0) {
0278         v = 0;
0279         return false;
0280     }
0281     c = *_str;
0282     if (c<'0' || c>'9') {
0283         v = 0;
0284         return false;
0285     }
0286 
0287     v = c-'0';
0288     const char* s = _str+1;
0289     int l = _len-1;
0290     c = *s;
0291 
0292     if ((l>0) && (c == 'x') && (v==0)) {
0293         // hexadecimal
0294         s++;
0295         c = *s;
0296         l--;
0297 
0298         while(l>0) {
0299             if (c>='0' && c<='9')
0300                 v = 16*v + (c-'0');
0301             else if (c>='a' && c<='f')
0302                 v = 16*v + 10 + (c-'a');
0303             else if (c>='A' && c<='F')
0304                 v = 16*v + 10 + (c-'A');
0305             else
0306                 break;
0307             s++;
0308             c = *s;
0309             l--;
0310         }
0311     }
0312     else {
0313         // decimal
0314 
0315         while(l>0) {
0316             if (c<'0' || c>'9') break;
0317             v = 10*v + (c-'0');
0318             s++;
0319             c = *s;
0320             l--;
0321         }
0322     }
0323 
0324     if (negative)
0325         v = -v;
0326 
0327     if (stripSpaces)
0328         while(l>0) {
0329             if (c != ' ') break;
0330             s++;
0331             c = *s;
0332             l--;
0333         }
0334 
0335     _str = s;
0336     _len = l;
0337     return true;
0338 }
0339 
0340 
0341 
0342 // class FixFile
0343 
0344 FixFile::FixFile(QIODevice* file, const QString& filename)
0345 {
0346     _file = file;
0347 
0348     if (!file) {
0349         _len = 0;
0350         _currentLeft = 0;
0351         _openError = true;
0352         return;
0353     }
0354 
0355     _filename = filename;
0356     if (!file->isOpen() && !file->open( QIODevice::ReadOnly ) ) {
0357         qWarning( "%s: %s", (const char*)QFile::encodeName(_filename),
0358                   strerror( errno ) );
0359         _len = 0;
0360         _currentLeft = 0;
0361         _openError = true;
0362         return;
0363     }
0364 
0365     _openError = false;
0366     _used_mmap = false;
0367 
0368     uchar* addr = nullptr;
0369 
0370 #if QT_VERSION >= 0x040400
0371     // QFile::map was introduced with Qt 4.4
0372     if (file->size() >0) {
0373         QFile* mappableDevice = dynamic_cast<QFile*>(file);
0374         if (mappableDevice) {
0375             addr = mappableDevice->map( 0, file->size() );
0376         }
0377     }
0378 #endif
0379 
0380     if (addr) {
0381         // map succeeded
0382         _base = (char*) addr;
0383         _len = file->size();
0384         _used_mmap = true;
0385 
0386         if (0) qDebug("Mapped '%s'", qPrintable( _filename ));
0387     }
0388     else {
0389         // try reading the data into memory instead
0390         file->seek(0);
0391         _data = file->readAll();
0392         _base = _data.data();
0393         _len  = _data.size();
0394     }
0395 
0396     _current     = _base;
0397     _currentLeft = _len;
0398 }
0399 
0400 FixFile::~FixFile()
0401 {
0402     // if the file was read into _data, it will be deleted automatically
0403 
0404     if (_used_mmap && _file) {
0405         if (0) qDebug("Unmapping '%s'", qPrintable( _filename ));
0406 #if QT_VERSION >= 0x040400
0407         QFile* mappableDevice = dynamic_cast<QFile*>(_file);
0408         Q_ASSERT(mappableDevice);
0409         if (!mappableDevice->unmap( (uchar*) _base ))
0410             qWarning( "munmap: %s", strerror( errno ) );
0411 #endif
0412     }
0413 }
0414 
0415 bool FixFile::nextLine(FixString& str)
0416 {
0417     if (_currentLeft == 0) return false;
0418 
0419     unsigned left = _currentLeft;
0420     char* current = _current;
0421 
0422     while(left>0) {
0423         if (*current == 0 || *current == '\n') break;
0424         current++;
0425         left--;
0426     }
0427 
0428     if (0) {
0429         char tmp[200];
0430         int l = _currentLeft-left;
0431         if (l>199) l = 199;
0432         strncpy(tmp, _current, l);
0433         tmp[l] = 0;
0434         qDebug("[FixFile::nextLine] At %lu, len %u: '%s'",
0435                (unsigned long) (_current - _base), _currentLeft-left, tmp);
0436     }
0437 
0438     int len =  _currentLeft-left;
0439     // get rid of any carriage return at end
0440     if ((len>0) && (*(current-1) == '\r')) len--;
0441     str.set(_current, len);
0442 
0443     if ((left > 0) && (*current == '\n')) {
0444         current++;
0445         left--;
0446     }
0447     _current = current;
0448     _currentLeft = left;
0449 
0450     return true;
0451 }
0452 
0453 bool FixFile::setCurrent(unsigned pos)
0454 {
0455     if (pos > _len) return false;
0456 
0457     _current = _base + pos;
0458     _currentLeft = _len - pos;
0459     return true;
0460 }
0461 
0462 
0463 #if 0
0464 
0465 // class AppendList
0466 
0467 
0468 AppendList::AppendList()
0469 {
0470     _next = 0;
0471     _current = 0;
0472     _last = 0;
0473 
0474     _count = 0;
0475     _currentIndex = 0;
0476     _lastIndex = 0;
0477     _autoDelete = false;
0478 }
0479 
0480 
0481 void AppendList::clear()
0482 {
0483     int count = _count;
0484     int i;
0485 
0486     if (count <= firstLen) {
0487         if (_autoDelete)
0488             for (i=0;i<count;i++)
0489                 delete _first[i];
0490     }
0491 }
0492 
0493 #endif
0494