blob: b320e87b1458527d138392b7c3204c081a033529 [file] [log] [blame]
// Copyright (C) 2006-2010 David Sugar, Tycho Softworks.
//
// This file is part of GNU uCommon C++.
//
// GNU uCommon C++ is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU uCommon C++ 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with GNU uCommon C++. If not, see <http://www.gnu.org/licenses/>.
#include <ucommon-config.h>
#include <ucommon/export.h>
#include <ucommon/string.h>
#include <ucommon/memory.h>
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <limits.h>
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif
using namespace UCOMMON_NAMESPACE;
String::regex::regex(const char *pattern, size_t slots)
{
#ifdef HAVE_REGEX_H
regex_t *r = (regex_t *)malloc(sizeof(regex_t));
if(regcomp(r, pattern, 0)) {
regfree(r);
free(r);
r = NULL;
}
object = r;
count = slots;
results = (regmatch_t *)malloc(sizeof(regmatch_t) * slots);
#else
object = results = NULL;
count = 0;
#endif
}
String::regex::regex(size_t slots)
{
#ifdef HAVE_REGEX_H
count = slots;
results = (regmatch_t *)malloc(sizeof(regmatch_t) * slots);
object = NULL;
#else
object = results = NULL;
count = 0;
#endif
}
String::regex& String::regex::operator=(const char *pattern)
{
#ifdef HAVE_REGEX_H
if(object) {
regfree((regex_t *)object);
free(object);
}
regex_t *r = (regex_t *)malloc(sizeof(regex_t));
if(regcomp(r, pattern, 0)) {
regfree(r);
free(r);
r = NULL;
}
object = r;
#endif
return *this;
}
bool String::regex::operator*=(const char *text)
{
return match(text);
}
String::regex::~regex()
{
#ifdef HAVE_REGEX_H
if(object) {
regfree((regex_t *)object);
free(object);
}
if(results)
free(results);
object = results = NULL;
#endif
}
size_t String::regex::offset(unsigned member)
{
#ifdef HAVE_REGEX_H
if(!results)
return (size_t)-1;
regmatch_t *r = (regmatch_t *)results;
if(member >= count)
return (size_t)-1;
return (size_t)r[member].rm_so;
#else
return (size_t)-1;
#endif
}
size_t String::regex::size(unsigned member)
{
#ifdef HAVE_REGEX_H
if(!results)
return 0;
regmatch_t *r = (regmatch_t *)results;
if(member >= count)
return (size_t)-1;
if(r[member].rm_so == -1)
return 0;
return (size_t)(r[member].rm_eo - r[member].rm_so);
#else
return (size_t)0;
#endif
}
bool String::regex::match(const char *text, unsigned mode)
{
#ifdef HAVE_REGEX_H
int flags = 0;
if((mode & 0x01) == INSENSITIVE)
flags |= REG_ICASE;
if(!text || !object || !results)
return false;
if(regexec((regex_t *)object, text, count, (regmatch_t *)results, flags))
return false;
return true;
#else
return false;
#endif
}
const char *String::search(regex& expr, unsigned member, unsigned flags) const
{
if(!str)
return NULL;
#ifdef HAVE_REGEX_H
if(expr.match(str->text, flags))
return NULL;
if(member >= expr.members())
return NULL;
if(expr.size(member) == 0)
return NULL;
return str->text + expr.offset(member);
#else
return NULL;
#endif
}
unsigned String::replace(regex& expr, const char *cp, unsigned flags)
{
#ifdef HAVE_REGEX_H
size_t cpl = 0;
if(cp)
cpl = strlen(cp);
if(!str || str->len == 0)
return 0;
if(expr.match(str->text, flags))
return 0;
ssize_t adjust = 0;
unsigned member = 0;
while(member < expr.members()) {
ssize_t tcl = expr.size(member);
ssize_t offset = (expr.offset(member) + adjust);
if(!tcl)
break;
++member;
cut(offset, tcl);
if(cpl) {
paste(offset, cp);
adjust += (cpl - tcl);
}
}
return member;
#else
return 0;
#endif
}
bool String::operator*=(regex& expr)
{
if(search(expr))
return true;
return false;
}
unsigned StringPager::split(stringex_t& expr, const char *string, unsigned flags)
{
strdup_t tmp = String::dup(string);
int prior = 0, match = 0;
size_t tcl = strlen(string);
unsigned count = 0, member = 0;
if(!expr.match(string, flags))
return 0;
while(member < expr.members()) {
if(!expr.size(member))
break;
match = expr.offset(member++);
if(match > prior) {
tmp[match] = 0;
add(tmp + (size_t)prior);
++count;
}
prior = match + tcl;
}
if(tmp[prior]) {
add(tmp + (size_t)prior);
++count;
}
return count;
}