File indexing completed on 2024-04-28 04:48:05
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Gary Steinert <gary.steinert@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "log.h" 0018 0019 #include <QDir> 0020 #include <QDebug> 0021 #include <QFile> 0022 #include <QTextStream> 0023 #include <QString> 0024 0025 const QString BLANKLINE( " * *" ); 0026 const QString TOPLINE( "/****************************************************************************************" ); 0027 QList<QStringList> LICENSES = QList<QStringList>() << 0028 ( QStringList() << 0029 " * This program is free software; you can redistribute it and/or modify it under *" << 0030 " * the terms of the GNU General Public License as published by the Free Software *" << 0031 " * Foundation; either version 2 of the License, or (at your option) any later *" << 0032 " * version. *" << 0033 " * *" << 0034 " * This program is distributed in the hope that it will be useful, but WITHOUT ANY *" << 0035 " * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *" << 0036 " * PARTICULAR PURPOSE. See the GNU General Public License for more details. *" << 0037 " * *" << 0038 " * You should have received a copy of the GNU General Public License along with *" << 0039 " * this program. If not, see <http://www.gnu.org/licenses/>. *" 0040 ) 0041 << 0042 ( QStringList() << 0043 " * This program is free software; you can redistribute it and/or modify it under *" << 0044 " * the terms of the GNU Library General Public License as published by the Free *" << 0045 " * Software Foundation; either version 2.1 of the License, or (at your option) any *" << 0046 " * later version. *" << 0047 " * *" << 0048 " * This program is distributed in the hope that it will be useful, but WITHOUT ANY *" << 0049 " * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *" << 0050 " * PARTICULAR PURPOSE. See the GNU General Public License for more details. *" << 0051 " * *" << 0052 " * You should have received a copy of the GNU Library General Public License along with *" << 0053 " * this program. If not, see <http://www.gnu.org/licenses/>. *" 0054 ) 0055 << 0056 ( QStringList() << 0057 " * This program is free software; you can redistribute it and/or modify it under *" << 0058 " * the terms of the GNU General Public License as published by the Free Software *" << 0059 " * Foundation; either version 2 of the License, or (at your option) version 3 or *" << 0060 " * any later version accepted by the membership of KDE e.V. (or its successor approved *" << 0061 " * by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of *" << 0062 " * version 3 of the license. *" << 0063 " * *" << 0064 " * This program is distributed in the hope that it will be useful, but WITHOUT ANY *" << 0065 " * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *" << 0066 " * PARTICULAR PURPOSE. See the GNU General Public License for more details. *" << 0067 " * *" << 0068 " * You should have received a copy of the GNU General Public License along with *" << 0069 " * this program. If not, see <http://www.gnu.org/licenses/>. *" 0070 ) 0071 << 0072 ( QStringList() << 0073 " * This program is free software; you can redistribute it and/or modify it under *" << 0074 " * the terms of the GNU General Public License as published by the Free Software *" << 0075 " * Foundation; either version 2 of the License, or (at your option) version 3 or any *" << 0076 " * later version publicly approved by Trolltech ASA (or its successor, if any) and the *" << 0077 " * KDE Free Qt Foundation. *" << 0078 " * *" << 0079 " * This program is distributed in the hope that it will be useful, but WITHOUT ANY *" << 0080 " * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *" << 0081 " * PARTICULAR PURPOSE. See the GNU General Public License for more details. *" << 0082 " * *" << 0083 " * You should have received a copy of the GNU General Public License along with *" << 0084 " * this program. If not, see <http://www.gnu.org/licenses/>. *" << 0085 " * *" << 0086 " * In addition, Trolltech gives you certain additional rights as described in the *" << 0087 " * Trolltech GPL Exception version 1.2 which can be found at *" << 0088 " * http://www.trolltech.com/products/qt/gplexception/ *" 0089 ); 0090 0091 struct { 0092 QString outputFile; 0093 bool recursive; 0094 LogEntry::PrintStyle outputStyle; 0095 bool fullReport; 0096 bool help; 0097 QList<QString> folders; 0098 QString bashScriptFile; 0099 } cliArgs; 0100 0101 Log log; 0102 0103 using namespace std; 0104 0105 void readFile( QString filename ) { 0106 0107 bool autofixed = false; 0108 0109 //Set up file variables 0110 QFile file( filename ); 0111 if( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) 0112 { 0113 log.append( LogEntry( filename, "Could not open file", LogEntry::failure ) ); 0114 return; 0115 } 0116 0117 QTextStream inStream( &file ); 0118 0119 if( inStream.atEnd() ) 0120 { 0121 log.append( LogEntry( filename, "Empty file - no license information", LogEntry::warning ) ); 0122 return; 0123 } 0124 0125 //Search for first comment block (search for /* at start of line) 0126 QString line; 0127 line = inStream.readLine(); 0128 0129 bool headerAtStart = true; 0130 int numLinesBeforeHeader = 0; 0131 0132 while( !line.contains( "/*" ) && !inStream.atEnd() ) 0133 { 0134 line = inStream.readLine(); 0135 headerAtStart = false; 0136 numLinesBeforeHeader++; 0137 } 0138 0139 int startpos = line.indexOf( "/*" ); 0140 int endpos = line.lastIndexOf( "*/" ); 0141 0142 if( startpos == -1 ) //No block comments 0143 { 0144 log.append( LogEntry( filename, "No license header - could not find block comment", LogEntry::failure ) ); 0145 0146 log.addProblemFile( filename ); 0147 0148 return; 0149 } 0150 0151 if( endpos != -1 || endpos > startpos ) //Single line comment - not license header 0152 { 0153 log.append( LogEntry( filename, "First block comment is single-line. Therefore not license header", LogEntry::failure ) ); 0154 0155 log.addProblemFile( filename ); 0156 0157 return; 0158 } 0159 0160 //Find end of comment block 0161 QList<QString> header; 0162 0163 header.append(line); 0164 0165 while( !line.contains( "*/" ) && !inStream.atEnd() ) 0166 { 0167 line = inStream.readLine(); 0168 header.append( line ); 0169 } 0170 0171 int originalLength = header.count(); 0172 0173 0174 if( !line.contains( "*/" ) ) 0175 { 0176 log.append( LogEntry( filename, "No license header - could not find end of block comment", LogEntry::failure ) ); 0177 0178 log.addProblemFile( filename ); 0179 0180 return; 0181 } 0182 0183 bool problemFile = false; 0184 0185 if ( !headerAtStart ) 0186 { 0187 log.append( LogEntry( filename, "License header is not at the start of the file", LogEntry::warning ) ); 0188 0189 problemFile = true; 0190 } 0191 0192 0193 //START CHECKS 0194 //Check first line *'s and correct length 0195 if( header[0] != TOPLINE ) 0196 { 0197 log.append( LogEntry( filename, "First line of header incorrect", LogEntry::error ) ); 0198 problemFile = true; 0199 } 0200 0201 //Find first line of license 0202 int i = 1; 0203 0204 bool firstLineFound = false; 0205 0206 while( i < header.count() ) 0207 { 0208 for( int j = 0; j < LICENSES.count(); j++ ) 0209 { 0210 if( header[i] == LICENSES[j][0] ) 0211 { 0212 firstLineFound = true; 0213 break; 0214 } 0215 } 0216 0217 if( firstLineFound ) 0218 break; 0219 0220 i++; 0221 } 0222 0223 if( i == header.count() ) 0224 { 0225 log.append( LogEntry( filename, "Required License wording and format not found. (Could not find match for first line)", LogEntry::failure ) ); 0226 0227 log.addProblemFile( filename ); 0228 return; 0229 } 0230 0231 bool licenseFound = false; 0232 0233 //Declaring k here so that it stays around for the log entry if needed. 0234 int k; 0235 0236 for( int j = 0; j < LICENSES.count(); j++ ) 0237 { 0238 if( header.count() + i < LICENSES[j].count() ) 0239 continue; //Too short to be header, so continue 0240 0241 k = 1; 0242 while( k < LICENSES[j].count() && header[k+i] == LICENSES[j][k] ) 0243 k++; 0244 0245 if( k == LICENSES[j].count() ) 0246 { 0247 //Check for extra lines. Means extra terms (+1 to incorporate last line) 0248 if( header.count() - i > LICENSES[j].count() + 1 ) 0249 log.append( LogEntry( filename, "Extra license terms in license header.", LogEntry::information ) ); 0250 0251 licenseFound = true; 0252 break; 0253 } 0254 } 0255 0256 if( !licenseFound ) 0257 { 0258 log.append( LogEntry( filename, "Required license wording and format not found.", LogEntry::failure ) ); 0259 log.addProblemFile( filename ); 0260 return; 0261 } 0262 0263 //Line i-1 should be a blank line 0264 if( header[i - 1] != BLANKLINE ) 0265 { 0266 log.append( LogEntry( filename, "No blank line between copyright holders and license text. - Fixed", LogEntry::information ) ); 0267 //Autofix 0268 header.insert( i, BLANKLINE ); 0269 autofixed = true; 0270 } 0271 0272 //Check for copyright holders (i - 1 > 1) 0273 if( i - 1 <= 1 ) 0274 { 0275 log.append( LogEntry( filename, "No copyright holders present", LogEntry::warning ) ); 0276 log.addProblemFile( filename ); 0277 } 0278 0279 bool overallSuccess = true; 0280 0281 //For each copyright holder 0282 for( int j = 1; j < i - 1; j++ ) 0283 { 0284 bool individualSuccess = true; 0285 0286 //Check for blank line (may be at top of header for instance) 0287 if( header[j] == BLANKLINE ) 0288 { 0289 log.append( LogEntry( filename, QString( "Blank line found in copyright holders. (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0290 header.removeAt( j ); 0291 j--; //So that the next line isn't skipped 0292 autofixed = true; 0293 continue; //Continue because its a blank line - nothing else needs to be done with it 0294 } 0295 0296 //Check each part of copyright line. 0297 //Check first 3 characters " * " 0298 if( header[j].mid( 0, 3 ) != " * " ) 0299 { 0300 log.append( LogEntry( filename, QString( "First 3 characters of copyright line incorrect (incorrect * border) (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0301 individualSuccess = false; 0302 0303 problemFile = true; 0304 } 0305 0306 //Check "Copyright" 0307 //From here, individualSuccess is used to skip remaining tests if one fails 0308 if( individualSuccess && header[j].mid( 3, 9 ) != "Copyright" ) 0309 { 0310 if( header[j].mid( 3, 9 ).toLower() == "copyright" ) 0311 { 0312 log.append( LogEntry( filename, QString( "Incorrect casing of \"Copyright\" (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0313 header[j] = header[j].left( 3 ) + "Copyright" + header[j].mid( 12 ); 0314 autofixed = true; 0315 } 0316 else 0317 { 0318 log.append( LogEntry( filename, QString( "\"Copyright\" not found in proper place (Line ").append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0319 individualSuccess = false; 0320 0321 problemFile = true; 0322 } 0323 } 0324 0325 //Check space between "Copyright" and "(c)" 0326 if( individualSuccess && header[j].mid( 12, 1 ) != " " ) 0327 { 0328 log.append( LogEntry( filename, QString( "No space between \"Copyright\" and \"(c)\" (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0329 individualSuccess = false; 0330 0331 problemFile = true; 0332 } 0333 0334 //Check "(c)" 0335 if( individualSuccess && header[j].mid( 13, 3 ) != "(c)" ) 0336 { 0337 if( header[j].mid( 13, 3 ).toLower() == "(c)" ) 0338 { 0339 log.append( LogEntry( filename, QString( "Incorrect casing of \"(c)\" (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0340 header[j] = header[j].left( 13 ) + "(c)" + header[j].mid( 16 ); 0341 autofixed = true; 0342 } 0343 else 0344 { 0345 log.append( LogEntry( filename, QString( "\"(c)\" not found in proper place (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0346 individualSuccess = false; 0347 0348 problemFile = true; 0349 } 0350 } 0351 0352 //Check space between "(c)" and year 0353 if( individualSuccess && header[j].mid( 16, 1 ) != " " ) 0354 { 0355 log.append( LogEntry( filename, QString( "No space between \"(c)\" and copyright holder's name (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0356 individualSuccess = false; 0357 0358 problemFile = true; 0359 } 0360 0361 //Process year 0362 //Check first year 0363 bool ok; 0364 int year = header[j].mid( 17, 4 ).toInt( &ok, 10 ); 0365 0366 if( individualSuccess && !ok ) 0367 { 0368 log.append( LogEntry( filename, QString( "Year is not found in correct format. (Not a numeric value) (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0369 individualSuccess = false; 0370 0371 problemFile = true; 0372 } 0373 0374 int k = 1; 0375 int lastyear; 0376 0377 while( individualSuccess && ( header[j].mid( 17+(4*k), 1 ) == "-" || header[j].mid( 17+(4*k), 1 ) == "," ) ) 0378 { 0379 lastyear = year; 0380 year = header[j].mid( 18+(4*k), 4 ).toInt( &ok, 10 ); 0381 0382 if( !ok ) 0383 { 0384 log.append( LogEntry( filename, QString( "Year is not found in correct format. (Not a numeric value) (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0385 individualSuccess = false; 0386 0387 problemFile = true; 0388 break; //Leave loop so no false warning for in-order years 0389 } 0390 0391 if( year < lastyear ) 0392 { 0393 log.append( LogEntry( filename, QString( "Years are not in ascending order. (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::warning ) ); 0394 } 0395 0396 //Move on to next year 0397 k++; 0398 } 0399 0400 if( individualSuccess && header[j].mid( 16+(5*k), 1 ) != " " ) 0401 { 0402 log.append( LogEntry( filename, QString( "Incorrect separator character between years, or no space between year(s) and name. (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0403 individualSuccess = false; 0404 0405 problemFile = true; 0406 } 0407 0408 //Find < at start of email 0409 int startEmail = header[j].indexOf( "<", 16+(5*k) ); 0410 0411 //Check for presence of name (startEmail > 18) (18 is first possible position plus a space) 0412 if( individualSuccess && startEmail <= 17+(5*k) ) 0413 { 0414 log.append( LogEntry( filename, QString( "Copyright holder's name not present in correct place. (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0415 individualSuccess = false; 0416 0417 problemFile = true; 0418 } 0419 0420 //Check for space at end of name 0421 if( individualSuccess && header[j].mid( startEmail - 1, 1 ) != " " ) 0422 { 0423 log.append( LogEntry( filename, QString( "No space between copyright holder's name and email (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0424 //Need to check here as this could be due to not enough width for name & email 0425 if( header[j].at( header[j].lastIndexOf( "*" ) ) == ' ' ) 0426 { 0427 header[j] = header[j].left( startEmail ) + ' ' + header[j].mid( startEmail ); 0428 //Now remove extra space 0429 header[j] = header[j].left( header[j].lastIndexOf( "*" ) - 1 ) + header[j].mid( header[j].lastIndexOf( "*" ) ); 0430 autofixed = true; 0431 } 0432 } 0433 0434 //Check for spaces at start of name (shouldn't be there) 0435 if( individualSuccess && header[j].mid( 17+(5*k), 1 ) == " " ) 0436 { 0437 log.append( LogEntry( filename, QString( "Too many spaces between copyright year and copyright holder's name (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0438 while( header[j].mid( 17+(5*k), 1 ) == " " ) 0439 { 0440 header[j] = header[j].left( 17+(5*k) ) + header[j].mid( 18+(5*k) ); 0441 header[j] = header[j].left( header[j].lastIndexOf( '*' ) ) + ' ' + header[j].mid( header[j].lastIndexOf( '*' ) ); 0442 } 0443 autofixed = true; 0444 } 0445 0446 //Check for end of email 0447 if( individualSuccess && header[j].lastIndexOf( ">" ) < startEmail ) 0448 { 0449 log.append( LogEntry( filename, QString( "No closing brackets for email address (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::error ) ); 0450 individualSuccess = false; 0451 0452 problemFile = true; 0453 } 0454 0455 //Check for @ followed by . in email address 0456 int atPos = header[j].indexOf( "@", startEmail ); 0457 int dotPos = header[j].lastIndexOf( ".", header[j].lastIndexOf( ">" ) ); 0458 0459 if( individualSuccess && ( atPos == -1 || dotPos < atPos ) ) 0460 { 0461 log.append( LogEntry( filename, QString( "Invalid email address (not format *@*.*) (Line " ).append( (char)(j+48) ).append( " of header)" ), LogEntry::warning ) ); 0462 0463 problemFile = true; 0464 } 0465 0466 //Check for 'by So and So' 0467 if( individualSuccess && header[j].mid( 17+(5*k), 5 ).trimmed().toLower().startsWith( "by " ) ) 0468 { 0469 log.append( LogEntry( filename, QString( "Copyright holder's name preceded by 'by'. (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0470 header[j] = 0471 header[j].left( header[j].toLower().indexOf( "by ", 17+(5*k) ) ) + 0472 header[j].mid( header[j].indexOf( "by ", 17+(5*k) ) + 3 ); 0473 autofixed = true; 0474 } 0475 0476 //Check length of line (stars in line at end) 0477 if( individualSuccess && header[j].trimmed().length() != 88 ) 0478 { 0479 //Easiest way is to rewrite line 0480 header[j] = header[j].left( header[j].lastIndexOf( ">" ) + 1 ); 0481 //Now add trailing spaces and * 0482 for ( int k = header[j].length(); k < 88; k++ ) 0483 header[j] += ' '; 0484 0485 header[j] += '*'; 0486 0487 log.append( LogEntry( filename, QString( "Length of copyright holder line incorrect. (Line " ).append( (char)(j+48) ).append( " of header) - Fixed" ), LogEntry::information ) ); 0488 0489 autofixed=true; 0490 } 0491 0492 //Add copyright holder (only if success) 0493 if( individualSuccess ) 0494 { 0495 log.addCopyHolder( 0496 header[j].mid( 17+(5*k), startEmail - (18+(5*k)) ), 0497 header[j].mid( startEmail + 1, header[j].lastIndexOf( ">" ) - (startEmail + 1) ), 0498 filename 0499 ); 0500 } 0501 0502 //Set overallSuccess false if this run failed 0503 if( !individualSuccess ) 0504 overallSuccess = false; 0505 0506 0507 } 0508 0509 if( autofixed ) 0510 { 0511 inStream.seek( 0 ); 0512 QList<QString> newFile; 0513 0514 for( int i = 0; i < numLinesBeforeHeader; i++ ) 0515 { 0516 newFile.append( inStream.readLine() ); 0517 } 0518 0519 newFile.append( header ); 0520 0521 //Skip old header 0522 for( int i = 0; i < originalLength; i++ ) 0523 { 0524 inStream.readLine(); 0525 } 0526 0527 while( !inStream.atEnd() ) 0528 { 0529 newFile.append( inStream.readLine() ); 0530 } 0531 0532 file.close(); 0533 if( !file.open( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text ) ) 0534 { 0535 log.append( LogEntry( filename, "Error opening file for writing autofixed header", LogEntry::error ) ); 0536 } 0537 else 0538 { 0539 QTextStream outStream( &file ); 0540 0541 foreach( const QString &i, newFile ) 0542 outStream << i << "\n"; 0543 0544 log.append( LogEntry( filename, "Some warnings autofixed", LogEntry::information ) ); 0545 } 0546 } 0547 0548 if( overallSuccess ) 0549 { 0550 log.append( LogEntry( filename, "Success", LogEntry::success ) ); 0551 0552 if( problemFile ) 0553 log.addProblemFile( filename ); 0554 } 0555 else 0556 { 0557 log.append( LogEntry( filename, "Errors in copyright holders (see above errors)", LogEntry::failure ) ); 0558 0559 log.addProblemFile( filename ); 0560 } 0561 0562 } 0563 0564 void processCliArgs(int argc, char** argv) 0565 { 0566 cliArgs.outputFile = ""; 0567 cliArgs.recursive = false; 0568 cliArgs.outputStyle = LogEntry::plainText; 0569 cliArgs.fullReport = true; 0570 cliArgs.help = false; 0571 cliArgs.folders = QList<QString>(); 0572 cliArgs.bashScriptFile = ""; 0573 0574 for( int i = 1; i < argc; i++ ) { 0575 if( argv[i][0] != '-' ) //Input folder 0576 { 0577 cliArgs.folders.append( QString( argv[i] ) ); 0578 continue; 0579 } 0580 0581 if( argv[i][1] == 'o' ) //Output filename 0582 { 0583 if( QString( argv[i] ).length() > 2 ) 0584 { 0585 cliArgs.outputFile = QString( argv[i] ).mid( 2 ).trimmed(); 0586 } 0587 else 0588 { 0589 cliArgs.outputFile = QString( argv[i + 1] ); 0590 i++; 0591 } 0592 } 0593 else if( argv[i][1] == 'b' ) //Output filename for bash script 0594 { 0595 if( QString( argv[i] ).length() > 2 ) 0596 { 0597 cliArgs.bashScriptFile = QString( argv[i] ).mid( 2 ).trimmed(); 0598 } 0599 else 0600 { 0601 cliArgs.bashScriptFile = QString( argv[i + 1] ); 0602 i++; 0603 } 0604 } 0605 else if( argv[i][1] == 'r' ) 0606 cliArgs.recursive = true; 0607 else if( argv[i][1] == 's' ) 0608 { 0609 QString outputString; 0610 if( QString( argv[i] ).length() > 2 ) 0611 { 0612 outputString = QString( argv[i] ).mid( 2 ).trimmed(); 0613 } 0614 else 0615 { 0616 outputString = QString( argv[i + 1] ); 0617 i++; 0618 } 0619 0620 if( outputString.toLower() == "plaintext" ) 0621 { 0622 cliArgs.outputStyle = LogEntry::plainText; 0623 } 0624 else if( outputString.toLower() == "html" ) 0625 { 0626 cliArgs.outputStyle = LogEntry::HTML; 0627 } 0628 else 0629 { 0630 cliArgs.help = true; 0631 } 0632 } 0633 else if( argv[i][1] == 't' ) 0634 { 0635 QString outputString; 0636 if( QString( argv[i] ).length() > 2 ) 0637 { 0638 outputString = QString( argv[i] ).mid( 2 ).trimmed(); 0639 } 0640 else 0641 { 0642 outputString = QString( argv[i + 1] ); 0643 i++; 0644 } 0645 0646 if( outputString.toLower() == "full" ) 0647 { 0648 cliArgs.fullReport = true; 0649 } 0650 else if( outputString.toLower() == "errors" ) 0651 { 0652 cliArgs.fullReport = false; 0653 } 0654 else 0655 { 0656 cliArgs.help = true; 0657 } 0658 } 0659 else if( argv[i][1] == 'h' ) 0660 cliArgs.help = true; 0661 else 0662 cliArgs.help = true; 0663 } 0664 } 0665 0666 QString appendTrailingForwardSlash( const QString a ) 0667 { 0668 if( !a.endsWith( '/' ) ) 0669 return a + '/'; 0670 else 0671 return a; 0672 } 0673 0674 void iterateFolder( QString folder ) 0675 { 0676 QDir dir( folder ); 0677 QStringList fileFilter; 0678 fileFilter << "*.h" << "*.cpp"; 0679 QStringList files = dir.entryList( fileFilter, QDir::Files ); 0680 0681 if( cliArgs.recursive ) 0682 { 0683 QStringList folders = dir.entryList( QStringList(), QDir::Dirs | QDir::NoDotAndDotDot ); 0684 foreach( const QString &i, folders ) 0685 { 0686 iterateFolder( appendTrailingForwardSlash( folder ) + i ); 0687 } 0688 0689 } 0690 0691 foreach( const QString &i, files ) 0692 { 0693 readFile( appendTrailingForwardSlash( folder ) + i ); 0694 } 0695 } 0696 0697 int main( int argc, char** argv ) 0698 { 0699 processCliArgs(argc, argv); 0700 0701 if( cliArgs.help ) 0702 { 0703 QTextStream output( stdout ); 0704 output << "Amarok License Header Checker" << "\n"; 0705 output << "Usage: " << argv[0] << " -hr -o <filename> -s <style> -t <type> file1, file2..." << "\n\n"; 0706 output << "Command Line Options:" << "\n"; 0707 output << " -h Print this help message and exit" << "\n"; 0708 output << " -r Recursive processing of directories" << "\n"; 0709 output << " -o <filename> Output written to <filename>" << "\n"; 0710 output << " -s <style> Output format. One of plaintext, HTML. Plaintext is default" << "\n"; 0711 output << " -t <type> Output type. One of full, errors. Full is default" << "\n"; 0712 output << " -b <filename> Write bash script for editing erroneous files to <filename>" << "\n"; 0713 0714 return 0; 0715 } 0716 0717 if( cliArgs.folders.count() == 0 ) 0718 cliArgs.folders.append( QString() ); 0719 0720 foreach( const QString &i, cliArgs.folders ) 0721 { 0722 iterateFolder( i ); 0723 } 0724 0725 if( cliArgs.fullReport ) 0726 log.printFullReport( cliArgs.outputStyle, cliArgs.outputFile ); 0727 else 0728 log.printErrorReport( cliArgs.outputStyle, true, cliArgs.outputFile ); 0729 0730 if( !cliArgs.bashScriptFile.isEmpty() ) 0731 log.writeShellScript( cliArgs.bashScriptFile ); 0732 0733 return 0; 0734 } 0735