/*
* This file is part of SWIG.
*
* SWIG is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SWIG 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with SWIG. If not, see .
*/
#include "doh.h"
#include
#include
#include
namespace doh {
/* class String */
/* Constructors */
String::String()
: sp(0)
{}
String::String(const String& str)
: Filelike(str), std::string(str), sp(str.sp)
{}
String::String(const std::string& str)
: Filelike(), std::string(str), sp(0)
{}
String::String(const char * s)
: std::string(s), sp(0) {
}
String::String(const char *s, size_t n)
: std::string(s, n), sp(0) {
}
/* inherit from DOH */
DOH* String::clone() const {
return new String(*this);
}
void String::clear() {
sp = 0;
std::string::clear();
DOH::clear();
return;
}
int String::size() const {
return std::string::size();
}
/* inherit from Filelike */
int String::write(const char *buffer, size_t length) {
replace(sp, length, buffer);
sp += length;
return length;
}
int String::read(char *buffer, size_t length) {
size_t readlen;
readlen = size() - sp;
if (readlen < 0)
return 0;
if (readlen > length)
readlen = length;
memmove(buffer, data(), readlen);
sp += readlen;
return readlen;
}
/* count the occurrence of '\n' in a closed range */
static int countline(const char *str, size_t l, size_t r) {
register int count = 0;
register const char *i = str + l;
register const char *rr = str + r;
while (i <= rr) {
/* XXX In the original DOH there is '++i',
* (accutally ++sp and --sp)
* but to conform with getc(), it should
* be i++. */
if (*(i++) == '\n')
++count;
}
return count;
}
int String::seek(off_t offset, int whence) {
int pos, nsp, inc;
int len = size();
if (whence == SEEK_SET)
pos = 0;
else if (whence == SEEK_CUR)
pos = sp;
else if (whence == SEEK_END) {
pos = len;
offset = -offset;
} else
pos = sp;
nsp = pos + offset;
if (nsp < 0)
nsp = 0;
if ( len > 0 && nsp > len)
nsp = len;
/* Set line number */
if (sp < nsp)
_line += countline(c_str(), sp, nsp-1);
else
_line -= countline(c_str(), nsp+1, sp);
sp = nsp;
assert( sp >= 0 );
return 0;
}
off_t String::tell() {
return sp;
}
char String::getc() {
char c;
if (sp >= size())
c = EOF;
else
c = c_str()[sp++];
if (c == '\n')
_line++;
return c;
}
char String::putc(char ch) {
register int len = size();
if (sp < len) {
at(sp++) = ch;
} else {
/* append to tail of the string */
push_back(ch);
sp++;
}
return ch;
}
char String::ungetc(char ch) {
if (ch == EOF)
return ch;
if (sp <= 0)
return EOF;
sp--;
if (ch == '\n')
_line--;
return ch;
}
/* Override std::string methods */
String& String::insert(size_t pos, const std::string &str) {
size_t len = str.size();
std::string::insert(pos, str);
if (sp >= pos) {
_line += countline(str.c_str(), 0, len-1);
sp += len;
}
return *this;
}
String& String::erase(size_t pos, size_t n) {
int eindex = pos + n;
int end;
/* Adjust file pointer sp and line count */
if (sp > pos) {
if (sp > eindex) {
end = eindex;
sp -= n;
} else {
end = sp;
sp = pos;
}
_line -= countline(c_str(), pos, end-1);
}
std::string::erase(pos, n);
return *this;
}
/* DOH String methods */
String *NewStringEmpty() {
return new String();
}
String *NewString(String_or_char_ptr c) {
return new String(c);
}
String *NewStringWithSize(const String_or_char_ptr c, int len) {
const char *p = c;
return new String(c, len);
}
/*XXX const char* fmt is enough */
String *NewStringf(const String_or_char_ptr fmt, VA_DEF) {
//va_list ap;
String *r = new String();
const char * fmtstr = fmt;
//va_start(ap, fmt);
Printf(r, fmtstr, VA_CALL);
//va_end(ap);
return r;
}
int Cmp(String_or_char_ptr obj1, String_or_char_ptr obj2) {
const String *str1 = obj1; // implicit cast
const String *str2 = obj2;
return str1->compare(*str2);
}
const char *Char(const String_or_char_ptr s) {
return s;
}
int Equal(const String_or_char_ptr obj1, const String_or_char_ptr obj2) {
return Cmp(obj1, obj2)==0;
}
int Strcmp(const String_or_char_ptr s1, const String_or_char_ptr s2) {
const char *c1 = Char(s1);
const char *c2 = Char(s2);
if (c1 && c2) {
return strcmp(c1, c2);
} else {
return c1 < c2;
}
}
int Strncmp(const String_or_char_ptr s1, const String_or_char_ptr s2, int n) {
return strncmp(Char(s1), Char(s2), n);
}
const char *Strstr(const String_or_char_ptr s1, const String_or_char_ptr s2) {
const char *p1 = Char(s1);
const char *p2 = Char(s2);
return p1 == 0 || p2 == 0 || *p2 == '\0' ? p1 : strstr(p1, p2);
}
const char *Strchr(const String_or_char_ptr s1, int ch) {
return strchr(Char(s1), ch);
}
void Chop(DOH *src) {
String &so = ref_cast(src);
int len = so.size();
int i = len;
while (i>0 && isspace(so[i-1])) {
i--;
}
so.erase(i, len-i);
}
int Replace(DOH * src, const String_or_char_ptr token,
const String_or_char_ptr rep, int flags) {
String *so = doh_cast(src);
so->doh_replace(token, rep, flags);
}
/* The powerful DOH string replace function */
static int replace_simple(char* &str, int &str_len, off_t &str_sp,
const char *token, const char *rep, int flags, int count,
char *(*match) (char *, char *, const char *, int));
static char *match_identifier(char *base, char *s, const char *token, int tokenlen);
static char *match_identifier_begin(char *base, char *s, const char *token, int tokenlen);
static char *match_identifier_end(char *base, char *s, const char *token, int tokenlen);
static char *match_simple(char *base, char *s, const char *token, int tokenlen);
int String::doh_replace(const char *token, const char *rep, int flags) {
int len = size();
int count = -1;
int ret;
char *str = new char[len+1];
strcpy(str, c_str());
if (flags & DOH_REPLACE_FIRST)
count = 1;
if (flags & DOH_REPLACE_ID_END) {
ret = replace_simple(str, len, sp, token, rep, flags, count,
match_identifier_end);
} else if (flags & DOH_REPLACE_ID_BEGIN) {
ret = replace_simple(str, len, sp, token, rep, flags, count,
match_identifier_begin);
} else if (flags & DOH_REPLACE_ID) {
ret = replace_simple(str, len, sp, token, rep, flags, count,
match_identifier);
} else {
ret = replace_simple(str, len, sp, token, rep, flags, count,
match_simple);
}
assert(strlen(str)==len);
assign(str);
delete[] str;
/* sp already set since we passed it as reference */
return ret;
}
/* below code is adapted from old DOH */
/* -----------------------------------------------------------------------------
* replace_simple(String *str, char *token, char *rep, int flags, int count)
*
* Replaces count non-overlapping occurrences of token with rep in a string.
* ----------------------------------------------------------------------------- */
static char *end_quote(char *s) {
char *qs;
char qc;
char *q;
char *nl;
qc = *s;
qs = s;
while (1) {
q = strpbrk(s + 1, "\"\'");
nl = strchr(s + 1, '\n');
if (nl && (nl < q)) {
/* A new line appears before the end of the string */
if (*(nl - 1) == '\\') {
s = nl + 1;
continue;
}
/* String was terminated by a newline. Wing it */
return qs;
}
if (!q && nl) {
return qs;
}
if (!q)
return 0;
if ((*q == qc) && (*(q - 1) != '\\'))
return q;
s = q;
}
}
static char *match_simple(char *base, char *s, const char *token, int tokenlen) {
(void) base;
(void) tokenlen;
return strstr(s, token);
}
static char *match_identifier(char *base, char *s, const char *token, int tokenlen) {
while (s) {
s = strstr(s, token);
if (!s)
return 0;
if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
s += tokenlen;
continue;
}
if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
s += tokenlen;
continue;
}
return s;
}
return 0;
}
static char *match_identifier_begin(char *base, char *s, const char *token, int tokenlen) {
while (s) {
s = strstr(s, token);
if (!s)
return 0;
if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
s += tokenlen;
continue;
}
return s;
}
return 0;
}
static char *match_identifier_end(char *base, char *s, const char *token, int tokenlen) {
(void) base;
while (s) {
s = strstr(s, token);
if (!s)
return 0;
if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
s += tokenlen;
continue;
}
return s;
}
return 0;
}
static int replace_simple(char* &str, int &str_len, off_t &str_sp,
const char *token, const char *rep, int flags, int count,
char *(*match) (char *, char *, const char *, int)) {
int tokenlen; /* Length of the token */
int replen; /* Length of the replacement */
int delta, expand = 0;
int ic;
int rcount = 0;
int noquote = 0;
char *c, *s, *t, *first;
char *q, *q2;
register char *base;
int i;
/* Figure out if anything gets replaced */
if (!strlen(token))
return 0;
//base = str->str;
base = str;
tokenlen = strlen(token);
s = (*match) (base, base, token, tokenlen);
if (!s)
return 0; /* No matches. Who cares */
if (flags & DOH_REPLACE_NOQUOTE)
noquote = 1;
/* If we are not replacing inside quotes, we need to do a little extra work */
if (noquote) {
q = strpbrk(base, "\"\'");
if (!q) {
noquote = 0; /* Well, no quotes to worry about. Oh well */
} else {
while (q && (q < s)) {
/* First match was found inside a quote. Try to find another match */
q2 = end_quote(q);
if (!q2) {
return 0;
}
if (q2 > s) {
/* Find next match */
s = (*match) (base, q2 + 1, token, tokenlen);
}
if (!s)
return 0; /* Oh well, no matches */
q = strpbrk(q2 + 1, "\"\'");
if (!q)
noquote = 0; /* No more quotes */
}
}
}
first = s;
replen = strlen(rep);
delta = (replen - tokenlen);
if (delta <= 0) {
/* String is either shrinking or staying the same size */
/* In this case, we do the replacement in place without memory reallocation */
ic = count;
t = s; /* Target of memory copies */
while (ic && s) {
if (replen) {
memcpy(t, rep, replen);
t += replen;
}
rcount++;
expand += delta;
/* Find the next location */
s += tokenlen;
if (ic == 1)
break;
c = (*match) (base, s, token, tokenlen);
if (noquote) {
q = strpbrk(s, "\"\'");
if (!q) {
noquote = 0;
} else {
while (q && (q < c)) {
/* First match was found inside a quote. Try to find another match */
q2 = end_quote(q);
if (!q2) {
c = 0;
break;
}
if (q2 > c)
c = (*match) (base, q2 + 1, token, tokenlen);
if (!c)
break;
q = strpbrk(q2 + 1, "\"\'");
if (!q)
noquote = 0; /* No more quotes */
}
}
}
if (delta) {
if (c) {
memmove(t, s, c - s);
t += (c - s);
} else {
memmove(t, s, (str + str_len) - s + 1);
}
} else {
t += (c - s);
}
s = c;
ic--;
}
if (s && delta) {
memmove(t, s, (str + str_len) - s + 1);
}
str_len += expand;
str[str_len] = 0;
if (str_sp >= str_len)
str_sp += expand; /* Fix the end of file pointer */
return rcount;
}
/* The string is expanding as a result of the replacement */
/* Figure out how much expansion is going to occur and allocate a new string */
{
char *ns;
int newsize;
rcount++;
ic = count - 1;
s += tokenlen;
while (ic && (c = (*match) (base, s, token, tokenlen))) {
if (noquote) {
q = strpbrk(s, "\"\'");
if (!q) {
break;
} else {
while (q && (q < c)) {
/* First match was found inside a quote. Try to find another match */
q2 = end_quote(q);
if (!q2) {
c = 0;
break;
}
if (q2 > c) {
c = (*match) (base, q2 + 1, token, tokenlen);
if (!c)
break;
}
q = strpbrk(q2 + 1, "\"\'");
if (!q)
noquote = 0;
}
}
}
if (c) {
rcount++;
ic--;
s = c + tokenlen;
} else {
break;
}
}
expand = delta * rcount; /* Total amount of expansion for the replacement */
//newsize = str->maxsize;
//while ((str->len + expand) >= newsize)
// newsize *= 2;
newsize = str_len + expand + 1;
ns = new char[newsize];
assert(ns);
t = ns;
s = first;
/* Copy the first part of the string */
if (first > str) {
memcpy(t, str, (first - str));
t += (first - str);
}
for (i = 0; i < rcount; i++) {
memcpy(t, rep, replen);
t += replen;
s += tokenlen;
c = (*match) (base, s, token, tokenlen);
if (noquote) {
q = strpbrk(s, "\"\'");
if (!q) {
noquote = 0;
} else {
while (q && (q < c)) {
/* First match was found inside a quote. Try to find another match */
q2 = end_quote(q);
if (!q2) {
c = 0;
break;
}
if (q2 > c) {
c = (*match) (base, q2 + 1, token, tokenlen);
if (!c)
break;
}
q = strpbrk(q2 + 1, "\"\'");
if (!q)
noquote = 0; /* No more quotes */
}
}
}
if (i < (rcount - 1)) {
memcpy(t, s, c - s);
t += (c - s);
} else {
memcpy(t, s, (str + str_len) - s + 1);
}
s = c;
}
c = str;
str = ns;
if (str_sp >= str_len)
str_sp += expand;
str_len += expand;
str[str_len] = 0;
//DohFree(c);
delete []c;
return rcount;
}
}
}