// @file str.h /* Copyright 2010 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. */ #pragma once /** * String utilities. * * TODO: De-inline. * TODO: Retire the mongoutils namespace, and move str under the mongo namespace. */ #include #include #include "mongo/bson/util/builder.h" namespace mongoutils { namespace str { /** the idea here is to make one liners easy. e.g.: return str::stream() << 1 << ' ' << 2; since the following doesn't work: (std::stringstream() << 1).str(); */ class stream { public: mongo::StringBuilder ss; template stream& operator<<(const T& v) { ss << v; return *this; } operator std::string () const { return ss.str(); } }; inline bool startsWith(const char *str, const char *prefix) { const char *s = str; const char *p = prefix; while( *p ) { if( *p != *s ) return false; p++; s++; } return true; } inline bool startsWith(const std::string& s, const std::string& p) { return startsWith(s.c_str(), p.c_str()); } // while these are trivial today use in case we do different wide char things later inline bool startsWith(const char *p, char ch) { return *p == ch; } inline bool startsWith(const std::string& s, char ch) { return startsWith(s.c_str(), ch); } inline bool endsWith(const std::string& s, const std::string& p) { int l = p.size(); int x = s.size(); if( x < l ) return false; return strncmp(s.c_str()+x-l, p.c_str(), l) == 0; } inline bool endsWith(const char *s, char p) { size_t len = strlen(s); return len && s[len-1] == p; } inline bool endsWith(const char *p, const char *suffix) { size_t a = strlen(p); size_t b = strlen(suffix); if ( b > a ) return false; return strcmp(p + a - b, suffix) == 0; } inline bool equals( const char * a , const char * b ) { return strcmp( a , b ) == 0; } /** find char x, and return rest of std::string thereafter, or "" if not found */ inline const char * after(const char *s, char x) { const char *p = strchr(s, x); return (p != 0) ? p+1 : ""; } inline std::string after(const std::string& s, char x) { const char *p = strchr(s.c_str(), x); return (p != 0) ? std::string(p+1) : ""; } /** find std::string x, and return rest of std::string thereafter, or "" if not found */ inline const char * after(const char *s, const char *x) { const char *p = strstr(s, x); return (p != 0) ? p+strlen(x) : ""; } inline std::string after(const std::string& s, const std::string& x) { const char *p = strstr(s.c_str(), x.c_str()); return (p != 0) ? std::string(p+x.size()) : ""; } /** @return true if s contains x * These should not be used with strings containing NUL bytes */ inline bool contains(const std::string& s, const std::string& x) { return strstr(s.c_str(), x.c_str()) != 0; } inline bool contains(const std::string& s, char x) { verify(x != '\0'); // this expects c-strings so don't use when looking for NUL bytes return strchr(s.c_str(), x) != 0; } /** @return everything before the character x, else entire std::string */ inline std::string before(const std::string& s, char x) { const char *p = strchr(s.c_str(), x); return (p != 0) ? s.substr(0, p-s.c_str()) : s; } /** @return everything before the std::string x, else entire std::string */ inline std::string before(const std::string& s, const std::string& x) { const char *p = strstr(s.c_str(), x.c_str()); return (p != 0) ? s.substr(0, p-s.c_str()) : s; } /** check if if strings share a common starting prefix @return offset of divergence (or length if equal). 0=nothing in common. */ inline int shareCommonPrefix(const char *p, const char *q) { int ofs = 0; while( 1 ) { if( *p == 0 || *q == 0 ) break; if( *p != *q ) break; p++; q++; ofs++; } return ofs; } inline int shareCommonPrefix(const std::string &a, const std::string &b) { return shareCommonPrefix(a.c_str(), b.c_str()); } /** std::string to unsigned. zero if not a number. can end with non-num chars */ inline unsigned toUnsigned(const std::string& a) { unsigned x = 0; const char *p = a.c_str(); while( 1 ) { if( !isdigit(*p) ) break; x = x * 10 + (*p - '0'); p++; } return x; } /** split a std::string on a specific char. We don't split N times, just once on the first occurrence. If char not present entire std::string is in L and R is empty. @return true if char found */ inline bool splitOn(const std::string &s, char c, std::string& L, std::string& R) { const char *start = s.c_str(); const char *p = strchr(start, c); if( p == 0 ) { L = s; R.clear(); return false; } L = std::string(start, p-start); R = std::string(p+1); return true; } /** split scanning reverse direction. Splits ONCE ONLY. */ inline bool rSplitOn(const std::string &s, char c, std::string& L, std::string& R) { const char *start = s.c_str(); const char *p = strrchr(start, c); if( p == 0 ) { L = s; R.clear(); return false; } L = std::string(start, p-start); R = std::string(p+1); return true; } /** @return number of occurrences of c in s */ inline unsigned count( const std::string& s , char c ) { unsigned n=0; for ( unsigned i=0; i