am_status_t Properties::parseBuffer(char *buffer) { am_status_t status = AM_SUCCESS; char *nextLine; #if defined(_AMD64_) size_t len; #else int len; #endif try { for (buffer = skipWhitespaceAndComments(buffer); *buffer; buffer = skipWhitespaceAndComments(nextLine)) { char *start = buffer; nextLine = terminateLine(buffer); // XXX - Should handle backslash escapes in the key buffer = findSeparator(start); if (start == buffer) { break; } std::string key(start, buffer - start); buffer = skipWhitespace(buffer); if (*buffer && isSeparator(*buffer)) { buffer += 1; buffer = skipWhitespace(buffer); } len = strlen(buffer) -1; while ((len > 0) && (buffer[len] == ' ')) { buffer[len--] = '\0'; } // XXX - Should handle backslash escapes in the value set(key, buffer); } if (*buffer) { status = AM_FAILURE; } } catch (const std::bad_alloc&) { status = AM_NO_MEMORY; } return status; }
/** Skips whitespace (including lineBreaks, if desired) & comments, then reads one token. A token can be: - a string ("" delimited; ignores readToEOL) - whitespace-delimited (if readToEOL == false) - EOL- or comment-delimited (if readToEOL == true); i.e. reads to end of line or the first // or /* @param text adjusted to start beyond the read token */ static gsl::cstring_view GetToken( gsl::cstring_view& text, bool allowLineBreaks, bool readToEOL = false ) { skipWhitespaceAndComments( text, allowLineBreaks ); // EOF if( text.empty() ) { return{}; } // string. ignores readToEOL. if( text[ 0 ] == '"' ) { // there are no escapes, string just ends at the next " auto tokenEnd = std::find( text.begin() + 1, text.end(), '"' ); if( tokenEnd == text.end() ) { gsl::cstring_view token = { text.begin() + 1, text.end() }; text = { text.end(), text.end() }; return token; } else { gsl::cstring_view token = { text.begin() + 1, tokenEnd }; text = { tokenEnd + 1, text.end() }; return token; } } else if( readToEOL ) { // find the first of '\n', "//" or "/*"; that's end of token auto tokenEnd = std::find( text.begin(), text.end(), '\n' ); static const std::array< char, 2 > commentPatterns[]{ { { '/', '*' } }, { { '/', '/' } } }; for( auto& pattern : commentPatterns ) { tokenEnd = std::min( tokenEnd, std::search( text.begin(), tokenEnd, pattern.begin(), pattern.end() ) ); } gsl::cstring_view token{ text.begin(), tokenEnd }; text = { tokenEnd, text.end() }; return removeTrailingWhitespace( token ); } else { // consume until first whitespace (if allowLineBreaks == false, that may be text.begin(); in that case token is empty.) auto tokenEnd = std::find_if( text.begin(), text.end(), static_cast< int( *)( int ) >( std::isspace ) ); gsl::cstring_view token{ text.begin(), tokenEnd }; text = { tokenEnd, text.end() }; return token; } }
int lexer(void) { char c; if ((c = skipWhitespaceAndComments()) == EOF) return(lexLiteral(c)); else return((*lexDispatchTable[c])(c)); }
static void skipWhitespaceAndComments( gsl::cstring_view& text, const bool allowLineBreaks ) { skipWhitespace( text, allowLineBreaks ); // skip single line comment if( text.size() >= 2 && text[ 0 ] == '/' && text[ 1 ] == '/' ) { auto commentEnd = std::find( text.begin() + 2, text.end(), '\n' ); if( commentEnd == text.end() ) { text = { text.end(), text.end() }; return; } else { text = { commentEnd, text.end() }; skipWhitespaceAndComments( text, allowLineBreaks ); return; } } // skip multi line comments if( text.size() >= 2 && text[ 0 ] == '/' && text[ 1 ] == '*' ) { static const std::array< char, 2 > endStr{ '*', '/' }; auto commentEnd = std::search( text.begin(), text.end(), endStr.begin(), endStr.end() ); if( commentEnd == text.end() ) { text = { text.end(), text.end() }; return; } else { text = { commentEnd + endStr.size(), text.end() }; skipWhitespace( text, allowLineBreaks ); return; } } // found start of token return; }