/** * check for SQL "END DECLARE SECTION". * must compare case insensitive and allow any spacing between words. * * @param line a reference to the line to indent. * @param index the current line index. * @return true if a hit. */ bool ASEnhancer::isEndDeclareSectionSQL(string& line, size_t index) const { string word; size_t hits = 0; size_t i; for(i = index; i < line.length(); i++) { i = line.find_first_not_of(" \t", i); if(i == string::npos) return false; if(line[i] == ';') break; if(!isCharPotentialHeader(line, i)) continue; word = getCurrentWord(line, i); for(size_t j = 0; j < word.length(); j++) word[j] = (char)toupper(word[j]); if(word == "EXEC" || word == "SQL") { i += word.length() - 1; continue; } if(word == "DECLARE" || word == "SECTION") { hits++; i += word.length() - 1; continue; } if(word == "END") { hits++; i += word.length() - 1; continue; } return false; } if(hits == 3) return true; return false; }
// get the current word on a line // index must point to the beginning of the word string ASBase::getCurrentWord(const string& line, size_t index) const { assert(isCharPotentialHeader(line, index)); size_t lineLength = line.length(); size_t i; for(i = index; i < lineLength; i++) { if(!isLegalNameChar(line[i])) break; } return line.substr(index, i - index); }
// get the current word on a line // i must point to the beginning of the word string ASBase::getCurrentWord(const string& line, size_t charNum) const { assert(isCharPotentialHeader(line, charNum)); size_t lineLength = line.length(); size_t i; for (i = charNum; i < lineLength; i++) { if (!isLegalNameChar(line[i])) break; } return line.substr(charNum, i - charNum); }
// check if a specific line position contains a keyword. bool ASBase::findKeyword(const string& line, int i, const string& keyword) const { assert(isCharPotentialHeader(line, i)); // check the word const size_t keywordLength = keyword.length(); const size_t wordEnd = i + keywordLength; if(wordEnd > line.length()) return false; if(line.compare(i, keywordLength, keyword) != 0) return false; // check that this is not part of a longer word if(wordEnd == line.length()) return true; if(isLegalNameChar(line[wordEnd])) return false; // is not a keyword if part of a definition const char peekChar = peekNextChar(line, wordEnd - 1); if(peekChar == ',' || peekChar == ')') return false; return true; }
// check if a specific line position contains a header. const string* ASBase::findHeader(const string& line, int i, const vector<const string*>* possibleHeaders) const { assert(isCharPotentialHeader(line, i)); // check the word size_t maxHeaders = possibleHeaders->size(); for (size_t p = 0; p < maxHeaders; p++) { const string* header = (*possibleHeaders)[p]; const size_t wordEnd = i + header->length(); if (wordEnd > line.length()) continue; int result = (line.compare(i, header->length(), *header)); if (result > 0) continue; if (result < 0) break; // check that this is not part of a longer word if (wordEnd == line.length()) return header; if (isLegalNameChar(line[wordEnd])) continue; const char peekChar = peekNextChar(line, wordEnd - 1); // is not a header if part of a definition if (peekChar == ',' || peekChar == ')') break; // the following accessor definitions are NOT headers // goto default; is NOT a header // default(int) keyword in C# is NOT a header if ((header == &AS_GET || header == &AS_SET || header == &AS_DEFAULT) && (peekChar == ';' || peekChar == '(' || peekChar == '=')) break; return header; } return nullptr; }
/** * process the character at the current index in a switch block. * * @param line a reference to the line to indent. * @param index the current line index. * @return the new line index. */ size_t ASEnhancer::processSwitchBlock(string& line, size_t index) { size_t i = index; bool isPotentialKeyword = isCharPotentialHeader(line, i); if (line[i] == '{') { sw.switchBracketCount++; if (lookingForCaseBracket) // if 1st after case statement { sw.unindentCase = true; // unindenting this case sw.unindentDepth++; lookingForCaseBracket = false; // not looking now } return i; } lookingForCaseBracket = false; // no opening bracket, don't indent if (line[i] == '}') // if close bracket { sw.switchBracketCount--; assert(sw.switchBracketCount <= bracketCount); if (sw.switchBracketCount == 0) // if end of switch statement { int lineUnindent = sw.unindentDepth; if (line.find_first_not_of(" \t") == i && switchStack.size() > 0) lineUnindent = switchStack[switchStack.size()-1].unindentDepth; if (shouldIndentLine) { if (lineUnindent > 0) i -= unindentLine(line, lineUnindent); shouldIndentLine = false; } switchDepth--; sw = switchStack.back(); switchStack.pop_back(); } return i; } if (isPotentialKeyword && (findKeyword(line, i, "case") || findKeyword(line, i, "default"))) { if (sw.unindentCase) // if unindented last case { sw.unindentCase = false; // stop unindenting previous case sw.unindentDepth--; } i = findCaseColon(line, i); i++; for (; i < line.length(); i++) // bypass whitespace { if (!isWhiteSpace(line[i])) break; } if (i < line.length()) { if (line[i] == '{') { bracketCount++; sw.switchBracketCount++; if (!isOneLineBlockReached(line, i)) unindentNextLine = true; return i; } } lookingForCaseBracket = true; i--; // need to process this char return i; } if (isPotentialKeyword) { string name = getCurrentWord(line, i); // bypass the entire name i += name.length() - 1; } return i; }
/** * additional formatting for line of source code. * every line of source code in a source code file should be sent * one after the other to this function. * indents event tables * unindents the case blocks * * @param line the original formatted line will be updated if necessary. */ void ASEnhancer::enhance(string& line, bool isInPreprocessor, bool isInSQL) { bool isSpecialChar = false; // is a backslash escape character shouldIndentLine = true; lineNumber++; // check for beginning of event table if (nextLineIsEventIndent) { isInEventTable = true; nextLineIsEventIndent = false; } // check for beginning of SQL declare section if (nextLineIsDeclareIndent) { isInDeclareSection = true; nextLineIsDeclareIndent = false; } if (line.length() == 0 && ! isInEventTable && ! isInDeclareSection && ! emptyLineFill) return; // test for unindent on attached brackets if (unindentNextLine) { sw.unindentDepth++; sw.unindentCase = true; unindentNextLine = false; } // parse characters in the current line. for (size_t i = 0; i < line.length(); i++) { char ch = line[i]; // bypass whitespace if (isWhiteSpace(ch)) continue; // handle special characters (i.e. backslash+character such as \n, \t, ...) if (isSpecialChar) { isSpecialChar = false; continue; } if (!(isInComment) && line.compare(i, 2, "\\\\") == 0) { i++; continue; } if (!(isInComment) && ch == '\\') { isSpecialChar = true; continue; } // handle quotes (such as 'x' and "Hello Dolly") if (!isInComment && (ch == '"' || ch == '\'')) { if (!isInQuote) { quoteChar = ch; isInQuote = true; } else if (quoteChar == ch) { isInQuote = false; continue; } } if (isInQuote) continue; // handle comments if (!(isInComment) && line.compare(i, 2, "//") == 0) { // check for windows line markers if (line.compare(i + 2, 1, "\xf0") > 0) lineNumber--; break; // finished with the line } else if (!(isInComment) && line.compare(i, 2, "/*") == 0) { isInComment = true; i++; continue; } else if ((isInComment) && line.compare(i, 2, "*/") == 0) { isInComment = false; i++; continue; } if (isInComment) continue; // if we have reached this far then we are NOT in a comment or string of special characters if (line[i] == '{') bracketCount++; if (line[i] == '}') bracketCount--; bool isPotentialKeyword = isCharPotentialHeader(line, i); // ---------------- wxWidgets and MFC macros ---------------------------------- if (isPotentialKeyword) { if (findKeyword(line, i, "BEGIN_EVENT_TABLE") || findKeyword(line, i, "BEGIN_DISPATCH_MAP") || findKeyword(line, i, "BEGIN_EVENT_MAP") || findKeyword(line, i, "BEGIN_MESSAGE_MAP") || findKeyword(line, i, "BEGIN_PROPPAGEIDS")) { nextLineIsEventIndent = true; break; } if (findKeyword(line, i, "END_EVENT_TABLE") || findKeyword(line, i, "END_DISPATCH_MAP") || findKeyword(line, i, "END_EVENT_MAP") || findKeyword(line, i, "END_MESSAGE_MAP") || findKeyword(line, i, "END_PROPPAGEIDS")) { isInEventTable = false; break; } } // ---------------- process SQL ----------------------------------------------- if (isInSQL) { if (isBeginDeclareSectionSQL(line, i)) nextLineIsDeclareIndent = true; if (isEndDeclareSectionSQL(line, i)) isInDeclareSection = false; break; } // ---------------- process switch statements --------------------------------- if (isPotentialKeyword && findKeyword(line, i, "switch")) { switchDepth++; switchStack.push_back(sw); // save current variables sw.switchBracketCount = 0; sw.unindentCase = false; // don't clear case until end of switch i += 5; // bypass switch statement continue; } // just want unindented switch statements from this point if (caseIndent || switchDepth == 0 || (isInPreprocessor && !preprocessorIndent)) { // bypass the entire word if (isPotentialKeyword) { string name = getCurrentWord(line, i); i += name.length() - 1; } continue; } i = processSwitchBlock(line, i); } // end of for loop * end of for loop * end of for loop * end of for loop if (isInEventTable || isInDeclareSection) { if (line.length() == 0 || line[0] != '#') indentLine(line, 1); } if (shouldIndentLine && sw.unindentDepth > 0) unindentLine(line, sw.unindentDepth); }
/** * process the character at the current index in a switch block. * * @param line a reference to the line to indent. * @param index the current line index. * @return the new line index. */ size_t ASEnhancer::processSwitchBlock(string &line, size_t index) { size_t i = index; bool isPotentialKeyword = isCharPotentialHeader(line, i); if (line[i] == '{') { sw.switchBracketCount++; if (lookingForCaseBracket) // if 1st after case statement { sw.unindentCase = true; // unindenting this case sw.unindentDepth++; lookingForCaseBracket = false; // not looking now } return i; } lookingForCaseBracket = false; // no opening bracket, don't indent if (line[i] == '}') // if close bracket { sw.switchBracketCount--; if (sw.switchBracketCount == 0) // if end of switch statement { switchDepth--; // one less switch sw = swVector.back(); // restore sw struct swVector.pop_back(); // remove last entry from stack } return i; } if (isPotentialKeyword && (findKeyword(line, i, "case") || findKeyword(line, i, "default"))) { if (sw.unindentCase) // if unindented last case { sw.unindentCase = false; // stop unindenting previous case sw.unindentDepth--; // reduce depth } i = findCaseColon(line, i); i++; for (; i < line.length(); i++) // bypass whitespace { if (!isWhiteSpace(line[i])) break; } if (i < line.length()) { if (line[i] == '{') { sw.switchBracketCount++; unindentNextLine = true; return i; } } lookingForCaseBracket = true; // bracket must be on next line i--; // need to check for comments return i; } if (isPotentialKeyword) { string name = getCurrentWord(line, i); // bypass the entire name i += name.length() - 1; } return i; }