Browse Source

Rewritten util::split and added its iterator version.

Iterator based functions util::startsWith, util::endsWith,
util::streq, util::strieq were added.
Tatsuhiro Tsujikawa 14 years ago
parent
commit
f84d2253b2

+ 11 - 8
src/AbstractCommand.cc

@@ -589,16 +589,19 @@ namespace {
 bool inNoProxy(const SharedHandle<Request>& req,
                const std::string& noProxy)
 {
-  std::vector<std::string> entries;
-  util::split(noProxy, std::back_inserter(entries), ",", true);
+  std::vector<Scip> entries;
+  util::splitIter(noProxy.begin(), noProxy.end(), std::back_inserter(entries),
+                  ',', true);
   if(entries.empty()) {
     return false;
   }
-  for(std::vector<std::string>::const_iterator i = entries.begin(),
+  for(std::vector<Scip>::const_iterator i = entries.begin(),
         eoi = entries.end(); i != eoi; ++i) {
-    std::string::size_type slashpos = (*i).find('/');
-    if(slashpos == std::string::npos) {
-      if(util::noProxyDomainMatch(req->getHost(), *i)) {
+    std::string::const_iterator slashpos =
+      std::find((*i).first, (*i).second, '/');
+    if(slashpos == (*i).second) {
+      if(util::noProxyDomainMatch
+         (req->getHost(), std::string((*i).first, (*i).second))) {
         return true;
       }
     } else {
@@ -606,9 +609,9 @@ bool inNoProxy(const SharedHandle<Request>& req,
       // implementation is that we should first resolve
       // hostname(which may result in several IP addresses) and
       // evaluates against all of them
-      std::string ip = (*i).substr(0, slashpos);
+      std::string ip((*i).first, slashpos);
       uint32_t bits;
-      if(!util::parseUIntNoThrow(bits, (*i).begin()+slashpos+1, (*i).end())) {
+      if(!util::parseUIntNoThrow(bits, slashpos+1, (*i).second)) {
         continue;
       }
       if(util::inSameCidrBlock(ip, req->getHost(), bits)) {

+ 24 - 0
src/Cookie.h

@@ -97,6 +97,12 @@ public:
 
   void setName(const std::string& name);
 
+  template<typename InputIterator>
+  void setName(InputIterator first, InputIterator last)
+  {
+    name_.assign(first, last);
+  }
+
   const std::string& getValue() const
   {
     return value_;
@@ -104,6 +110,12 @@ public:
 
   void setValue(const std::string& value);
 
+  template<typename InputIterator>
+  void setValue(InputIterator first, InputIterator last)
+  {
+    value_.assign(first, last);
+  }
+
   time_t getExpiryTime() const
   {
     return expiryTime_;
@@ -131,6 +143,12 @@ public:
 
   void setDomain(const std::string& domain);
 
+  template<typename InputIterator>
+  void setDomain(InputIterator first, InputIterator last)
+  {
+    domain_.assign(first, last);
+  }
+
   bool getHostOnly() const
   {
     return hostOnly_;
@@ -148,6 +166,12 @@ public:
 
   void setPath(const std::string& path);
 
+  template<typename InputIterator>
+  void setPath(InputIterator first, InputIterator last)
+  {
+    path_.assign(first, last);
+  }
+
   bool getSecure() const
   {
     return secure_;

+ 18 - 10
src/CookieStorage.cc

@@ -210,11 +210,19 @@ bool CookieStorage::parseAndStore
 struct CookiePathDivider {
   Cookie cookie_;
   int pathDepth_;
-  CookiePathDivider(const Cookie& cookie):cookie_(cookie)
+  CookiePathDivider(const Cookie& cookie):cookie_(cookie), pathDepth_(0)
   {
-    std::vector<std::string> paths;
-    util::split(cookie_.getPath(), std::back_inserter(paths), A2STR::SLASH_C);
-    pathDepth_ = paths.size();
+    const std::string& path = cookie_.getPath();
+    if(!path.empty()) {
+      for(size_t i = 1, len = path.size(); i < len; ++i) {
+        if(path[i] == '/' && path[i-1] != '/') {
+          ++pathDepth_;
+        }
+      }
+      if(path[path.size()-1] != '/') {
+        ++pathDepth_;
+      }
+    }
   }
 };
 
@@ -302,14 +310,14 @@ std::vector<Cookie> CookieStorage::criteriaFind
       (requestHost, domains_.begin(), domains_.end(), std::back_inserter(res),
        requestHost, requestPath, now, secure);
   } else {
-    std::vector<std::string> levels;
-    util::split(requestHost, std::back_inserter(levels),A2STR::DOT_C);
-    std::reverse(levels.begin(), levels.end());
+    std::vector<Scip> levels;
+    util::splitIter(requestHost.begin(), requestHost.end(),
+                    std::back_inserter(levels), '.');
     std::string domain;
-    for(std::vector<std::string>::const_iterator i =
-          levels.begin(), eoi = levels.end();
+    for(std::vector<Scip>::const_reverse_iterator i =
+          levels.rbegin(), eoi = levels.rend();
         i != eoi; ++i, domain.insert(domain.begin(), '.')) {
-      domain.insert(domain.begin(), (*i).begin(), (*i).end());
+      domain.insert(domain.begin(), (*i).first, (*i).second);
       searchCookieByDomainSuffix
         (domain, domains_.begin(), domains_.end(),
          std::back_inserter(res), requestHost, requestPath, now, secure);

+ 5 - 4
src/FtpConnection.cc

@@ -487,12 +487,13 @@ unsigned int FtpConnection::receiveEpsvResponse(uint16_t& port)
          leftParen > rightParen) {
         return response.first;
       }
-      std::vector<std::string> rd;
-      util::split(response.second.substr(leftParen+1, rightParen-(leftParen+1)),
-                  std::back_inserter(rd), "|", true, true);
+      std::vector<Scip> rd;
+      util::splitIter(response.second.begin()+leftParen+1,
+                      response.second.begin()+rightParen,
+                      std::back_inserter(rd), '|', true, true);
       uint32_t portTemp = 0;
       if(rd.size() == 5 &&
-         util::parseUIntNoThrow(portTemp, rd[3].begin(), rd[3].end())) {
+         util::parseUIntNoThrow(portTemp, rd[3].first, rd[3].second)) {
         if(0 < portTemp  && portTemp <= UINT16_MAX) {
           port = portTemp;
         }

+ 2 - 2
src/FtpNegotiationCommand.cc

@@ -270,9 +270,9 @@ bool FtpNegotiationCommand::sendCwdPrep()
 {
   // Calling setReadCheckSocket() is needed when the socket is reused, 
   setReadCheckSocket(getSocket());
-  util::split(getRequest()->getDir(), std::back_inserter(cwdDirs_),
-              A2STR::SLASH_C);
   cwdDirs_.push_front(ftp_->getBaseWorkingDir());
+  util::split(getRequest()->getDir().begin(), getRequest()->getDir().end(),
+              std::back_inserter(cwdDirs_), '/');
   sequence_ = SEQ_SEND_CWD;
   return true;
 }

+ 18 - 0
src/HttpHeader.h

@@ -95,6 +95,12 @@ public:
 
   void setVersion(const std::string& version);
 
+  template<typename InputIterator>
+  void setVersion(InputIterator first, InputIterator last)
+  {
+    version_.assign(first, last);
+  }
+
   const std::string& getMethod() const
   {
     return method_;
@@ -102,6 +108,12 @@ public:
 
   void setMethod(const std::string& method);
 
+  template<typename InputIterator>
+  void setMethod(InputIterator first, InputIterator last)
+  {
+    method_.assign(first, last);
+  }
+
   const std::string& getRequestPath() const
   {
     return requestPath_;
@@ -109,6 +121,12 @@ public:
 
   void setRequestPath(const std::string& requestPath);
 
+  template<typename InputIterator>
+  void setRequestPath(InputIterator first, InputIterator last)
+  {
+    requestPath_.assign(first, last);
+  }
+
   void fill
   (std::string::const_iterator first,
    std::string::const_iterator last);

+ 6 - 5
src/HttpHeaderProcessor.cc

@@ -139,16 +139,17 @@ SharedHandle<HttpHeader> HttpHeaderProcessor::getHttpRequestHeader()
      delimpos < 14) {
     throw DL_RETRY_EX(EX_NO_STATUS_HEADER);
   }
-  std::vector<std::string> firstLine;
-  util::split(buf_.substr(0, delimpos), std::back_inserter(firstLine)," ",true);
+  std::vector<Scip> firstLine;
+  util::splitIter(buf_.begin(), buf_.begin()+delimpos,
+                  std::back_inserter(firstLine), ' ', true);
   if(firstLine.size() != 3) {
     throw DL_ABORT_EX2("Malformed HTTP request header.",
                        error_code::HTTP_PROTOCOL_ERROR);
   }
   SharedHandle<HttpHeader> httpHeader(new HttpHeader());
-  httpHeader->setMethod(firstLine[0]);
-  httpHeader->setRequestPath(firstLine[1]);
-  httpHeader->setVersion(firstLine[2]);
+  httpHeader->setMethod(firstLine[0].first, firstLine[0].second);
+  httpHeader->setRequestPath(firstLine[1].first, firstLine[1].second);
+  httpHeader->setVersion(firstLine[2].first, firstLine[2].second);
   if((delimpos = buf_.find("\r\n\r\n")) == std::string::npos &&
      (delimpos = buf_.find("\n\n")) == std::string::npos) {
     delimpos = buf_.size();

+ 2 - 3
src/HttpRequest.cc

@@ -317,9 +317,8 @@ void HttpRequest::disableContentEncoding()
 
 void HttpRequest::addHeader(const std::string& headersString)
 {
-  std::vector<std::string> headers;
-  util::split(headersString, std::back_inserter(headers), "\n", true);
-  headers_.insert(headers_.end(), headers.begin(), headers.end());
+  util::split(headersString.begin(), headersString.end(),
+              std::back_inserter(headers_), '\n', true);
 }
 
 void HttpRequest::clearHeader()

+ 6 - 2
src/HttpResponse.cc

@@ -378,8 +378,12 @@ void HttpResponse::getMetalinKHttpEntries
   if(!result.empty()) {
     std::vector<std::string> locs;
     if(option->defined(PREF_METALINK_LOCATION)) {
-      util::split(util::toLower(option->get(PREF_METALINK_LOCATION)),
-                  std::back_inserter(locs), ",", true);
+      const std::string& loc = option->get(PREF_METALINK_LOCATION);
+      util::split(loc.begin(), loc.end(), std::back_inserter(locs), ',', true);
+      for(std::vector<std::string>::iterator i = locs.begin(), eoi = locs.end();
+          i != eoi; ++i) {
+        util::lowercase(*i);
+      }
     }
     for(std::vector<MetalinkHttpEntry>::iterator i = result.begin(),
           eoi = result.end(); i != eoi; ++i) {

+ 22 - 15
src/HttpServer.cc

@@ -49,6 +49,7 @@
 #include "fmt.h"
 #include "SocketRecvBuffer.h"
 #include "TimeA2.h"
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -99,12 +100,20 @@ SharedHandle<HttpHeader> HttpServer::receiveRequest()
       (lastRequestHeader_->getVersion() == HttpHeader::HTTP_1_1 ||
        connection.find("keep-alive") != std::string::npos);
 
-    std::vector<std::string> acceptEncodings;
-    util::split(lastRequestHeader_->getFirst(HttpHeader::ACCEPT_ENCODING),
-                std::back_inserter(acceptEncodings), A2STR::COMMA_C, true);
-    acceptsGZip_ =
-      std::find(acceptEncodings.begin(), acceptEncodings.end(), "gzip")
-      != acceptEncodings.end();
+    std::vector<Scip> acceptEncodings;
+    const std::string& acceptEnc =
+      lastRequestHeader_->getFirst(HttpHeader::ACCEPT_ENCODING);
+    util::splitIter(acceptEnc.begin(), acceptEnc.end(),
+                    std::back_inserter(acceptEncodings), ',', true);
+    const char A2_GZIP[] = "gzip";
+    acceptsGZip_ = false;
+    for(std::vector<Scip>::const_iterator i = acceptEncodings.begin(),
+          eoi = acceptEncodings.end(); i != eoi; ++i) {
+      if(util::streq((*i).first, (*i).second, A2_GZIP, vend(A2_GZIP)-1)) {
+        acceptsGZip_ = true;
+        break;
+      }
+    }
     return header;
   } else {
     socketRecvBuffer_->clearBuffer();
@@ -209,20 +218,18 @@ bool HttpServer::authenticate()
   }
   std::pair<Scip, Scip> p;
   util::divide(p, authHeader.begin(), authHeader.end(), ' ');
-  const char authMethod[] = "Basic";
-  if(!std::distance(p.first.first, p.first.second) == sizeof(authMethod) ||
-     !std::equal(p.first.first, p.first.second, &authMethod[0])) {
+  const char A2_AUTHMETHOD[] = "Basic";
+  if(!util::streq(p.first.first, p.first.second,
+                  A2_AUTHMETHOD, vend(A2_AUTHMETHOD)-1)) {
     return false;
   }
   std::string userpass = Base64::decode(std::string(p.second.first,
                                                     p.second.second));
   util::divide(p, userpass.begin(), userpass.end(), ':');
-  return username_.size() ==
-    static_cast<size_t>(std::distance(p.first.first, p.first.second)) &&
-    std::equal(username_.begin(), username_.end(), p.first.first) &&
-    password_.size() ==
-    static_cast<size_t>(std::distance(p.second.first, p.second.second)) &&
-    std::equal(password_.begin(), password_.end(), p.second.first);
+  return util::streq(p.first.first, p.first.second,
+                     username_.begin(), username_.end()) &&
+    util::streq(p.second.first, p.second.second,
+                password_.begin(), password_.end());
 }
 
 void HttpServer::setUsernamePassword

+ 7 - 2
src/Metalink2RequestGroup.cc

@@ -156,8 +156,13 @@ Metalink2RequestGroup::createRequestGroup
   }
   std::vector<std::string> locations;
   if(optionTemplate->defined(PREF_METALINK_LOCATION)) {
-    util::split(util::toLower(optionTemplate->get(PREF_METALINK_LOCATION)),
-                std::back_inserter(locations), ",", true);
+    const std::string& loc = optionTemplate->get(PREF_METALINK_LOCATION);
+    util::split(loc.begin(), loc.end(),
+                std::back_inserter(locations), ',', true);
+    for(std::vector<std::string>::iterator i = locations.begin(),
+          eoi = locations.end(); i != eoi; ++i) {
+      util::lowercase(*i);
+    }
   }
   std::string preferredProtocol;
   if(optionTemplate->get(PREF_METALINK_PREFERRED_PROTOCOL) != V_NONE) {

+ 2 - 2
src/MultiUrlRequestInfo.cc

@@ -99,9 +99,9 @@ namespace {
 ares_addr_node* parseAsyncDNSServers(const std::string& serversOpt)
 {
   std::vector<std::string> servers;
-  util::split(serversOpt,
+  util::split(serversOpt.begin(), serversOpt.end(),
               std::back_inserter(servers),
-              A2STR::COMMA_C,
+              ',',
               true /* doStrip */);
   ares_addr_node root;
   root.next = 0;

+ 30 - 15
src/Netrc.cc

@@ -43,6 +43,7 @@
 #include "A2STR.h"
 #include "util.h"
 #include "BufferedFile.h"
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -152,44 +153,58 @@ void Netrc::parse(const std::string& path)
     if(util::startsWith(line, "#")) {
       continue;
     }
-    std::vector<std::string> tokens;
-    util::split(line, std::back_inserter(tokens), " \t", true);
-    for(std::vector<std::string>::const_iterator iter = tokens.begin(),
+    std::vector<Scip> tokens;
+    const char A2_DELIMS[] = " \t";
+    util::splitIterM(line.begin(), line.end(), std::back_inserter(tokens),
+                     A2_DELIMS, vend(A2_DELIMS)-1, true);
+    const char A2_MACHINE[] = "machine";
+    const char A2_DEFAULT[] = "default";
+    const char A2_LOGIN[] = "login";
+    const char A2_PASSWORD[] = "password";
+    const char A2_ACCOUNT[] = "account";
+    const char A2_MACDEF[] = "macdef";
+    for(std::vector<Scip>::const_iterator iter = tokens.begin(),
           eoi = tokens.end(); iter != eoi; ++iter) {
-      const std::string& token = *iter;
       if(state == GET_TOKEN) {
-        if(token == "machine") {
+        if(util::streq((*iter).first, (*iter).second,
+                       A2_MACHINE, vend(A2_MACHINE)-1)) {
           storeAuthenticator(authenticator);
           authenticator.reset(new Authenticator());
           state = SET_MACHINE;
-        } else if(token == "default") {
+        } else if(util::streq((*iter).first, (*iter).second,
+                              A2_DEFAULT, vend(A2_DEFAULT)-1)) {
           storeAuthenticator(authenticator);
           authenticator.reset(new DefaultAuthenticator());
         } else {
           if(!authenticator) {
             throw DL_ABORT_EX
               (fmt("Netrc:parse error. %s encounterd where 'machine'"
-                   " or 'default' expected.", token.c_str()));
+                   " or 'default' expected.",
+                   std::string((*iter).first, (*iter).second).c_str()));
           }
-          if(token == "login") {
+          if(util::streq((*iter).first, (*iter).second,
+                         A2_LOGIN, vend(A2_LOGIN)-1)) {
             state = SET_LOGIN;
-          } else if(token == "password") {
+          } else if(util::streq((*iter).first, (*iter).second,
+                                A2_PASSWORD, vend(A2_PASSWORD)-1)) {
             state = SET_PASSWORD;
-          } else if(token == "account") {
+          } else if(util::streq((*iter).first, (*iter).second,
+                                A2_ACCOUNT, vend(A2_ACCOUNT)-1)) {
             state = SET_ACCOUNT;
-          } else if(token == "macdef") {
+          } else if(util::streq((*iter).first, (*iter).second,
+                                A2_MACDEF, vend(A2_MACDEF)-1)) {
             state = SET_MACDEF;
           }
         }
       } else {
         if(state == SET_MACHINE) {
-          authenticator->setMachine(token);
+          authenticator->setMachine((*iter).first, (*iter).second);
         } else if(state == SET_LOGIN) {
-          authenticator->setLogin(token);
+          authenticator->setLogin((*iter).first, (*iter).second);
         } else if(state == SET_PASSWORD) {
-          authenticator->setPassword(token);
+          authenticator->setPassword((*iter).first, (*iter).second);
         } else if(state == SET_ACCOUNT) {
-          authenticator->setAccount(token);
+          authenticator->setAccount((*iter).first, (*iter).second);
         } else if(state == SET_MACDEF) {
           skipMacdef(fp);
         }

+ 24 - 0
src/Netrc.h

@@ -76,6 +76,12 @@ public:
 
   void setMachine(const std::string& machine);
 
+  template<typename InputIterator>
+  void setMachine(InputIterator first, InputIterator last)
+  {
+    machine_.assign(first, last);
+  }
+
   const std::string& getLogin() const
   {
     return login_;
@@ -83,6 +89,12 @@ public:
 
   void setLogin(const std::string& login);
 
+  template<typename InputIterator>
+  void setLogin(InputIterator first, InputIterator last)
+  {
+    login_.assign(first, last);
+  }
+
   const std::string& getPassword() const
   {
     return password_;
@@ -90,12 +102,24 @@ public:
 
   void setPassword(const std::string& password);
 
+  template<typename InputIterator>
+  void setPassword(InputIterator first, InputIterator last)
+  {
+    password_.assign(first, last);
+  }
+
   const std::string& getAccount() const
   {
     return account_;
   }
 
   void setAccount(const std::string& account);
+
+  template<typename InputIterator>
+  void setAccount(InputIterator first, InputIterator last)
+  {
+    account_.assign(first, last);
+  }
 };
 
 class DefaultAuthenticator : public Authenticator {

+ 22 - 16
src/NsCookieParser.cc

@@ -45,6 +45,7 @@
 #include "Cookie.h"
 #include "cookie_helper.h"
 #include "BufferedFile.h"
+#include "array_fun.h"
 
 namespace aria2 {
 
@@ -52,26 +53,23 @@ NsCookieParser::NsCookieParser() {}
 
 NsCookieParser::~NsCookieParser() {}
 
-namespace {
-const std::string C_TRUE("TRUE");
-} // namespace
-
 namespace {
 bool parseNsCookie
 (Cookie& cookie, const std::string& nsCookieStr, time_t creationTime)
 {
-  std::vector<std::string> vs;
-  util::split(nsCookieStr, std::back_inserter(vs), "\t", true);
+  std::vector<Scip> vs;
+  util::splitIter(nsCookieStr.begin(), nsCookieStr.end(),
+                  std::back_inserter(vs), '\t', true);
   if(vs.size() < 6) {
     return false;
   }
-  std::string cookieDomain = cookie::removePrecedingDots(vs[0]);
-  if(vs[5].empty() || cookieDomain.empty() ||
-     !cookie::goodPath(vs[2].begin(), vs[2].end())) {
+  vs[0].first = util::lstripIter(vs[0].first, vs[0].second, '.');
+  if(vs[5].first == vs[5].second || vs[0].first == vs[0].second ||
+     !cookie::goodPath(vs[2].first, vs[2].second)) {
     return false;
   }
   int64_t expiryTime;
-  if(!util::parseLLIntNoThrow(expiryTime, vs[4].begin(), vs[4].end())) {
+  if(!util::parseLLIntNoThrow(expiryTime, vs[4].first, vs[4].second)) {
     return false;
   }
   if(std::numeric_limits<time_t>::max() < expiryTime) {
@@ -79,16 +77,24 @@ bool parseNsCookie
   } else if(std::numeric_limits<time_t>::min() > expiryTime) {
     expiryTime = std::numeric_limits<time_t>::min();
   }
-  cookie.setName(vs[5]);
-  cookie.setValue(vs.size() >= 7? vs[6]:A2STR::NIL);
+  cookie.setName(vs[5].first, vs[5].second);
+  if(vs.size() >= 7) {
+    cookie.setValue(vs[6].first, vs[6].second);
+  } else {
+    cookie.setValue(A2STR::NIL.begin(), A2STR::NIL.end());
+  }
   cookie.setExpiryTime(expiryTime == 0?
                        std::numeric_limits<time_t>::max():expiryTime);
   // aria2 treats expiryTime == 0 means session cookie.
   cookie.setPersistent(expiryTime != 0);
-  cookie.setDomain(cookieDomain);
-  cookie.setHostOnly(util::isNumericHost(cookieDomain) || vs[1] != C_TRUE);
-  cookie.setPath(vs[2]);
-  cookie.setSecure(vs[3] == C_TRUE);
+  cookie.setDomain(vs[0].first, vs[0].second);
+  const char C_TRUE[] = "TRUE";
+  cookie.setHostOnly(util::isNumericHost(cookie.getDomain()) ||
+                     !util::streq(vs[1].first, vs[1].second,
+                                  C_TRUE, vend(C_TRUE)-1));
+  cookie.setPath(vs[2].first, vs[2].second);
+  cookie.setSecure(util::streq(vs[3].first, vs[3].second,
+                               C_TRUE, vend(C_TRUE)-1));
   cookie.setCreationTime(creationTime);
   return true;
 }

+ 2 - 2
src/ParameterizedStringParser.cc

@@ -92,8 +92,8 @@ ParameterizedStringParser::createSelect(const std::string& src, int& offset)
     throw DL_ABORT_EX("Missing '}' in the parameterized string.");
   }
   std::vector<std::string> values;
-  util::split(src.substr(offset, rightParenIndex-offset),
-              std::back_inserter(values), ",", true);
+  util::split(src.begin()+offset, src.begin()+rightParenIndex,
+              std::back_inserter(values), ',', true);
   if(values.empty()) {
     throw DL_ABORT_EX("Empty {} is not allowed.");
   }

+ 4 - 4
src/ServerStatMan.cc

@@ -155,13 +155,13 @@ bool ServerStatMan::load(const std::string& filename)
       continue;
     }
     std::string line(p.first, p.second);
-    std::vector<std::string> items;
-    util::split(line, std::back_inserter(items), ",");
+    std::vector<Scip> items;
+    util::splitIter(line.begin(), line.end(), std::back_inserter(items), ',');
     std::map<std::string, std::string> m;
-    for(std::vector<std::string>::const_iterator i = items.begin(),
+    for(std::vector<Scip>::const_iterator i = items.begin(),
           eoi = items.end(); i != eoi; ++i) {
       std::pair<Scip, Scip> p;
-      util::divide(p, (*i).begin(), (*i).end(), '=');
+      util::divide(p, (*i).first, (*i).second, '=');
       m[std::string(p.first.first, p.first.second)] =
         std::string(p.second.first, p.second.second);
     }

+ 2 - 1
src/SessionSerializer.cc

@@ -85,8 +85,9 @@ bool writeOption(BufferedFile& fp, const SharedHandle<Option>& op)
     const SharedHandle<OptionHandler>& h = oparser->find(pref);
     if(h && h->getInitialOption() && op->defined(pref)) {
       if(h->getCumulative()) {
+        const std::string& val = op->get(pref);
         std::vector<std::string> v;
-        util::split(op->get(pref), std::back_inserter(v), "\n",
+        util::split(val.begin(), val.end(), std::back_inserter(v), '\n',
                     false, false);
         for(std::vector<std::string>::const_iterator j = v.begin(),
               eoj = v.end(); j != eoj; ++j) {

+ 7 - 4
src/Sqlite3CookieParser.cc

@@ -100,14 +100,17 @@ bool parseTime(int64_t& time, InputIterator first, InputIterator last)
 namespace {
 int cookieRowMapper(void* data, int columns, char** values, char** names)
 {
-  if(columns != 7) {
+  if(columns != 7 || !values[0] || !values[1] || !values[4]) {
     return 0;
   }
   std::vector<Cookie>& cookies =
     *reinterpret_cast<std::vector<Cookie>*>(data);
-  std::string cookieDomain = cookie::removePrecedingDots(toString(values[0]));
-  std::string cookieName = toString(values[4]);
-  std::string cookiePath = toString(values[1]);
+  size_t val0len = strlen(values[0]);
+  std::string cookieDomain
+    (util::lstripIter(&values[0][0], &values[0][val0len], '.'),
+     &values[0][val0len]);
+  std::string cookieName(&values[4][0], &values[4][strlen(values[4])]);
+  std::string cookiePath(&values[1][0], &values[1][strlen(values[1])]);
   if(cookieName.empty() || cookieDomain.empty() ||
      !cookie::goodPath(cookiePath.begin(), cookiePath.end())) {
     return 0;

+ 2 - 1
src/UriListParser.cc

@@ -66,7 +66,8 @@ void UriListParser::parseNext(std::vector<std::string>& uris, Option& op)
   const SharedHandle<OptionParser>& optparser = OptionParser::getInstance();
   while(1) {
     if(!util::startsWith(line_, A2STR::SHARP_C) && !util::strip(line_).empty()){
-      util::split(line_, std::back_inserter(uris), "\t", true);
+      util::split(line_.begin(), line_.end(), std::back_inserter(uris),
+                  '\t', true);
       // Read options
       std::stringstream ss;
       while(1) {

+ 6 - 4
src/bittorrent_helper.cc

@@ -1036,10 +1036,12 @@ void adjustAnnounceUri
 {
   std::vector<std::string> excludeUris;
   std::vector<std::string> addUris;
-  util::split(option->get(PREF_BT_EXCLUDE_TRACKER),
-              std::back_inserter(excludeUris), A2STR::COMMA_C, true);
-  util::split(option->get(PREF_BT_TRACKER),
-              std::back_inserter(addUris), A2STR::COMMA_C, true);
+  const std::string& exTracker = option->get(PREF_BT_EXCLUDE_TRACKER);
+  util::split(exTracker.begin(), exTracker.end(),
+              std::back_inserter(excludeUris), ',', true);
+  const std::string& btTracker = option->get(PREF_BT_TRACKER);
+  util::split(btTracker.begin(), btTracker.end(),
+              std::back_inserter(addUris), ',', true);
   removeAnnounceUri(attrs, excludeUris);
   addAnnounceUri(attrs, addUris);
 }

+ 0 - 8
src/cookie_helper.cc

@@ -352,14 +352,6 @@ bool parse
   return true;
 }
 
-std::string removePrecedingDots(const std::string& host)
-{
-  std::string::const_iterator noDot = host.begin();
-  std::string::const_iterator end = host.end();
-  for(; noDot != end && *noDot == '.'; ++noDot);
-  return std::string(noDot, end);
-}
-
 bool goodPath
 (std::string::const_iterator first,
  std::string::const_iterator last)

+ 0 - 2
src/cookie_helper.h

@@ -59,8 +59,6 @@ bool parse
  const std::string& defaultPath,
  time_t creationTime);
 
-std::string removePrecedingDots(const std::string& host);
-
 bool goodPath
 (std::string::const_iterator first,
  std::string::const_iterator last);

+ 23 - 14
src/json.cc

@@ -620,21 +620,30 @@ decodeGetParams(const std::string& query)
     Scip method;
     Scip id;
     Scip params;
-    std::vector<std::string> getParams;
-    util::split(query.substr(1), std::back_inserter(getParams), "&");
-    for(std::vector<std::string>::const_iterator i =
+    std::vector<Scip> getParams;
+    util::splitIter(query.begin()+1, query.end(), std::back_inserter(getParams),
+                    '&');
+    const char A2_METHOD[] = "method=";
+    const char A2_ID[] = "id=";
+    const char A2_PARAMS[] = "params=";
+    const char A2_JSONCB[] = "jsoncallback=";
+    for(std::vector<Scip>::const_iterator i =
           getParams.begin(), eoi = getParams.end(); i != eoi; ++i) {
-      if(util::startsWith(*i, "method=")) {
-        method.first = (*i).begin()+7;
-        method.second = (*i).end();
-      } else if(util::startsWith(*i, "id=")) {
-        id.first = (*i).begin()+3;
-        id.second = (*i).end();
-      } else if(util::startsWith(*i, "params=")) {
-        params.first = (*i).begin()+7;
-        params.second = (*i).end();
-      } else if(util::startsWith(*i, "jsoncallback=")) {
-        callback.assign((*i).begin()+13, (*i).end());
+      if(util::startsWith((*i).first, (*i).second,
+                          A2_METHOD, vend(A2_METHOD)-1)) {
+        method.first = (*i).first+7;
+        method.second = (*i).second;
+      } else if(util::startsWith((*i).first, (*i).second,
+                                 A2_ID, vend(A2_ID)-1)) {
+        id.first = (*i).first+3;
+        id.second = (*i).second;
+      } else if(util::startsWith((*i).first, (*i).second,
+                                 A2_PARAMS, vend(A2_PARAMS)-1)) {
+        params.first = (*i).first+7;
+        params.second = (*i).second;
+      } else if(util::startsWith((*i).first, (*i).second,
+                                 A2_JSONCB, vend(A2_JSONCB)-1)) {
+        callback.assign((*i).first+13, (*i).second);
       }
     }
     std::string jsonParam =

+ 8 - 8
src/magnet.cc

@@ -46,15 +46,15 @@ SharedHandle<Dict> parse(const std::string& magnet)
     return dict;
   }
   dict.reset(new Dict());
-  std::vector<std::string> queries;
-  util::split(std::string(magnet.begin()+8, magnet.end()),
-              std::back_inserter(queries), "&");
-  for(std::vector<std::string>::const_iterator i = queries.begin(),
+  std::vector<Scip> queries;
+  util::splitIter(magnet.begin()+8, magnet.end(), std::back_inserter(queries),
+                  '&');
+  for(std::vector<Scip>::const_iterator i = queries.begin(),
         eoi = queries.end(); i != eoi; ++i) {
-    std::string::const_iterator eq = std::find((*i).begin(), (*i).end(), '=');
-    std::string name((*i).begin(), eq);
-    std::string value =
-      eq == (*i).end() ? "" : util::percentDecode(eq+1, (*i).end());
+    std::pair<Scip, Scip> p;
+    util::divide(p, (*i).first, (*i).second, '=');
+    std::string name(p.first.first, p.first.second);
+    std::string value(util::percentDecode(p.second.first, p.second.second));
     List* l = downcast<List>(dict->get(name));
     if(l) {
       l->append(String::g(value));

+ 4 - 5
src/uri.cc

@@ -307,7 +307,8 @@ std::string joinUri(const std::string& baseUri, const std::string& uri)
     }
     std::vector<std::string> parts;
     if(!util::startsWith(uri, "/")) {
-      util::split(bus.dir, std::back_inserter(parts), "/");
+      util::split(bus.dir.begin(), bus.dir.end(), std::back_inserter(parts),
+                  '/');
     }
     std::string::const_iterator qend;
     for(qend = uri.begin(); qend != uri.end(); ++qend) {
@@ -321,15 +322,13 @@ std::string joinUri(const std::string& baseUri, const std::string& uri)
         break;
       }
     }
-    std::string path(uri.begin(), end);
-    util::split(path, std::back_inserter(parts), "/");
+    util::split(uri.begin(), end, std::back_inserter(parts), '/');
     bus.dir.clear();
     bus.file.clear();
     bus.query.clear();
     std::string res = construct(bus);
     res += util::joinPath(parts.begin(), parts.end());
-    if((path.empty() || util::endsWith(path, "/")) &&
-       !util::endsWith(res, "/")) {
+    if((uri.begin() == end || *(end-1) == '/') && *(res.end()-1) != '/') {
       res += "/";
     }
     res.append(end, qend);

+ 31 - 25
src/util.cc

@@ -687,26 +687,31 @@ void parsePrioritizePieceRange
  uint64_t defaultSize)
 {
   std::vector<size_t> indexes;
-  std::vector<std::string> parts;
-  split(src, std::back_inserter(parts), ",", true);
-  for(std::vector<std::string>::const_iterator i = parts.begin(),
+  std::vector<Scip> parts;
+  const char A2_HEAD[] = "head";
+  const char A2_HEADEQ[] = "head=";
+  const char A2_TAIL[] = "tail";
+  const char A2_TAILEQ[] = "tail=";
+  splitIter(src.begin(), src.end(), std::back_inserter(parts), ',', true);
+  for(std::vector<Scip>::const_iterator i = parts.begin(),
         eoi = parts.end(); i != eoi; ++i) {
-    if((*i) == "head") {
+    if(util::streq((*i).first, (*i).second, A2_HEAD, vend(A2_HEAD)-1)) {
       computeHeadPieces(indexes, fileEntries, pieceLength, defaultSize);
-    } else if(util::startsWith(*i, "head=")) {
-      std::string sizestr = std::string((*i).begin()+(*i).find("=")+1,
-                                        (*i).end());
+    } else if(util::startsWith((*i).first, (*i).second,
+                               A2_HEADEQ, vend(A2_HEADEQ)-1)) {
+      std::string sizestr((*i).first+5, (*i).second);
       computeHeadPieces(indexes, fileEntries, pieceLength,
                         std::max((int64_t)0, getRealSize(sizestr)));
-    } else if((*i) == "tail") {
+    } else if(util::streq((*i).first, (*i).second, A2_TAIL, vend(A2_TAIL)-1)) {
       computeTailPieces(indexes, fileEntries, pieceLength, defaultSize);
-    } else if(util::startsWith(*i, "tail=")) {
-      std::string sizestr = std::string((*i).begin()+(*i).find("=")+1,
-                                        (*i).end());
+    } else if(util::startsWith((*i).first, (*i).second,
+                               A2_TAILEQ, vend(A2_TAILEQ)-1)) {
+      std::string sizestr((*i).first+5, (*i).second);
       computeTailPieces(indexes, fileEntries, pieceLength,
                         std::max((int64_t)0, getRealSize(sizestr)));
     } else {
-      throw DL_ABORT_EX(fmt("Unrecognized token %s", (*i).c_str()));
+      throw DL_ABORT_EX(fmt("Unrecognized token %s",
+                            std::string((*i).first, (*i).second).c_str()));
     }
   }
   std::sort(indexes.begin(), indexes.end());
@@ -802,16 +807,15 @@ std::string getContentDispositionFilename(const std::string& header)
       if(markeritr == param.end() || *markeritr != '=') {
         continue;
       }
-      std::string value(markeritr+1, param.end());
-      std::vector<std::string> extValues;
-      split(value, std::back_inserter(extValues), "'", true, true);
+      std::vector<Scip> extValues;
+      splitIter(markeritr+1, param.end(), std::back_inserter(extValues),
+                '\'', true, true);
       if(extValues.size() != 3) {
         continue;
       }
       bool bad = false;
-      const std::string& charset = extValues[0];
-      for(std::string::const_iterator j = charset.begin(), eoi = charset.end();
-          j != eoi; ++j) {
+      for(std::string::const_iterator j = extValues[0].first,
+            eoj = extValues[0].second; j != eoj; ++j) {
         // Since we first split parameter by ', we can safely assume
         // that ' is not included in charset.
         if(!inRFC2978MIMECharset(*j)) {
@@ -823,12 +827,11 @@ std::string getContentDispositionFilename(const std::string& header)
         continue;
       }
       bad = false;
-      value = extValues[2];
-      for(std::string::const_iterator j = value.begin(), eoi = value.end();
-          j != eoi; ++j){
+      for(std::string::const_iterator j = extValues[2].first,
+            eoj = extValues[2].second; j != eoj; ++j){
         if(*j == '%') {
-          if(j+1 != value.end() && isHexDigit(*(j+1)) &&
-             j+2 != value.end() && isHexDigit(*(j+2))) {
+          if(j+1 != eoj && isHexDigit(*(j+1)) &&
+             j+2 != eoj && isHexDigit(*(j+2))) {
             j += 2;
           } else {
             bad = true;
@@ -844,8 +847,11 @@ std::string getContentDispositionFilename(const std::string& header)
       if(bad) {
         continue;
       }
-      value = percentDecode(value.begin(), value.end());
-      if(toLower(extValues[0]) == "iso-8859-1") {
+      std::string value =
+        percentDecode(extValues[2].first, extValues[2].second);
+      const char A2_ISO88591[] = "iso-8859-1";
+      if(util::strieq(extValues[0].first, extValues[0].second,
+                      A2_ISO88591, vend(A2_ISO88591)-1)) {
         value = iso8859ToUtf8(value);
       }
       if(!detectDirTraversal(value) &&

+ 170 - 18
src/util.h

@@ -177,6 +177,31 @@ std::pair<InputIterator, InputIterator> stripIter
   return std::make_pair(first, left+1);
 }
 
+template<typename InputIterator>
+InputIterator lstripIter
+(InputIterator first, InputIterator last, char ch)
+{
+  for(; first != last && *first == ch; ++first);
+  return first;
+}
+
+template<typename InputIterator, typename InputIterator2>
+InputIterator lstripIter
+(InputIterator first, InputIterator last,
+ InputIterator2 cfirst, InputIterator2 clast)
+{
+  for(; first != last && std::find(cfirst, clast, *first) != clast; ++first);
+  return first;
+}
+
+template<typename InputIterator>
+InputIterator lstripIter
+(InputIterator first, InputIterator last)
+{
+  return lstripIter(first, last,
+                    DEFAULT_STRIP_CHARSET.begin(), DEFAULT_STRIP_CHARSET.end());
+}
+
 std::string strip
 (const std::string& str, const std::string& chars = DEFAULT_STRIP_CHARSET);
 
@@ -526,22 +551,86 @@ parseIndexPath(const std::string& line);
 std::vector<std::pair<size_t, std::string> > createIndexPaths(std::istream& i);
 
 /**
- * Take a string src which is a delimited list and add its elements
- * into result. result is stored in out.
+ * Take a string [first, last) which is a delimited list and add its
+ * elements into result as iterator pair. result is stored in out.
  */
-template<typename OutputIterator>
-OutputIterator split(const std::string& src, OutputIterator out,
-                     const std::string& delims, bool doStrip = false,
-                     bool allowEmpty = false)
+template<typename InputIterator, typename OutputIterator>
+OutputIterator splitIter
+(InputIterator first,
+ InputIterator last,
+ OutputIterator out,
+ char delim,
+ bool doStrip = false,
+ bool allowEmpty = false)
 {
-  std::string::const_iterator first = src.begin();
-  std::string::const_iterator last = src.end();
-  for(std::string::const_iterator i = first; i != last;) {
-    std::string::const_iterator j = i;
-    for(; j != last &&
-          std::find(delims.begin(), delims.end(), *j) == delims.end(); ++j);
-    std::pair<std::string::const_iterator,
-              std::string::const_iterator> p(i, j);
+  for(InputIterator i = first; i != last;) {
+    InputIterator j = std::find(i, last, delim);
+    std::pair<InputIterator, InputIterator> p(i, j);
+    if(doStrip) {
+      p = stripIter(i, j);
+    }
+    if(allowEmpty || p.first != p.second) {
+      *out++ = p;
+    }
+    i = j;
+    if(j != last) {
+      ++i;
+    }
+  }
+  if(allowEmpty &&
+     (first == last || *(last-1) == delim)) {
+    *out++ = std::make_pair(last, last);
+  }
+  return out;
+}
+
+template<typename InputIterator,
+         typename InputIterator2,
+         typename OutputIterator>
+OutputIterator splitIterM
+(InputIterator first,
+ InputIterator last,
+ OutputIterator out,
+ InputIterator2 dfirst,
+ InputIterator2 dlast,
+ bool doStrip = false,
+ bool allowEmpty = false)
+{
+  for(InputIterator i = first; i != last;) {
+    InputIterator j = i;
+    for(; j != last && std::find(dfirst, dlast, *j) == dlast; ++j);
+    std::pair<InputIterator, InputIterator> p(i, j);
+    if(doStrip) {
+      p = stripIter(i, j);
+    }
+    if(allowEmpty || p.first != p.second) {
+      *out++ = p;
+    }
+    i = j;
+    if(j != last) {
+      ++i;
+    }
+  }
+  if(allowEmpty &&
+     (first == last ||
+      std::find(dfirst, dlast, *(last-1)) != dlast)) {
+    *out++ = std::make_pair(last, last);
+  }
+  return out;
+}
+
+template<typename InputIterator, typename OutputIterator>
+OutputIterator split
+(InputIterator first,
+ InputIterator last,
+ OutputIterator out,
+ char delim,
+ bool doStrip = false,
+ bool allowEmpty = false)
+{
+  for(InputIterator i = first; i != last;) {
+    InputIterator j = std::find(i, last, delim);
+    std::pair<InputIterator, InputIterator> p(i, j);
     if(doStrip) {
       p = stripIter(i, j);
     }
@@ -554,14 +643,77 @@ OutputIterator split(const std::string& src, OutputIterator out,
     }
   }
   if(allowEmpty &&
-     (src.empty() ||
-      std::find(delims.begin(), delims.end(),
-                src[src.size()-1]) != delims.end())) {
-    *out++ = A2STR::NIL;
+     (first == last || *(last-1) == delim)) {
+    *out++ = std::string(last, last);
   }
   return out;
 }
 
+template<typename InputIterator1, typename InputIterator2>
+bool streq
+(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2)
+{
+  if(last1-first1 != last2-first2) {
+    return false;
+  }
+  return std::equal(first1, last1, first2);
+}
+
+template<typename InputIterator1, typename InputIterator2>
+bool strieq
+(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2)
+{
+  if(last1-first1 != last2-first2) {
+    return false;
+  }
+  for(; first1 != last1; ++first1, ++first2) {
+    char c1 = *first1;
+    char c2 = *first2;
+    if('A' <= c1 && c1 <= 'Z') {
+      c1 = c1-'A'+'a';
+    }
+    if('A' <= c2 && c2 <= 'Z') {
+      c2 = c2-'A'+'a';
+    }
+    if(c1 != c2) {
+      return false;
+    }
+  }
+  return true;
+}
+
+template<typename InputIterator1, typename InputIterator2>
+bool startsWith
+(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2)
+{
+  if(last1-first1 < last2-first2) {
+    return false;
+  }
+  return std::equal(first2, last2, first1);
+}
+
+template<typename InputIterator1, typename InputIterator2>
+bool endsWith
+(InputIterator1 first1,
+ InputIterator1 last1,
+ InputIterator2 first2,
+ InputIterator2 last2)
+{
+  if(last1-first1 < last2-first2) {
+    return false;
+  }
+  return std::equal(first2, last2, last1-(last2-first2));
+}
+
 void generateRandomData(unsigned char* data, size_t length);
 
 // Saves data to file whose name is filename. If overwrite is true,

+ 383 - 14
test/UtilTest.cc

@@ -24,8 +24,14 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST_SUITE(UtilTest);
   CPPUNIT_TEST(testStrip);
   CPPUNIT_TEST(testStripIter);
+  CPPUNIT_TEST(testLstripIter);
+  CPPUNIT_TEST(testLstripIter_char);
   CPPUNIT_TEST(testDivide);
   CPPUNIT_TEST(testSplit);
+  CPPUNIT_TEST(testSplitIter);
+  CPPUNIT_TEST(testSplitIterM);
+  CPPUNIT_TEST(testStreq);
+  CPPUNIT_TEST(testStrieq);
   CPPUNIT_TEST(testEndsWith);
   CPPUNIT_TEST(testReplace);
   CPPUNIT_TEST(testStartsWith);
@@ -85,8 +91,14 @@ public:
 
   void testStrip();
   void testStripIter();
+  void testLstripIter();
+  void testLstripIter_char();
   void testDivide();
   void testSplit();
+  void testSplitIter();
+  void testSplitIterM();
+  void testStreq();
+  void testStrieq();
   void testEndsWith();
   void testReplace();
   void testStartsWith();
@@ -211,6 +223,46 @@ void UtilTest::testStripIter()
   CPPUNIT_ASSERT_EQUAL(str4, std::string(p.first, p.second));
 }
 
+void UtilTest::testLstripIter()
+{
+  std::string::iterator r;
+  std::string s = "foo";
+  r = util::lstripIter(s.begin(), s.end());
+  CPPUNIT_ASSERT_EQUAL(std::string("foo"), std::string(r, s.end()));
+  
+  s = "  foo bar  ";
+  r = util::lstripIter(s.begin(), s.end());
+  CPPUNIT_ASSERT_EQUAL(std::string("foo bar  "), std::string(r, s.end()));
+
+  s = "f";
+  r = util::lstripIter(s.begin(), s.end());
+  CPPUNIT_ASSERT_EQUAL(std::string("f"), std::string(r, s.end()));
+
+  s = "foo  ";
+  r = util::lstripIter(s.begin(), s.end());
+  CPPUNIT_ASSERT_EQUAL(std::string("foo  "), std::string(r, s.end()));
+}
+
+void UtilTest::testLstripIter_char()
+{
+  std::string::iterator r;
+  std::string s = "foo";
+  r = util::lstripIter(s.begin(), s.end(), '$');
+  CPPUNIT_ASSERT_EQUAL(std::string("foo"), std::string(r, s.end()));
+  
+  s = "$$foo$bar$$";
+  r = util::lstripIter(s.begin(), s.end(), '$');
+  CPPUNIT_ASSERT_EQUAL(std::string("foo$bar$$"), std::string(r, s.end()));
+
+  s = "f";
+  r = util::lstripIter(s.begin(), s.end(), '$');
+  CPPUNIT_ASSERT_EQUAL(std::string("f"), std::string(r, s.end()));
+
+  s = "foo$$";
+  r = util::lstripIter(s.begin(), s.end(), '$');
+  CPPUNIT_ASSERT_EQUAL(std::string("foo$$"), std::string(r, s.end()));
+}
+
 void UtilTest::testDivide() {
   std::pair<Scip, Scip> p1;
   std::string s = "name=value";
@@ -247,7 +299,8 @@ void UtilTest::testDivide() {
 
 void UtilTest::testSplit() {
   std::vector<std::string> v;
-  util::split("k1; k2;; k3", std::back_inserter(v), ";", true);
+  std::string s = "k1; k2;; k3";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', true);
   CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
   std::vector<std::string>::iterator itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("k1"), *itr++);
@@ -256,8 +309,8 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split("k1; k2; k3",
-              std::back_inserter(v), ";");
+  s = "k1; k2; k3";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';');
   CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("k1"), *itr++);
@@ -266,14 +319,16 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split("k=v", std::back_inserter(v), ";", false, true);
+  s = "k=v";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
   CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("k=v"), *itr++);
 
   v.clear();
 
-  util::split(";;k1;;k2;", std::back_inserter(v), ";", false, true);
+  s = ";;k1;;k2;";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
   CPPUNIT_ASSERT_EQUAL((size_t)6, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string(""), *itr++);
@@ -285,7 +340,8 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split(";;k1;;k2;", std::back_inserter(v), ";");
+  s = ";;k1;;k2;";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';');
   CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("k1"), *itr++);
@@ -293,7 +349,8 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split("k; ", std::back_inserter(v), ";");
+  s = "k; ";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';');
   CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string("k"), *itr++);
@@ -301,29 +358,34 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split(" ", std::back_inserter(v), ";", true, true);
+  s = " ";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', true, true);
   CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
   CPPUNIT_ASSERT_EQUAL(std::string(""), v[0]);
 
   v.clear();
 
-  util::split(" ", std::back_inserter(v), ";", true);
+  s = " ";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', true);
   CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
 
   v.clear();
 
-  util::split(" ", std::back_inserter(v), ";");
+  s = " ";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';');
   CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
   CPPUNIT_ASSERT_EQUAL(std::string(" "), v[0]);
 
   v.clear();
 
-  util::split(";", std::back_inserter(v), ";");
+  s = ";";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';');
   CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
 
   v.clear();
 
-  util::split(";", std::back_inserter(v), ";", false, true);
+  s = ";";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
   CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
   itr = v.begin();
   CPPUNIT_ASSERT_EQUAL(std::string(""), *itr++);
@@ -331,43 +393,337 @@ void UtilTest::testSplit() {
 
   v.clear();
 
-  util::split("", std::back_inserter(v), ";", false, true);
+  s = "";
+  util::split(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
   CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
   CPPUNIT_ASSERT_EQUAL(std::string(""), v[0]);
 }
 
+void UtilTest::testSplitIter() {
+  std::vector<Scip> v;
+  std::string s = "k1; k2;; k3";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', true);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k3"), std::string(v[2].first, v[2].second));
+
+  v.clear();
+
+  s = "k1; k2; k3";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';');
+  CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" k2"),
+                       std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" k3"),
+                       std::string(v[2].first, v[2].second));
+
+  v.clear();
+
+  s = "k=v";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k=v"),
+                       std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = ";;k1;;k2;";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)6, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[2].first, v[2].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[3].first, v[3].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[4].first, v[4].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[5].first, v[5].second));
+
+  v.clear();
+
+  s = ";;k1;;k2;";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';');
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = "k; ";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';');
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" "), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = " ";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', true, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = " ";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', true);
+  CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
+
+  v.clear();
+
+  s = " ";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';');
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(" "), std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = ";";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';');
+  CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
+
+  v.clear();
+
+  s = ";";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = "";
+  util::splitIter(s.begin(), s.end(), std::back_inserter(v), ';', false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+}
+
+void UtilTest::testSplitIterM() {
+  std::string d = ";";
+  std::string md = "; ";
+  std::vector<Scip> v;
+  std::string s = "k1; k2;; k3";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), true);
+  CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k3"), std::string(v[2].first, v[2].second));
+
+  v.clear();
+
+  s = "k1; k2; k3";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" k2"),
+                       std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" k3"),
+                       std::string(v[2].first, v[2].second));
+
+  v.clear();
+
+  s = "k1; k2; k3";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   md.begin(), md.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)3, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k3"), std::string(v[2].first, v[2].second));
+
+  v.clear();
+
+  s = "k1; k2; k3;";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   md.begin(), md.end(), false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)6, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[2].first, v[2].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[3].first, v[3].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k3"), std::string(v[4].first, v[4].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[5].first, v[5].second));
+
+  v.clear();
+
+  s = "k=v";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k=v"),
+                       std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = ";;k1;;k2;";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)6, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[1].first, v[1].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[2].first, v[2].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[3].first, v[3].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[4].first, v[4].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[5].first, v[5].second));
+
+  v.clear();
+
+  s = ";;k1;;k2;";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k1"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string("k2"), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = "k; ";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string("k"), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(" "), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = " ";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), true, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = " ";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), true);
+  CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
+
+  v.clear();
+
+  s = " ";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(" "), std::string(v[0].first, v[0].second));
+
+  v.clear();
+
+  s = ";";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end());
+  CPPUNIT_ASSERT_EQUAL((size_t)0, v.size());
+
+  v.clear();
+
+  s = ";";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)2, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[1].first, v[1].second));
+
+  v.clear();
+
+  s = "";
+  util::splitIterM(s.begin(), s.end(), std::back_inserter(v),
+                   d.begin(), d.end(), false, true);
+  CPPUNIT_ASSERT_EQUAL((size_t)1, v.size());
+  CPPUNIT_ASSERT_EQUAL(std::string(""), std::string(v[0].first, v[0].second));
+}
+
 void UtilTest::testEndsWith() {
   std::string target = "abcdefg";
   std::string part = "fg";
   CPPUNIT_ASSERT(util::endsWith(target, part));
+  CPPUNIT_ASSERT(util::endsWith(target.begin(), target.end(),
+                                part.begin(), part.end()));
 
   target = "abdefg";
   part = "g";
   CPPUNIT_ASSERT(util::endsWith(target, part));
+  CPPUNIT_ASSERT(util::endsWith(target.begin(), target.end(),
+                                part.begin(), part.end()));
 
   target = "abdefg";
   part = "eg";
   CPPUNIT_ASSERT(!util::endsWith(target, part));
+  CPPUNIT_ASSERT(!util::endsWith(target.begin(), target.end(),
+                                 part.begin(), part.end()));
 
   target = "g";
   part = "eg";
   CPPUNIT_ASSERT(!util::endsWith(target, part));
+  CPPUNIT_ASSERT(!util::endsWith(target.begin(), target.end(),
+                                 part.begin(), part.end()));
 
   target = "g";
   part = "g";
   CPPUNIT_ASSERT(util::endsWith(target, part));
+  CPPUNIT_ASSERT(util::endsWith(target.begin(), target.end(),
+                                part.begin(), part.end()));
 
   target = "g";
   part = "";
   CPPUNIT_ASSERT(util::endsWith(target, part));
+  CPPUNIT_ASSERT(util::endsWith(target.begin(), target.end(),
+                                part.begin(), part.end()));
 
   target = "";
   part = "";
   CPPUNIT_ASSERT(util::endsWith(target, part));
+  CPPUNIT_ASSERT(util::endsWith(target.begin(), target.end(),
+                                part.begin(), part.end()));
 
   target = "";
   part = "g";
   CPPUNIT_ASSERT(!util::endsWith(target, part));
+  CPPUNIT_ASSERT(!util::endsWith(target.begin(), target.end(),
+                                 part.begin(), part.end()));
+}
+
+void UtilTest::testStreq()
+{
+  std::string s1, s2;
+  s1 = "foo";
+  s2 = "foo";
+  CPPUNIT_ASSERT(util::streq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "fooo";
+  CPPUNIT_ASSERT(!util::streq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "fo";
+  CPPUNIT_ASSERT(!util::streq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "";
+  CPPUNIT_ASSERT(!util::streq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s1 = "";
+  CPPUNIT_ASSERT(util::streq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+}
+
+void UtilTest::testStrieq()
+{
+  std::string s1, s2;
+  s1 = "foo";
+  s2 = "foo";
+  CPPUNIT_ASSERT(util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s1 = "FoO";
+  s2 = "fOo";
+  CPPUNIT_ASSERT(util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "fooo";
+  CPPUNIT_ASSERT(!util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "fo";
+  CPPUNIT_ASSERT(!util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s2 = "";
+  CPPUNIT_ASSERT(!util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
+
+  s1 = "";
+  CPPUNIT_ASSERT(util::strieq(s1.begin(), s1.end(), s2.begin(), s2.end()));
 }
 
 void UtilTest::testReplace() {
@@ -385,31 +741,44 @@ void UtilTest::testStartsWith() {
   target = "abcdefg";
   part = "abc";
   CPPUNIT_ASSERT(util::startsWith(target, part));
+  CPPUNIT_ASSERT(util::startsWith(target.begin(), target.end(),
+                                  part.begin(), part.end()));
 
   target = "abcdefg";
   part = "abx";
   CPPUNIT_ASSERT(!util::startsWith(target, part));
+  CPPUNIT_ASSERT(!util::startsWith(target.begin(), target.end(),
+                                   part.begin(), part.end()));
 
   target = "abcdefg";
   part = "bcd";
   CPPUNIT_ASSERT(!util::startsWith(target, part));
+  CPPUNIT_ASSERT(!util::startsWith(target.begin(), target.end(),
+                                   part.begin(), part.end()));
 
   target = "";
   part = "a";
   CPPUNIT_ASSERT(!util::startsWith(target, part));
+  CPPUNIT_ASSERT(!util::startsWith(target.begin(), target.end(),
+                                   part.begin(), part.end()));
 
   target = "";
   part = "";
   CPPUNIT_ASSERT(util::startsWith(target, part));
+  CPPUNIT_ASSERT(util::startsWith(target.begin(), target.end(),
+                                  part.begin(), part.end()));
   
   target = "a";
   part = "";
   CPPUNIT_ASSERT(util::startsWith(target, part));
+  CPPUNIT_ASSERT(util::startsWith(target.begin(), target.end(),
+                                  part.begin(), part.end()));
 
   target = "a";
   part = "a";
   CPPUNIT_ASSERT(util::startsWith(target, part));
-
+  CPPUNIT_ASSERT(util::startsWith(target.begin(), target.end(),
+                                  part.begin(), part.end()));
 }
 
 void UtilTest::testGetContentDispositionFilename() {