/*! * Counts the number of comment lines, removes comments, and * replaces quoted strings by special chars, e.g., $ * All arguments are modified by the method. * Special processing for """ and ''' which can be multi-line literal * or a multi-line comment if it stands alone. * * \param fmap list of processed file lines * \param result counter results * \param fmapBak list of original file lines (same as fmap except it contains unmodified quoted strings) * * \return method status */ int CPythonCounter::CountCommentsSLOC(filemap* fmap, results* result, filemap *fmapBak) { if (BlockCommentStart.empty() && LineCommentStart.empty()) return 0; if (classtype == UNKNOWN || classtype == DATAFILE) return 0; bool contd = false; bool contd_nextline; int comment_type = 0; /* comment_type: 0 : not a comment 1 : line comment, whole line 2 : line comment, embedded 3 : block comment, undecided 4 : block comment, embedded */ size_t idx_start, idx_end, comment_start; size_t quote_idx_start; string curBlckCmtStart, curBlckCmtEnd, tmp; string CurrentQuoteEnd = ""; bool quote_contd = false; filemap::iterator itfmBak = fmapBak->begin(); quote_idx_start = 0; for (filemap::iterator iter = fmap->begin(); iter != fmap->end(); iter++, itfmBak++) { contd_nextline = false; quote_idx_start = 0; idx_start = 0; if (CUtil::CheckBlank(iter->line)) continue; if (quote_contd) { // Replace quote until next character ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd); if (quote_contd) continue; } if (contd) comment_type = 3; while (!contd_nextline && idx_start < iter->line.length()) { // need to handle multiple quote chars in some languages, both " and ' may be accepted quote_idx_start = FindQuote(iter->line, QuoteStart, quote_idx_start, QuoteEscapeFront); comment_start = idx_start; if (!contd) { FindCommentStart(iter->line, comment_start, comment_type, curBlckCmtStart, curBlckCmtEnd); if (comment_start != string::npos && comment_type > 2) { // python: check whether this is a multi-line literal or a block comment tmp = CUtil::TrimString(iter->line, -1); if (iter->line.length() - tmp.length() != comment_start) { quote_idx_start = comment_start; comment_start = string::npos; } } } if (comment_start == string::npos && quote_idx_start == string::npos) break; if (comment_start != string::npos) idx_start = comment_start; // if found quote before comment, e.g., "this is quote");//comment if (quote_idx_start != string::npos && (comment_start == string::npos || quote_idx_start < comment_start)) { ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd); if (quote_idx_start > idx_start && quote_idx_start != iter->line.length()) { // comment delimiter inside quote idx_start = quote_idx_start; continue; } } else if (comment_start != string::npos) { // comment delimiter starts first switch (comment_type) { case 1: // line comment, definitely whole line iter->line = ""; itfmBak->line = ""; result->comment_lines++; contd_nextline = true; break; case 2: // line comment, possibly embedded iter->line = iter->line.substr(0, idx_start); itfmBak->line = itfmBak->line.substr(0, idx_start); // trim trailing space iter->line = CUtil::TrimString(iter->line, 1); itfmBak->line = CUtil::TrimString(itfmBak->line, 1); if (iter->line.empty()) result->comment_lines++; // whole line else result->e_comm_lines++; // embedded contd_nextline = true; break; case 3: // block comment case 4: if (contd) idx_end = iter->line.find(curBlckCmtEnd); else idx_end = iter->line.find(curBlckCmtEnd, idx_start + curBlckCmtStart.length()); if (idx_end == string::npos) { if (comment_type == 3) { iter->line = ""; itfmBak->line = ""; result->comment_lines++; } else if (comment_type == 4) { iter->line = iter->line.substr(0, idx_start); itfmBak->line = itfmBak->line.substr(0, idx_start); // trim trailing space iter->line = CUtil::TrimString(iter->line, 1); itfmBak->line = CUtil::TrimString(itfmBak->line, 1); if (iter->line.empty()) result->comment_lines++; // whole line else result->e_comm_lines++; // embedded } contd = true; contd_nextline = true; break; } else { contd = false; iter->line.erase(idx_start, idx_end - idx_start + curBlckCmtEnd.length()); itfmBak->line.erase(idx_start, idx_end - idx_start + curBlckCmtEnd.length()); if (iter->line.empty()) result->comment_lines++; else { // trim trailing space iter->line = CUtil::TrimString(iter->line, 1); itfmBak->line = CUtil::TrimString(itfmBak->line, 1); if (iter->line.empty()) result->comment_lines++; // whole line else result->e_comm_lines++; // embedded } // quote chars found may be erased as it is inside comment quote_idx_start = idx_start; } break; default: cout << "Error in CountCommentsSLOC()" << endl; break; } } } } return 1; }
/*! * Counts the number of comment lines, removes comments, and * replaces quoted strings by special chars, e.g., $ * All arguments are modified by the method. * * \param fmap list of processed file lines * \param result counter results * \param fmapBak list of original file lines (same as fmap except it contains unmodified quoted strings) * * \return method status */ int CFortranCounter::CountCommentsSLOC(filemap* fmap, results* result, filemap *fmapBak) { if (LineCommentStart.empty()) return 0; if (classtype == UNKNOWN || classtype == DATAFILE) return 0; bool contd_nextline; int comment_type = 0; /* comment_type: 0 : not comment 1 : line comment, whole line 2 : line comment, embedded */ size_t i, idx_start, comment_start; size_t quote_idx_start; string curBlckCmtStart, curBlckCmtEnd, prevLine; char CurrentQuoteEnd = 0; bool quote_contd = false, found, foundSpc; filemap::iterator itfmBak = fmapBak->begin(); quote_idx_start = 0; prevLine = ""; for (filemap::iterator iter = fmap->begin(); iter != fmap->end(); iter++, itfmBak++) { contd_nextline = false; quote_idx_start = 0; idx_start = 0; if (CUtil::CheckBlank(iter->line)) continue; if (quote_contd) { // replace quote until next character ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd); prevLine = itfmBak->line; if (quote_contd) continue; } while (!contd_nextline && idx_start < iter->line.length()) { quote_idx_start = FindQuote(iter->line, QuoteStart, quote_idx_start, QuoteEscapeFront); comment_start = idx_start; // check for comment delimiters 'C', 'c' in col 1 (works for most cases) found = false; if ((iter->line[0] == 'C' || iter->line[0] == 'c') && (prevLine.length() < 1 || prevLine[prevLine.length() - 1] != '&')) { // check for reserved 'c' words for (vector<string>::iterator viter = c_keywords.begin(); viter != c_keywords.end(); viter++) { if (CUtil::FindKeyword(iter->line, *viter, 0, TO_END_OF_STRING, false) == 0) { found = true; break; } } if (!found) { // check for function or assignment (check for 'c__()' or 'c__ =') foundSpc = false; for (i = 1; i < iter->line.length(); i++) { if (iter->line[i] == '(') { found = true; break; } else if (iter->line[i] == '=') { if (i >= iter->line.length() - 1 || iter->line[i + 1] != '=') found = true; break; } else if (iter->line[i] == ' ') foundSpc = true; else if (foundSpc) break; } } found = !found; } // check for comment delimiters '*', '!' in col 1 if (found || ((iter->line[0] == '*' || iter->line[0] == '!') && (prevLine.length() < 1 || prevLine[prevLine.length() - 1] != '&'))) { comment_start = 0; comment_type = 1; } // commented out to favor Fortran 90+ (in Fortran 77 any character in column 6 indicates continuation, not comment) // else if (iter->line.length() > 6 && iter->line[5] == '!' && CUtil::CheckBlank(iter->line.substr(0, 5))) // comment_start = string::npos; else { FindCommentStart(iter->line, comment_start, comment_type, curBlckCmtStart, curBlckCmtEnd); if (comment_start != string::npos) { // check for characters before comment for (i = 0; i < comment_start; i++) { if (iter->line[i] != ' ') { comment_type = 2; break; } } } } if (comment_start == string::npos && quote_idx_start == string::npos) { prevLine = itfmBak->line; break; } if (comment_start != string::npos) idx_start = comment_start; // if found quote before comment if (quote_idx_start != string::npos && (comment_start == string::npos || quote_idx_start < comment_start)) { ReplaceQuote(iter->line, quote_idx_start, quote_contd, CurrentQuoteEnd); if (quote_idx_start > idx_start) { if (quote_contd) { if (itfmBak->line[itfmBak->line.length() - 1] == '&') { iter->line[iter->line.length() - 1] = '&'; if (itfmBak->line.length() > 2 && itfmBak->line[itfmBak->line.length() - 2] == ' ') iter->line[iter->line.length() - 2] = ' '; } } idx_start = quote_idx_start; prevLine = itfmBak->line; continue; // comment delimiter inside quote } } else if (idx_start != string::npos) { // comment delimiter starts first switch(comment_type) { case 1: // line comment, definitely whole line case 3: prevLine = ""; iter->line = ""; itfmBak->line = ""; result->comment_lines++; contd_nextline = true; break; case 2: // line comment, possibly embedded case 4: result->e_comm_lines++; prevLine = ""; iter->line = iter->line.substr(0, idx_start); itfmBak->line = itfmBak->line.substr(0, idx_start); // trim trailing space iter->line = CUtil::TrimString(iter->line, 1); itfmBak->line = CUtil::TrimString(itfmBak->line, 1); if (iter->line.empty()) result->comment_lines++; // whole line else result->e_comm_lines++; // embedded contd_nextline = true; break; default: cout << "Error in CountCommentsSLOC()"; break; } } } } return 1; }