/* ----------------------------------------------------------------------------- * 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 https://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 { /* We use the djb2 hash function: https://theartincode.stanis.me/008-djb2/ * * One difference is we use initial seed 0. It seems the usual seed value * is intended to help spread out hash values, which is beneficial if * linear probing is used but DOH Hash uses a chain of buckets instead, and * grouped hash values are probably more cache friendly. In tests using * 0 seems slightly faster anyway. */ const 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 + (h << 5) + *(c++); h = h + (h << 5) + *(c++); h = h + (h << 5) + *(c++); h = h + (h << 5) + *(c++); } for (i = len - (mlen << 2); i; --i) { h = 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); }