/*! * Replaces up to ONE quoted string inside a string starting at idx_start. * * \param strline string to be processed * \param idx_start index of line character to start search * \param contd specifies the quote string is continued from the previous line * \param CurrentQuoteEnd end quote character of the current status * * \return method status */ int CCodeCounter::ReplaceQuote(string &strline, size_t &idx_start, bool &contd, char &CurrentQuoteEnd) { size_t idx_end, idx_quote; if (contd) { idx_start = 0; if (strline[0] == CurrentQuoteEnd) { idx_start = 1; contd = false; return 1; } strline[0] = '$'; } else { // handle two quote chars in some languages, both " and ' may be accepted idx_start = FindQuote(strline, QuoteStart, idx_start, QuoteEscapeFront); if (idx_start != string::npos) { idx_quote = QuoteStart.find_first_of(strline[idx_start]); CurrentQuoteEnd = QuoteEnd[idx_quote]; } else { idx_start = strline.length(); return 0; } } idx_end = CUtil::FindCharAvoidEscape(strline, CurrentQuoteEnd, idx_start + 1, QuoteEscapeFront); if (idx_end == string::npos) { idx_end = strline.length() - 1; strline.replace(idx_start + 1, idx_end - idx_start, idx_end - idx_start, '$'); contd = true; idx_start = idx_end + 1; } else { if ((QuoteEscapeRear) && (strline.length() > idx_end + 1) && (strline[idx_end+1] == QuoteEscapeRear)) { strline[idx_end] = '$'; strline[idx_end+1] = '$'; } else { contd = false; strline.replace(idx_start + 1, idx_end - idx_start - 1, idx_end - idx_start - 1, '$'); idx_start = idx_end + 1; } } 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. * 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; }
/*! * Replaces up to ONE quoted string inside a string starting at idx_start. * Uses a string instead of a character to allow processing multi-line * literals """ and '''. * * \param strline string to be processed * \param idx_start index of line character to start search * \param contd specifies the quote string is continued from the previous line * \param CurrentQuoteEnd end quote string of the current status * * \return method status */ int CPythonCounter::ReplaceQuote(string &strline, size_t &idx_start, bool &contd, string &CurrentQuoteEnd) { size_t idx_end, idx_quote; if (contd) { // python: use string instead of character to check for """ and ''' idx_start = 0; if (strline.length() >= CurrentQuoteEnd.length() && strline.substr(0, CurrentQuoteEnd.length()) == CurrentQuoteEnd) { idx_start = CurrentQuoteEnd.length(); contd = false; return 1; } strline[0] = '$'; } else { // handle two quote chars in some languages, both " and ' may be accepted idx_start = FindQuote(strline, QuoteStart, idx_start, QuoteEscapeFront); if (idx_start != string::npos) { idx_quote = QuoteStart.find_first_of(strline[idx_start]); CurrentQuoteEnd = QuoteEnd[idx_quote]; // python: check for """ or ''' if (strline.length() >= idx_start + 3) { if (CurrentQuoteEnd == "\"") { if (strline.substr(idx_start, 3) == "\"\"\"") CurrentQuoteEnd = "\"\"\""; } else if (CurrentQuoteEnd == "'") { if (strline.substr(idx_start, 3) == "'''") CurrentQuoteEnd = "'''"; } } } else { idx_start = strline.length(); return 0; } } // python: handle """ and ''' if (CurrentQuoteEnd.length() == 3) { if (idx_start + 3 >= strline.length()) idx_end = string::npos; else { idx_end = strline.find(CurrentQuoteEnd, idx_start + 3); if (idx_end != string::npos) idx_end += 2; // shift to last quote character } } else idx_end = CUtil::FindCharAvoidEscape(strline, CurrentQuoteEnd[0], idx_start + 1, QuoteEscapeFront); if (idx_end == string::npos) { idx_end = strline.length() - 1; strline.replace(idx_start + 1, idx_end - idx_start, idx_end - idx_start, '$'); contd = true; idx_start = idx_end + 1; } else { if (CurrentQuoteEnd.length() != 3 && (QuoteEscapeRear) && (strline.length() > idx_end + 1) && (strline[idx_end+1] == QuoteEscapeRear)) { strline[idx_end] = '$'; strline[idx_end+1] = '$'; } else { contd = false; strline.replace(idx_start + 1, idx_end - idx_start - 1, idx_end - idx_start - 1, '$'); idx_start = idx_end + 1; } } return 1; }
/*! * Processes physical and logical lines according to language specific rules. * NOTE: all the blank lines + * whole line comments * should have been blanked from filemap by previous processing * before reaching this function * * \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 CTagCounter::LanguageSpecificProcess(filemap* fmap, results* result, filemap* fmapBak) { unsigned int cnt = 0; filemap::iterator fit, fitBak; string line, lineBak; size_t lineNumber = 0; string exclude = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$"; string strLSLOC, strLSLOCBak; char prev_char = 0; bool ok, data_continue = false; unsigned int phys_exec_lines = 0; unsigned int phys_data_lines = 0; unsigned int temp_lines = 0; size_t idx_start, quote_idx_start; char CurrentQuoteEnd = 0; bool quote_contd = false; QuoteStart = ">"; QuoteEnd = "<"; for (fit = fmap->begin(), fitBak = fmapBak->begin(); fit != fmap->end(); fit++, fitBak++) { if (!CUtil::CheckBlank(fit->line)) { // replace "quotes" - string between close and open tags // must be processed after comments since comments start/end with same character as tag quote_idx_start = 0; idx_start = 0; if (quote_contd) { // replace quote until next character ReplaceQuote(fit->line, quote_idx_start, quote_contd, CurrentQuoteEnd); } if (!quote_contd) { while (idx_start < fit->line.length()) { quote_idx_start = FindQuote(fit->line, QuoteStart, quote_idx_start, QuoteEscapeFront); if (quote_idx_start == string::npos) break; ReplaceQuote(fit->line, quote_idx_start, quote_contd, CurrentQuoteEnd); if (quote_idx_start > idx_start) { // comment delimiter inside quote idx_start = quote_idx_start; continue; } } } line = fit->line; lineBak = fitBak->line; lineNumber = fit->lineNumber; LSLOC(result, line, lineNumber, lineBak, strLSLOC, strLSLOCBak, prev_char, data_continue, temp_lines, phys_exec_lines, phys_data_lines); if (print_cmplx) { cnt = 0; CountTagTally(line, exec_name_list, cnt, 1, exclude, "", "", &result->exec_name_count, false); } result->exec_lines[PHY] += phys_exec_lines; phys_exec_lines = 0; result->data_lines[PHY] += phys_data_lines; phys_data_lines = 0; } } QuoteStart = ""; QuoteEnd = ""; // capture closing tag if (strLSLOC.length() > 0) { bool trunc_flag = false; if (strLSLOCBak.length() == this->lsloc_truncate) trunc_flag = true; ok = result->addSLOC(strLSLOCBak, lineNumber, trunc_flag); cnt = 0; if (data_name_list.size() > 0) CUtil::CountTally(strLSLOC, data_name_list, cnt, 1, exclude, "", "", &result->data_name_count); if (data_continue || cnt > 0) { if (ok) result->data_lines[LOG]++; result->data_lines[PHY]++; } else { if (ok) result->exec_lines[LOG]++; // since physical data lines are recorded at next LSLOC, check if first line was a data line if (data_name_list.size() > 0) { fit = fmap->begin(); cnt = 0; CUtil::CountTally(fit->line, data_name_list, cnt, 1, exclude, "", "", NULL); if (cnt > 0) result->exec_lines[PHY]++; } } } return 0; }
/*! * 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; }