With flags DOH_REPLACE_ID_BEGIN, DOH_REPLACE_ID_END and
DOH_REPLACE_NUMBER_END the code looked for a match for the token
string using strstr() and then checked the extra condition - if the
extra condition didn't apply it then advanced by the length of the token
before searching again.
However that can miss matches if the strstr() matches can overlap
one another, so only advance one position, which is conservative
but can't miss matches.
For example this would not match before:
Replace("123123", "1231", r, DOH_REPLACE_NUMBER_END);
This issue seems to be entirely latent in the current SWIG codebase
due to the nature of the token strings passed when using these flags.
See #2235
1278 lines
31 KiB
C
1278 lines
31 KiB
C
/* -----------------------------------------------------------------------------
|
|
* This file is part of SWIG, which is licensed as a whole under version 3
|
|
* (or any later version) of the GNU General Public License. Some additional
|
|
* terms also apply to certain portions of SWIG. The full details of the SWIG
|
|
* license and copyrights can be found in the LICENSE and COPYRIGHT files
|
|
* included with the SWIG source code as distributed by the SWIG developers
|
|
* and at http://www.swig.org/legal.html.
|
|
*
|
|
* string.c
|
|
*
|
|
* Implements a string object that supports both sequence operations and
|
|
* file semantics.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include "dohint.h"
|
|
|
|
extern DohObjInfo DohStringType;
|
|
|
|
typedef struct String {
|
|
DOH *file;
|
|
int line;
|
|
int maxsize; /* Max size allocated */
|
|
int len; /* Current length */
|
|
int hashkey; /* Hash key value */
|
|
int sp; /* Current position */
|
|
char *str; /* String data */
|
|
} String;
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_data() - Return as a 'void *'
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void *String_data(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
s->str[s->len] = 0;
|
|
return (void *) s->str;
|
|
}
|
|
|
|
/* static char *String_char(DOH *so) {
|
|
return (char *) String_data(so);
|
|
}
|
|
*/
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_dump() - Serialize a string onto out
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_dump(DOH *so, DOH *out) {
|
|
int nsent;
|
|
int ret;
|
|
String *s = (String *) ObjData(so);
|
|
nsent = 0;
|
|
while (nsent < s->len) {
|
|
ret = Write(out, s->str + nsent, (s->len - nsent));
|
|
if (ret < 0)
|
|
return ret;
|
|
nsent += ret;
|
|
}
|
|
return nsent;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* CopyString() - Copy a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static DOH *CopyString(DOH *so) {
|
|
String *str;
|
|
String *s = (String *) ObjData(so);
|
|
str = (String *) DohMalloc(sizeof(String));
|
|
str->hashkey = s->hashkey;
|
|
str->sp = s->sp;
|
|
str->line = s->line;
|
|
str->file = s->file;
|
|
if (str->file)
|
|
Incref(str->file);
|
|
str->str = (char *) DohMalloc(s->len + 1);
|
|
memcpy(str->str, s->str, s->len);
|
|
str->maxsize = s->len;
|
|
str->len = s->len;
|
|
str->str[str->len] = 0;
|
|
|
|
return DohObjMalloc(&DohStringType, str);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DelString() - Delete a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void DelString(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
DohFree(s->str);
|
|
DohFree(s);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohString_len() - Length of a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_len(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
return s->len;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_cmp() - Compare two strings
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_cmp(DOH *so1, DOH *so2) {
|
|
String *s1, *s2;
|
|
char *c1, *c2;
|
|
int maxlen, i;
|
|
s1 = (String *) ObjData(so1);
|
|
s2 = (String *) ObjData(so2);
|
|
maxlen = s1->len;
|
|
if (s2->len < maxlen)
|
|
maxlen = s2->len;
|
|
c1 = s1->str;
|
|
c2 = s2->str;
|
|
for (i = maxlen; i; --i, c1++, c2++) {
|
|
if (*c1 != *c2)
|
|
break;
|
|
}
|
|
if (i != 0) {
|
|
if (*c1 < *c2)
|
|
return -1;
|
|
else
|
|
return 1;
|
|
}
|
|
if (s1->len == s2->len)
|
|
return 0;
|
|
if (s1->len > s2->len)
|
|
return 1;
|
|
return -1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_equal() - Say if two string are equal
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_equal(DOH *so1, DOH *so2) {
|
|
String *s1 = (String *) ObjData(so1);
|
|
String *s2 = (String *) ObjData(so2);
|
|
int len = s1->len;
|
|
if (len != s2->len) {
|
|
return 0;
|
|
} else {
|
|
char *c1 = s1->str;
|
|
char *c2 = s2->str;
|
|
#if 0
|
|
int mlen = len >> 2;
|
|
int i = mlen;
|
|
for (; i; --i) {
|
|
if (*(c1++) != *(c2++))
|
|
return 0;
|
|
if (*(c1++) != *(c2++))
|
|
return 0;
|
|
if (*(c1++) != *(c2++))
|
|
return 0;
|
|
if (*(c1++) != *(c2++))
|
|
return 0;
|
|
}
|
|
for (i = len - (mlen << 2); i; --i) {
|
|
if (*(c1++) != *(c2++))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
#else
|
|
return memcmp(c1, c2, len) == 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_hash() - Compute string hash value
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_hash(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
if (s->hashkey >= 0) {
|
|
return s->hashkey;
|
|
} else {
|
|
char *c = s->str;
|
|
unsigned int len = s->len > 50 ? 50 : s->len;
|
|
unsigned int h = 0;
|
|
unsigned int mlen = len >> 2;
|
|
unsigned int i = mlen;
|
|
for (; i; --i) {
|
|
h = (h << 5) + *(c++);
|
|
h = (h << 5) + *(c++);
|
|
h = (h << 5) + *(c++);
|
|
h = (h << 5) + *(c++);
|
|
}
|
|
for (i = len - (mlen << 2); i; --i) {
|
|
h = (h << 5) + *(c++);
|
|
}
|
|
h &= 0x7fffffff;
|
|
s->hashkey = (int)h;
|
|
return h;
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* DohString_append() - Append to s
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void DohString_append(DOH *so, const DOHString_or_char *str) {
|
|
int oldlen, newlen, newmaxsize, l, sp;
|
|
char *tc;
|
|
String *s = (String *) ObjData(so);
|
|
char *newstr = 0;
|
|
|
|
if (DohCheck(str)) {
|
|
String *ss = (String *) ObjData(str);
|
|
newstr = (char *) String_data((DOH *) str);
|
|
l = ss->len;
|
|
} else {
|
|
newstr = (char *) (str);
|
|
l = (int) strlen(newstr);
|
|
}
|
|
if (!newstr)
|
|
return;
|
|
s->hashkey = -1;
|
|
|
|
oldlen = s->len;
|
|
newlen = oldlen + l + 1;
|
|
if (newlen >= s->maxsize - 1) {
|
|
newmaxsize = 2 * s->maxsize;
|
|
if (newlen >= newmaxsize - 1)
|
|
newmaxsize = newlen + 1;
|
|
s->str = (char *) DohRealloc(s->str, newmaxsize);
|
|
s->maxsize = newmaxsize;
|
|
}
|
|
tc = s->str;
|
|
memcpy(tc + oldlen, newstr, l + 1);
|
|
sp = s->sp;
|
|
if (sp >= oldlen) {
|
|
int i = oldlen + l - sp;
|
|
tc += sp;
|
|
for (; i; --i) {
|
|
if (*(tc++) == '\n')
|
|
s->line++;
|
|
}
|
|
s->sp = oldlen + l;
|
|
}
|
|
s->len += l;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_clear() - Clear a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void String_clear(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
s->hashkey = -1;
|
|
s->len = 0;
|
|
*(s->str) = 0;
|
|
s->sp = 0;
|
|
s->line = 1;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_insert() - Insert a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_insert(DOH *so, int pos, DOH *str) {
|
|
String *s;
|
|
int len;
|
|
char *data;
|
|
|
|
if (pos == DOH_END) {
|
|
DohString_append(so, str);
|
|
return 0;
|
|
}
|
|
|
|
|
|
s = (String *) ObjData(so);
|
|
s->hashkey = -1;
|
|
if (DohCheck(str)) {
|
|
String *ss = (String *) ObjData(str);
|
|
data = (char *) String_data(str);
|
|
len = ss->len;
|
|
} else {
|
|
data = (char *) (str);
|
|
len = (int) strlen(data);
|
|
}
|
|
|
|
if (pos < 0)
|
|
pos = 0;
|
|
else if (pos > s->len)
|
|
pos = s->len;
|
|
|
|
/* See if there is room to insert the new data */
|
|
while (s->maxsize <= s->len + len) {
|
|
int newsize = 2 * s->maxsize;
|
|
s->str = (char *) DohRealloc(s->str, newsize);
|
|
s->maxsize = newsize;
|
|
}
|
|
memmove(s->str + pos + len, s->str + pos, (s->len - pos));
|
|
memcpy(s->str + pos, data, len);
|
|
if (s->sp >= pos) {
|
|
int i;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (data[i] == '\n')
|
|
s->line++;
|
|
}
|
|
s->sp += len;
|
|
}
|
|
s->len += len;
|
|
s->str[s->len] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_delitem() - Delete a character
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_delitem(DOH *so, int pos) {
|
|
String *s = (String *) ObjData(so);
|
|
s->hashkey = -1;
|
|
if (pos == DOH_END)
|
|
pos = s->len - 1;
|
|
if (pos == DOH_BEGIN)
|
|
pos = 0;
|
|
if (s->len == 0)
|
|
return 0;
|
|
|
|
if (s->sp > pos) {
|
|
s->sp--;
|
|
assert(s->sp >= 0);
|
|
if (s->str[pos] == '\n')
|
|
s->line--;
|
|
}
|
|
memmove(s->str + pos, s->str + pos + 1, ((s->len - 1) - pos));
|
|
s->len--;
|
|
s->str[s->len] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_delslice() - Delete a range
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_delslice(DOH *so, int sindex, int eindex) {
|
|
String *s = (String *) ObjData(so);
|
|
int size;
|
|
if (s->len == 0)
|
|
return 0;
|
|
s->hashkey = -1;
|
|
if (eindex == DOH_END)
|
|
eindex = s->len;
|
|
if (sindex == DOH_BEGIN)
|
|
sindex = 0;
|
|
|
|
size = eindex - sindex;
|
|
if (s->sp > sindex) {
|
|
/* Adjust the file pointer and line count */
|
|
int i, end;
|
|
if (s->sp > eindex) {
|
|
end = eindex;
|
|
s->sp -= size;
|
|
} else {
|
|
end = s->sp;
|
|
s->sp = sindex;
|
|
}
|
|
for (i = sindex; i < end; i++) {
|
|
if (s->str[i] == '\n')
|
|
s->line--;
|
|
}
|
|
assert(s->sp >= 0);
|
|
}
|
|
memmove(s->str + sindex, s->str + eindex, s->len - eindex);
|
|
s->len -= size;
|
|
s->str[s->len] = 0;
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_str() - Returns a string (used by printing commands)
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static DOH *String_str(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
s->str[s->len] = 0;
|
|
return NewString(s->str);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_read() - Read data from a string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_read(DOH *so, void *buffer, int len) {
|
|
int reallen, retlen;
|
|
char *cb;
|
|
String *s = (String *) ObjData(so);
|
|
if ((s->sp + len) > s->len)
|
|
reallen = (s->len - s->sp);
|
|
else
|
|
reallen = len;
|
|
|
|
cb = (char *) buffer;
|
|
retlen = reallen;
|
|
|
|
if (reallen > 0) {
|
|
memmove(cb, s->str + s->sp, reallen);
|
|
s->sp += reallen;
|
|
}
|
|
return retlen;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_write() - Write data to a string
|
|
* ----------------------------------------------------------------------------- */
|
|
static int String_write(DOH *so, const void *buffer, int len) {
|
|
int newlen;
|
|
String *s = (String *) ObjData(so);
|
|
s->hashkey = -1;
|
|
if (s->sp > s->len)
|
|
s->sp = s->len;
|
|
newlen = s->sp + len + 1;
|
|
if (newlen > s->maxsize) {
|
|
s->str = (char *) DohRealloc(s->str, newlen);
|
|
s->maxsize = newlen;
|
|
s->len = s->sp + len;
|
|
}
|
|
if ((s->sp + len) > s->len)
|
|
s->len = s->sp + len;
|
|
memmove(s->str + s->sp, buffer, len);
|
|
s->sp += len;
|
|
s->str[s->len] = 0;
|
|
return len;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_seek() - Seek to a new position
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_seek(DOH *so, long offset, int whence) {
|
|
int pos, nsp, inc;
|
|
String *s = (String *) ObjData(so);
|
|
if (whence == SEEK_SET)
|
|
pos = 0;
|
|
else if (whence == SEEK_CUR)
|
|
pos = s->sp;
|
|
else if (whence == SEEK_END) {
|
|
pos = s->len;
|
|
offset = -offset;
|
|
} else
|
|
pos = s->sp;
|
|
|
|
nsp = pos + offset;
|
|
if (nsp < 0)
|
|
nsp = 0;
|
|
if (s->len > 0 && nsp > s->len)
|
|
nsp = s->len;
|
|
|
|
inc = (nsp > s->sp) ? 1 : -1;
|
|
|
|
{
|
|
#if 0
|
|
int sp = s->sp;
|
|
char *tc = s->str;
|
|
int len = s->len;
|
|
while (sp != nsp) {
|
|
int prev = sp + inc;
|
|
if (prev >= 0 && prev <= len && tc[prev] == '\n')
|
|
s->line += inc;
|
|
sp += inc;
|
|
}
|
|
#else
|
|
int sp = s->sp;
|
|
char *tc = s->str;
|
|
if (inc > 0) {
|
|
while (sp != nsp) {
|
|
if (tc[++sp] == '\n')
|
|
++s->line;
|
|
}
|
|
} else {
|
|
while (sp != nsp) {
|
|
if (tc[--sp] == '\n')
|
|
--s->line;
|
|
}
|
|
}
|
|
#endif
|
|
s->sp = sp;
|
|
}
|
|
assert(s->sp >= 0);
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_tell() - Return current position
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static long String_tell(DOH *so) {
|
|
String *s = (String *) ObjData(so);
|
|
return (long) (s->sp);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_putc()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_putc(DOH *so, int ch) {
|
|
String *s = (String *) ObjData(so);
|
|
int len = s->len;
|
|
int sp = s->sp;
|
|
s->hashkey = -1;
|
|
if (sp >= len) {
|
|
int maxsize = s->maxsize;
|
|
char *tc = s->str;
|
|
if (len > (maxsize - 2)) {
|
|
maxsize *= 2;
|
|
tc = (char *) DohRealloc(tc, maxsize);
|
|
s->maxsize = (int) maxsize;
|
|
s->str = tc;
|
|
}
|
|
tc += sp;
|
|
*tc = (char) ch;
|
|
*(++tc) = 0;
|
|
s->len = s->sp = sp + 1;
|
|
} else {
|
|
s->str[s->sp++] = (char) ch;
|
|
}
|
|
if (ch == '\n')
|
|
s->line++;
|
|
return ch;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_getc()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_getc(DOH *so) {
|
|
int c;
|
|
String *s = (String *) ObjData(so);
|
|
if (s->sp >= s->len)
|
|
c = EOF;
|
|
else
|
|
c = (int)(unsigned char) s->str[s->sp++];
|
|
if (c == '\n')
|
|
s->line++;
|
|
return c;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_ungetc()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_ungetc(DOH *so, int ch) {
|
|
String *s = (String *) ObjData(so);
|
|
if (ch == EOF)
|
|
return ch;
|
|
if (s->sp <= 0)
|
|
return EOF;
|
|
s->sp--;
|
|
if (ch == '\n')
|
|
s->line--;
|
|
return ch;
|
|
}
|
|
|
|
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 *end_comment(char *s) {
|
|
char *substring = strstr(s, "*/");
|
|
if (substring)
|
|
++substring;
|
|
return substring;
|
|
}
|
|
|
|
static char *match_simple(char *base, char *s, char *token, int tokenlen) {
|
|
(void) base;
|
|
(void) tokenlen;
|
|
return strstr(s, token);
|
|
}
|
|
|
|
static char *match_identifier(char *base, char *s, char *token, int tokenlen) {
|
|
while (s) {
|
|
s = strstr(s, token);
|
|
if (!s)
|
|
return 0;
|
|
if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
|
|
/* We could advance by tokenlen if strstr(s, token) matches can't overlap. */
|
|
++s;
|
|
continue;
|
|
}
|
|
if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
|
|
/* We could advance by tokenlen if strstr(s, token) matches can't overlap. */
|
|
++s;
|
|
continue;
|
|
}
|
|
return s;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static char *match_identifier_begin(char *base, char *s, char *token, int tokenlen) {
|
|
(void)tokenlen;
|
|
while (s) {
|
|
s = strstr(s, token);
|
|
if (!s)
|
|
return 0;
|
|
if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
|
|
/* We could advance by tokenlen if strstr(s, token) matches can't overlap. */
|
|
++s;
|
|
continue;
|
|
}
|
|
return s;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *match_identifier_end(char *base, char *s, char *token, int tokenlen) {
|
|
(void) base;
|
|
while (s) {
|
|
s = strstr(s, token);
|
|
if (!s)
|
|
return 0;
|
|
if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
|
|
/* We could advance by tokenlen if strstr(s, token) matches can't overlap. */
|
|
++s;
|
|
continue;
|
|
}
|
|
return s;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static char *match_number_end(char *base, char *s, char *token, int tokenlen) {
|
|
(void) base;
|
|
while (s) {
|
|
s = strstr(s, token);
|
|
if (!s)
|
|
return 0;
|
|
if (isdigit((int) *(s + tokenlen))) {
|
|
/* We could advance by tokenlen if strstr(s, token) matches can't overlap. */
|
|
++s;
|
|
continue;
|
|
}
|
|
return s;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* replace_simple()
|
|
*
|
|
* Replaces count non-overlapping occurrences of token with rep in a string.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int replace_simple(String *str, char *token, char *rep, int flags, int count, char *(*match) (char *, char *, 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;
|
|
int nocomment = 0;
|
|
char *c, *s, *t, *first;
|
|
char *q, *q2;
|
|
char *base;
|
|
int i;
|
|
|
|
/* Figure out if anything gets replaced */
|
|
if (!strlen(token))
|
|
return 0;
|
|
|
|
base = str->str;
|
|
tokenlen = (int)strlen(token);
|
|
s = (*match) (base, base, token, tokenlen);
|
|
|
|
if (!s)
|
|
return 0; /* No matches. Who cares */
|
|
|
|
str->hashkey = -1;
|
|
|
|
if (flags & DOH_REPLACE_NOQUOTE)
|
|
noquote = 1;
|
|
|
|
if (flags & DOH_REPLACE_NOCOMMENT)
|
|
nocomment = 1;
|
|
|
|
assert(!(noquote && nocomment)); /* quote and comment combination not implemented */
|
|
|
|
/* 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 */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we are not replacing inside comments, we need to do a little extra work */
|
|
if (nocomment) {
|
|
q = strstr(base, "/*");
|
|
if (!q) {
|
|
nocomment = 0; /* Well, no comments to worry about. Oh well */
|
|
} else {
|
|
while (q && (q < s)) {
|
|
/* First match was found inside a comment. Try to find another match */
|
|
q2 = end_comment(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 = strstr(q2 + 1, "/*");
|
|
if (!q)
|
|
nocomment = 0; /* No more comments */
|
|
}
|
|
}
|
|
}
|
|
|
|
first = s;
|
|
replen = (int)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 (nocomment) {
|
|
q = strstr(s, "/*");
|
|
if (!q) {
|
|
nocomment = 0;
|
|
} else {
|
|
while (q && (q < c)) {
|
|
/* First match was found inside a comment. Try to find another match */
|
|
q2 = end_comment(q);
|
|
if (!q2) {
|
|
c = 0;
|
|
break;
|
|
}
|
|
if (q2 > c)
|
|
c = (*match) (base, q2 + 1, token, tokenlen);
|
|
if (!c)
|
|
break;
|
|
q = strstr(q2 + 1, "/*");
|
|
if (!q)
|
|
nocomment = 0; /* No more comments */
|
|
}
|
|
}
|
|
}
|
|
if (delta) {
|
|
if (c) {
|
|
memmove(t, s, c - s);
|
|
t += (c - s);
|
|
} else {
|
|
memmove(t, s, (str->str + str->len) - s + 1);
|
|
}
|
|
} else {
|
|
if (c) {
|
|
t += (c - s);
|
|
}
|
|
}
|
|
s = c;
|
|
ic--;
|
|
}
|
|
if (s && delta) {
|
|
memmove(t, s, (str->str + str->len) - s + 1);
|
|
}
|
|
str->len += expand;
|
|
str->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 (nocomment) {
|
|
q = strstr(s, "/*");
|
|
if (!q) {
|
|
break;
|
|
} else {
|
|
while (q && (q < c)) {
|
|
/* First match was found inside a comment. Try to find another match */
|
|
q2 = end_comment(q);
|
|
if (!q2) {
|
|
c = 0;
|
|
break;
|
|
}
|
|
if (q2 > c) {
|
|
c = (*match) (base, q2 + 1, token, tokenlen);
|
|
if (!c)
|
|
break;
|
|
}
|
|
q = strstr(q2 + 1, "/*");
|
|
if (!q)
|
|
nocomment = 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;
|
|
|
|
ns = (char *) DohMalloc(newsize);
|
|
t = ns;
|
|
s = first;
|
|
|
|
/* Copy the first part of the string */
|
|
if (first > str->str) {
|
|
memcpy(t, str->str, (first - str->str));
|
|
t += (first - str->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 (nocomment) {
|
|
q = strstr(s, "/*");
|
|
if (!q) {
|
|
nocomment = 0;
|
|
} else {
|
|
while (q && (q < c)) {
|
|
/* First match was found inside a comment. Try to find another match */
|
|
q2 = end_comment(q);
|
|
if (!q2) {
|
|
c = 0;
|
|
break;
|
|
}
|
|
if (q2 > c) {
|
|
c = (*match) (base, q2 + 1, token, tokenlen);
|
|
if (!c)
|
|
break;
|
|
}
|
|
q = strstr(q2 + 1, "/*");
|
|
if (!q)
|
|
nocomment = 0; /* No more comments */
|
|
}
|
|
}
|
|
}
|
|
if (i < (rcount - 1)) {
|
|
memcpy(t, s, c - s);
|
|
t += (c - s);
|
|
} else {
|
|
memcpy(t, s, (str->str + str->len) - s + 1);
|
|
}
|
|
s = c;
|
|
}
|
|
c = str->str;
|
|
str->str = ns;
|
|
if (str->sp >= str->len)
|
|
str->sp += expand;
|
|
str->len += expand;
|
|
str->str[str->len] = 0;
|
|
str->maxsize = newsize;
|
|
DohFree(c);
|
|
return rcount;
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_replace()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static int String_replace(DOH *stro, const DOHString_or_char *token, const DOHString_or_char *rep, int flags) {
|
|
int count = -1;
|
|
String *str = (String *) ObjData(stro);
|
|
|
|
if (flags & DOH_REPLACE_FIRST)
|
|
count = 1;
|
|
|
|
if (flags & DOH_REPLACE_ID_END) {
|
|
return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_end);
|
|
} else if (flags & DOH_REPLACE_ID_BEGIN) {
|
|
return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_begin);
|
|
} else if (flags & DOH_REPLACE_ID) {
|
|
return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier);
|
|
} else if (flags & DOH_REPLACE_NUMBER_END) {
|
|
return replace_simple(str, Char(token), Char(rep), flags, count, match_number_end);
|
|
} else {
|
|
return replace_simple(str, Char(token), Char(rep), flags, count, match_simple);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* String_chop()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static void String_chop(DOH *so) {
|
|
char *c;
|
|
String *str = (String *) ObjData(so);
|
|
/* Replace trailing whitespace */
|
|
c = str->str + str->len - 1;
|
|
while ((str->len > 0) && (isspace((int) *c))) {
|
|
if (str->sp >= str->len) {
|
|
str->sp--;
|
|
if (*c == '\n')
|
|
str->line--;
|
|
}
|
|
str->len--;
|
|
c--;
|
|
}
|
|
str->str[str->len] = 0;
|
|
assert(str->sp >= 0);
|
|
str->hashkey = -1;
|
|
}
|
|
|
|
static void String_setfile(DOH *so, DOH *file) {
|
|
DOH *fo;
|
|
String *str = (String *) ObjData(so);
|
|
|
|
if (!DohCheck(file)) {
|
|
fo = NewString(file);
|
|
Decref(fo);
|
|
} else
|
|
fo = file;
|
|
Incref(fo);
|
|
Delete(str->file);
|
|
str->file = fo;
|
|
}
|
|
|
|
static DOH *String_getfile(DOH *so) {
|
|
String *str = (String *) ObjData(so);
|
|
return str->file;
|
|
}
|
|
|
|
static void String_setline(DOH *so, int line) {
|
|
String *str = (String *) ObjData(so);
|
|
str->line = line;
|
|
}
|
|
|
|
static int String_getline(DOH *so) {
|
|
String *str = (String *) ObjData(so);
|
|
return str->line;
|
|
}
|
|
|
|
static DohListMethods StringListMethods = {
|
|
0, /* doh_getitem */
|
|
0, /* doh_setitem */
|
|
String_delitem, /* doh_delitem */
|
|
String_insert, /* doh_insitem */
|
|
String_delslice, /* doh_delslice */
|
|
};
|
|
|
|
static DohFileMethods StringFileMethods = {
|
|
String_read,
|
|
String_write,
|
|
String_putc,
|
|
String_getc,
|
|
String_ungetc,
|
|
String_seek,
|
|
String_tell,
|
|
};
|
|
|
|
static DohStringMethods StringStringMethods = {
|
|
String_replace,
|
|
String_chop,
|
|
};
|
|
|
|
DohObjInfo DohStringType = {
|
|
"String", /* objname */
|
|
DelString, /* doh_del */
|
|
CopyString, /* doh_copy */
|
|
String_clear, /* doh_clear */
|
|
String_str, /* doh_str */
|
|
String_data, /* doh_data */
|
|
String_dump, /* doh_dump */
|
|
String_len, /* doh_len */
|
|
String_hash, /* doh_hash */
|
|
String_cmp, /* doh_cmp */
|
|
String_equal, /* doh_equal */
|
|
0, /* doh_first */
|
|
0, /* doh_next */
|
|
String_setfile, /* doh_setfile */
|
|
String_getfile, /* doh_getfile */
|
|
String_setline, /* doh_setline */
|
|
String_getline, /* doh_getline */
|
|
0, /* doh_mapping */
|
|
&StringListMethods, /* doh_sequence */
|
|
&StringFileMethods, /* doh_file */
|
|
&StringStringMethods, /* doh_string */
|
|
0, /* doh_position */
|
|
0
|
|
};
|
|
|
|
|
|
#define INIT_MAXSIZE 16
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* NewString() - Create a new string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
DOHString *DohNewString(const DOHString_or_char *so) {
|
|
int l = 0, max;
|
|
String *str;
|
|
char *s;
|
|
int hashkey = -1;
|
|
if (DohCheck(so)) {
|
|
str = (String *) ObjData(so);
|
|
s = (char *) String_data((String *) so);
|
|
l = s ? str->len : 0;
|
|
hashkey = str->hashkey;
|
|
} else {
|
|
s = (char *) so;
|
|
l = s ? (int) strlen(s) : 0;
|
|
}
|
|
|
|
str = (String *) DohMalloc(sizeof(String));
|
|
str->hashkey = hashkey;
|
|
str->sp = 0;
|
|
str->line = 1;
|
|
str->file = 0;
|
|
max = INIT_MAXSIZE;
|
|
if (s) {
|
|
if ((l + 1) > max)
|
|
max = l + 1;
|
|
}
|
|
str->str = (char *) DohMalloc(max);
|
|
str->maxsize = max;
|
|
if (s) {
|
|
strcpy(str->str, s);
|
|
str->len = l;
|
|
str->sp = l;
|
|
} else {
|
|
str->str[0] = 0;
|
|
str->len = 0;
|
|
}
|
|
return DohObjMalloc(&DohStringType, str);
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* NewStringEmpty() - Create a new string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
DOHString *DohNewStringEmpty(void) {
|
|
int max = INIT_MAXSIZE;
|
|
String *str = (String *) DohMalloc(sizeof(String));
|
|
str->hashkey = 0;
|
|
str->sp = 0;
|
|
str->line = 1;
|
|
str->file = 0;
|
|
str->str = (char *) DohMalloc(max);
|
|
str->maxsize = max;
|
|
str->str[0] = 0;
|
|
str->len = 0;
|
|
return DohObjMalloc(&DohStringType, str);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* NewStringWithSize() - Create a new string
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
DOHString *DohNewStringWithSize(const DOHString_or_char *so, int len) {
|
|
int l = 0, max;
|
|
String *str;
|
|
char *s;
|
|
if (DohCheck(so)) {
|
|
s = (char *) String_data((String *) so);
|
|
} else {
|
|
s = (char *) so;
|
|
}
|
|
|
|
str = (String *) DohMalloc(sizeof(String));
|
|
str->hashkey = -1;
|
|
str->sp = 0;
|
|
str->line = 1;
|
|
str->file = 0;
|
|
max = INIT_MAXSIZE;
|
|
if (s) {
|
|
l = (int) len;
|
|
if ((l + 1) > max)
|
|
max = l + 1;
|
|
}
|
|
str->str = (char *) DohMalloc(max);
|
|
str->maxsize = max;
|
|
if (s) {
|
|
strncpy(str->str, s, len);
|
|
str->str[l] = 0;
|
|
str->len = l;
|
|
str->sp = l;
|
|
} else {
|
|
str->str[0] = 0;
|
|
str->len = 0;
|
|
}
|
|
return DohObjMalloc(&DohStringType, str);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* NewStringf()
|
|
*
|
|
* Create a new string from a list of objects.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
DOHString *DohNewStringf(const DOHString_or_char *fmt, ...) {
|
|
va_list ap;
|
|
DOH *r;
|
|
va_start(ap, fmt);
|
|
r = NewStringEmpty();
|
|
DohvPrintf(r, Char(fmt), ap);
|
|
va_end(ap);
|
|
return (DOHString *) r;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Strcmp()
|
|
* Strncmp()
|
|
* Strstr()
|
|
* Strchr()
|
|
*
|
|
* Some utility functions.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
int DohStrcmp(const DOHString_or_char *s1, const DOHString_or_char *s2) {
|
|
const char *c1 = Char(s1);
|
|
const char *c2 = Char(s2);
|
|
return strcmp(c1, c2);
|
|
}
|
|
|
|
int DohStrncmp(const DOHString_or_char *s1, const DOHString_or_char *s2, int n) {
|
|
return strncmp(Char(s1), Char(s2), n);
|
|
}
|
|
|
|
char *DohStrstr(const DOHString_or_char *s1, const DOHString_or_char *s2) {
|
|
char *p1 = Char(s1);
|
|
char *p2 = Char(s2);
|
|
return p1 == 0 || p2 == 0 || *p2 == '\0' ? p1 : strstr(p1, p2);
|
|
}
|
|
|
|
char *DohStrchr(const DOHString_or_char *s1, int ch) {
|
|
return strchr(Char(s1), ch);
|
|
}
|