// @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