/* * SPL - The SPL Programming Language * Copyright (C) 2004, 2005 Clifford Wolf * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * string.c: SPL string implementation */ #include #include #include #include #include "spl.h" #include "compat.h" #define newlen(a,b) (a+b < a || a+b >= ~0U >> 1 ? ~0U : a+b) struct spl_string *spl_string_new(int flags, struct spl_string *left, struct spl_string *right, char *text, struct spl_code *code) { struct spl_string *s = calloc(1, sizeof(struct spl_string)); if (flags & SPL_STRING_NOAUTOGET) { s->left = left; s->right = right; } else { s->left = spl_string_get(left); s->right = spl_string_get(right); } if (s->left) { s->left_len = s->left->total_len; if (s->left->flags & SPL_STRING_UTF8) s->flags |= SPL_STRING_UTF8; } if (s->right) { s->right_len = s->right->total_len; if (s->right->flags & SPL_STRING_UTF8) s->flags |= SPL_STRING_UTF8; } s->flags = flags & ~SPL_STRING_NOAUTOGET; s->ref_counter = 1; if (text) { int i = 0; while (text[i]) if (text[i++] & 0x80) s->flags |= SPL_STRING_UTF8; s->text = text; s->text_len = i; } if (code) { s->code = spl_code_get(code); s->flags |= SPL_STRING_STATIC; } s->total_len = newlen(s->total_len, s->left_len); s->total_len = newlen(s->total_len, s->text_len); s->total_len = newlen(s->total_len, s->right_len); if (s->flags & SPL_STRING_DOTCAT) s->total_len = newlen(s->total_len, 1); return s; } struct spl_string *spl_string_printf(int flags, struct spl_string *left, struct spl_string *right, const char *fmt, ...) { char *text = 0; if (fmt) { va_list ap; va_start(ap, fmt); my_vasprintf(&text, fmt, ap); va_end(ap); } return spl_string_new(flags, left, right, text, 0); } struct spl_string *spl_string_split(struct spl_string *s, unsigned int offset, unsigned int len) { if (!s) { assert(len == 0); return 0; } assert(offset+len <= s->total_len); if (len < 128) { char *text = spl_string(s); return spl_string_new(0, 0, 0, my_strndup(text+offset, len), 0); } else { struct spl_string *r = spl_string_new(0, s, 0, 0, 0); r->left_offset = offset; r->left_len = len; r->total_len = len; return r; } } struct spl_string *spl_string_get(struct spl_string *s) { if (s) s->ref_counter++; return s; } void spl_string_put(struct spl_string *s) { if (s && --(s->ref_counter) == 0) { spl_string_put(s->left); spl_string_put(s->right); spl_code_put(s->code); if ((s->flags & SPL_STRING_STATIC) == 0 && s->text) free(s->text); free(s); } } static char *spl_string_write(struct spl_string *s, int *flags_p, char *t, unsigned int offset, unsigned int len) { if (!s) return t; assert(offset+len <= s->total_len); if (s->left_len > offset) { unsigned int left_len = s->left_len - offset; if (left_len > len) left_len = len; if (left_len) { t = spl_string_write(s->left, flags_p, t, s->left_offset + offset, left_len); len -= left_len; } offset = 0; } else offset -= s->left_len; if ((s->flags & SPL_STRING_DOTCAT) != 0) { if (offset) { offset--; } else { *(t++) = '.'; len--; } } if (s->text_len > offset) { unsigned int text_len = s->text_len - offset; if (text_len > len) text_len = len; if (text_len) { int found_utf8 = 0; for (unsigned int i=0; itext[offset+i]) & 0x80) found_utf8 = 1; if (found_utf8) *flags_p |= SPL_STRING_UTF8; len -= text_len; t += text_len; } offset = 0; } else offset -= s->text_len; return spl_string_write(s->right, flags_p, t, offset, len); } char *spl_string(struct spl_string *s) { if (!s) return ""; if (!s->left && !s->right) return s->text ? s->text : ""; s->flags &= ~SPL_STRING_UTF8; assert(s->total_len != ~0U); char *newtext = malloc(s->total_len + 1); *(spl_string_write(s, &s->flags, newtext, 0, s->total_len)) = 0; spl_string_put(s->left); spl_string_put(s->right); spl_code_put(s->code); s->left = s->right = 0; s->left_offset = s->right_offset = 0; s->left_len = s->right_len = 0; s->code = 0; if ( (s->flags & SPL_STRING_STATIC) == 0 && s->text ) free(s->text); s->text_len = s->total_len; s->text = newtext; s->flags = s->flags & ~(SPL_STRING_STATIC|SPL_STRING_DOTCAT); return newtext; }