// stringutils.cpp /* Copyright 2009 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * * As a special exception, the copyright holders give permission to link the * code of portions of this program with the OpenSSL library under certain * conditions as described in each individual source file and distribute * linked combinations including the program with the OpenSSL library. You * must comply with the GNU Affero General Public License in all respects * for all of the code used other than as permitted herein. If you modify * file(s) with this exception, you may extend this exception to your * version of the file(s), but you are not obligated to do so. If you do not * wish to do so, delete this exception statement from your version. If you * delete this exception statement from all source files in the program, * then also delete it in the license file. */ #include "mongo/platform/basic.h" #include "mongo/util/stringutils.h" namespace mongo { using std::string; using std::vector; void splitStringDelim( const string& str , vector* res , char delim ) { if ( str.empty() ) return; size_t beg = 0; size_t pos = str.find( delim ); while ( pos != string::npos ) { res->push_back( str.substr( beg, pos - beg) ); beg = ++pos; pos = str.find( delim, beg ); } res->push_back( str.substr( beg ) ); } void joinStringDelim( const vector& strs , string* res , char delim ) { for ( vector::const_iterator it = strs.begin(); it != strs.end(); ++it ) { if ( it !=strs.begin() ) res->push_back( delim ); res->append( *it ); } } LexNumCmp::LexNumCmp( bool lexOnly ) : _lexOnly( lexOnly ) { } int LexNumCmp::cmp( StringData sd1, StringData sd2, bool lexOnly ) { bool startWord = true; size_t s1 = 0; size_t s2 = 0; while( s1 < sd1.size() && s2 < sd2.size() ) { bool d1 = ( sd1[s1] == '.' ); bool d2 = ( sd2[s2] == '.' ); if ( d1 && !d2 ) return -1; if ( d2 && !d1 ) return 1; if ( d1 && d2 ) { ++s1; ++s2; startWord = true; continue; } bool p1 = ( sd1[s1] == (char)255 ); bool p2 = ( sd2[s2] == (char)255 ); if ( p1 && !p2 ) return 1; if ( p2 && !p1 ) return -1; if ( !lexOnly ) { bool n1 = isdigit( sd1[s1] ); bool n2 = isdigit( sd2[s2] ); if ( n1 && n2 ) { // get rid of leading 0s if ( startWord ) { while ( s1 < sd1.size() && sd1[s1] == '0' ) s1++; while ( s2 < sd2.size() && sd2[s2] == '0' ) s2++; } size_t e1 = s1; size_t e2 = s2; while ( e1 < sd1.size() && isdigit( sd1[e1] ) ) e1++; while ( e2 < sd2.size() && isdigit( sd2[e2] ) ) e2++; size_t len1 = e1-s1; size_t len2 = e2-s2; int result; // if one is longer than the other, return if ( len1 > len2 ) { return 1; } else if ( len2 > len1 ) { return -1; } // if the lengths are equal, just strcmp else { result = strncmp( sd1.rawData() + s1, sd2.rawData() + s2, len1 ); if ( result ) return ( result > 0) ? 1 : -1; } // otherwise, the numbers are equal s1 = e1; s2 = e2; startWord = false; continue; } if ( n1 ) return 1; if ( n2 ) return -1; } if ( sd1[s1] > sd2[s2] ) return 1; if ( sd2[s2] > sd1[s1] ) return -1; s1++; s2++; startWord = false; } if ( s1 < sd1.size() && sd1[s1] ) return 1; if ( s2 < sd2.size() && sd2[s2] ) return -1; return 0; } int LexNumCmp::cmp( StringData s1, StringData s2 ) const { return cmp( s1, s2, _lexOnly ); } bool LexNumCmp::operator()( StringData s1, StringData s2 ) const { return cmp( s1, s2 ) < 0; } int versionCmp(const StringData rhs, const StringData lhs) { if (rhs == lhs) return 0; // handle "1.2.3-" and "1.2.3-pre" if (rhs.size() < lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), rhs.size()) == 0 && lhs[rhs.size()] == '-') return +1; } else if (rhs.size() > lhs.size()) { if (strncmp(rhs.rawData(), lhs.rawData(), lhs.size()) == 0 && rhs[lhs.size()] == '-') return -1; } return LexNumCmp::cmp(rhs, lhs, false); } } // namespace mongo