*/
#include <list>
+#include <msp/core/error.h>
#include "utils.h"
using namespace std;
namespace Msp {
-/**
-Compares two strings, ignoring case.
-
-@param s1 First string
-@param s2 Second string
-
-@return -1 if s1<s2, 0 if s1==s2, 1 if s1>s2
-*/
int strcasecmp(const string &s1, const string &s2)
{
string::const_iterator i1=s1.begin();
return 0;
}
-/**
-Returns a lowercase copy of the given string.
-*/
string tolower(const string &str)
{
string result(str);
return result;
}
-/**
-Returns an uppercase copy of the given string.
-*/
string toupper(const string &str)
{
string result(str);
return result;
}
-vector<string> split_fields(const string &str, const string &sep, int max_split)
+vector<string> split(const string &str, const string &sep, int max_split)
{
- return do_split<true, true>(str, sep, max_split);
+ return do_split<false, false>(str, sep, max_split);
}
-vector<string> split_fields(const string &str, char sep, int max_split)
+vector<string> split(const string &str, char sep, int max_split)
{
- return split_fields(str, string(1, sep), max_split);
+ return split(str, string(1, sep), max_split);
}
vector<string> split_long(const string &str, const string &sep, int max_split)
return do_split<true, false>(str, sep, max_split);
}
-vector<string> split(const string &str, const string &sep, int max_split)
+vector<string> split_fields(const string &str, const string &sep, int max_split)
{
- return do_split<false, false>(str, sep, max_split);
+ return do_split<true, true>(str, sep, max_split);
}
-vector<string> split(const string &str, char sep, int max_split)
+vector<string> split_fields(const string &str, char sep, int max_split)
{
- return split(str, string(1, sep), max_split);
+ return split_fields(str, string(1, sep), max_split);
}
/**
return split(str, string(1, sep), allow_empty);
}
-/**
-Builds a single string from the strings in the given sequence by concatenating
-them.
+string strip(const string &s)
+{
+ string result=s;
+ if(!result.erase(0, result.find_first_not_of(" \t\r\n")).empty())
+ result.erase(result.find_last_not_of(" \t\r\n")+1);
+ return result;
+}
-@param seq A sequence of strings
-@param sep Separator to be inserted between strings
-*/
-template<typename T>
-string join(const T &seq, const string &sep)
+string c_unescape(const std::string &str)
{
+ bool escape=false;
+ unsigned numeric_type=0;
+ unsigned numeric_pos=0;
+ unsigned numeric_value=0;
string result;
- for(typename T::const_iterator i=seq.begin(); i!=seq.end(); ++i)
+ for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
{
- if(i!=seq.begin())
- result+=sep;
- result+=*i;
+ if(numeric_type==1)
+ {
+ unsigned digit=0;
+ if(*i>='0' && *i<='9')
+ digit=*i-'0';
+ else if(*i>='a' && *i<='f')
+ digit=*i-'a'+10;
+ else if(*i>='A' && *i<='F')
+ digit=*i-'A'+10;
+ else
+ throw InvalidParameterValue("Invalid hexadecimal digit");
+
+ numeric_value=(numeric_value<<4 | digit);
+ ++numeric_pos;
+ if(numeric_pos==2)
+ {
+ result+=numeric_value;
+ numeric_type=0;
+ }
+ }
+ else if(numeric_type==2)
+ {
+ unsigned digit=0;
+ if(*i>='0' && *i<='7')
+ digit=*i-'0';
+ else
+ throw InvalidParameterValue("Invalid octal digit");
+
+ if(numeric_pos==0 && digit>3)
+ throw InvalidParameterValue("Octal escape sequence must start with [0-3]");
+
+ numeric_value=(numeric_value<<3 | digit);
+ ++numeric_pos;
+ if(numeric_pos==2)
+ {
+ result+=numeric_value;
+ numeric_type=0;
+ }
+ }
+ else if(escape)
+ {
+ if(*i=='x' || (*i>='0' && *i<='7'))
+ {
+ numeric_type=(*i=='x' ? 1 : 2);
+ numeric_pos=0;
+ numeric_value=0;
+ }
+ else if(*i=='n')
+ result+='\n';
+ else if(*i=='t')
+ result+='\t';
+ else if(*i=='r')
+ result+='\r';
+ else if(*i=='b')
+ result+='\b';
+ else if(*i=='v')
+ result+='\v';
+ else if(*i=='a')
+ result+='\a';
+ else if(*i=='f')
+ result+='\f';
+ else if(*i=='\"')
+ result+='\"';
+ else if(*i=='\'')
+ result+='\'';
+ else if(*i=='\\')
+ result+='\\';
+ else
+ throw InvalidParameterValue("Invalid escape sequence");
+
+ escape=false;
+ }
+ else if(*i=='\\')
+ escape=true;
+ else
+ result+=*i;
}
+ if(escape)
+ throw InvalidParameterValue("Stray backslash at end of string");
+
return result;
}
-template string join<list<string> >(const list<string> &, const string &);
-template string join<vector<string> >(const vector<string> &, const string &);
-/**
-Returns a copy of the given string with leading and trailing whitespace
-removed.
-*/
-string strip(const string &s)
+string c_escape(const string &str, bool escape_8bit)
{
- string result=s;
- if(!result.erase(0, result.find_first_not_of(" \t\r\n")).empty())
- result.erase(result.find_last_not_of(" \t\r\n")+1);
+ string result;
+
+ for(string::const_iterator i=str.begin(); i!=str.end(); ++i)
+ {
+ if(*i=='\n')
+ result+="\\n";
+ else if(*i=='\t')
+ result+="\\t";
+ else if(*i=='\r')
+ result+="\\r";
+ else if(*i=='\b')
+ result+="\\b";
+ else if(*i=='\v')
+ result+="\\v";
+ else if(*i=='\a')
+ result+="\\a";
+ else if(*i=='\f')
+ result+="\\f";
+ else if(*i=='\"')
+ result+="\\\"";
+ else if(*i=='\'')
+ result+="\\\'";
+ else if(*i=='\\')
+ result+="\\\\";
+ else if(*i<' ' || (escape_8bit && (*i&0x80)))
+ {
+ char buf[4]={'\\', (*i>>6)&7, (*i>>3)&7, *i&7};
+ result.append(buf, 4);
+ }
+ else
+ result+=*i;
+ }
+
return result;
}
namespace Msp {
-int strcasecmp(const std::string &, const std::string &);
+/**
+Compares two strings, ignoring upper/lower case.
+
+@param s1 First string
+@param s2 Second string
+
+@return -1 if s1<s2, 0 if s1==s2, 1 if s1>s2
+*/
+int strcasecmp(const std::string &s1, const std::string &s2);
+
+/**
+Converts a string to lower case.
+*/
std::string tolower(const std::string &);
+
+/**
+Converts a string to upper case.
+*/
std::string toupper(const std::string &);
-std::vector<std::string> split_fields(const std::string &, const std::string &, int =-1);
-std::vector<std::string> split_fields(const std::string &, char, int =-1);
-std::vector<std::string> split_long(const std::string &, const std::string &, int =-1);
-std::vector<std::string> split(const std::string &, const std::string & =" \t\r\n", int =-1);
-std::vector<std::string> split(const std::string &, char, int =-1);
+/**
+Splits a string at occurrences of any of the characters in sep. If max_split
+is non-negative, at most that many split will be performed, i.e. the resulting
+vector will contain at most max_split+1 elements. Two or more consecutive
+separator characters will be treated as a single separator.
+
+@param str A string
+@param sep Separator characters
+@param max_split Maximum number of splits to perform
+*/
+std::vector<std::string> split(const std::string &str, const std::string &sep=" \t\r\n", int max_split=-1);
+
+/**
+Splits a string on occurrences of a single character.
+*/
+std::vector<std::string> split(const std::string &str, char sep, int max_split=-1);
+
+/**
+Splits a string on occurrences of another string.
+*/
+std::vector<std::string> split_long(const std::string &str, const std::string &sep, int max_split=-1);
+
+/**
+Splits a string on occurrences of another string. Two consecutive separators
+will cause an empty string to be placed in the result.
+*/
+std::vector<std::string> split_fields(const std::string &str, const std::string &sep, int max_split=-1);
+
+/**
+Splits a string on occurrences of a single character. Two consecutive
+separators will cause an empty string to be placed in the result.
+*/
+std::vector<std::string> split_fields(const std::string &str, char sep, int max_split=-1);
+
+/**
+Concatenates strings from an iterator range.
+
+@param begin First iterator
+@param end Last iterator
+@param sep Separator to be inserted between strings
+*/
+template<typename Iter>
+std::string join(Iter begin, Iter end, const std::string &sep=" ")
+{
+ std::string result;
+ for(Iter i=begin; i!=end; ++i)
+ {
+ if(i!=begin)
+ result+=sep;
+ result+=*i;
+ }
+
+ return result;
+}
-template<typename T>
-std::string join(const T &, const std::string & =" ");
+/**
+Strips leading and trailing whitespace from a string.
+*/
std::string strip(const std::string &);
+/**
+Unescapes a string with C escape sequences.
+*/
+std::string c_unescape(const std::string &str);
+
+/**
+Escapes any non-printable characters in a string with C escape sequences.
+
+@param str A string
+@param escape_8bit If true, consider characters with high bit set as
+ non-printable
+
+@return An escaped version of the string
+*/
+std::string c_escape(const std::string &str, bool escape_8bit=true);
+
} // namespace Msp
#endif