示例#1
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_init_from_fp(spif_str_t self, FILE *fp)
{
    spif_charptr_t p, end = NULL;

    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    ASSERT_RVAL((fp != (FILE *) NULL), FALSE);
    /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
    spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_STRCLASS_VAR(str)));
    self->size = buff_inc;
    self->len = 0;
    self->s = (spif_charptr_t) MALLOC(self->size);

    for (p = self->s; fgets((char *)p, buff_inc, fp); p += buff_inc) {
        if (!(end = (spif_charptr_t)strchr((const char *)p, '\n'))) {
            self->size += buff_inc;
            self->s = (spif_charptr_t) REALLOC(self->s, self->size);
        } else {
            *end = 0;
            break;
        }
    }
    self->len = (spif_stridx_t) ((end)
                          ? (end - self->s)
                          : ((int) strlen((const char *)self->s)));
    self->size = self->len + 1;
    self->s = (spif_charptr_t) REALLOC(self->s, self->size);
    return TRUE;
}
示例#2
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_init_from_fd(spif_str_t self, int fd)
{
    int n;
    spif_charptr_t p;

    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    ASSERT_RVAL((fd >= 0), FALSE);
    /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
    spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_STRCLASS_VAR(str)));
    self->size = buff_inc;
    self->len = 0;
    self->s = (spif_charptr_t) MALLOC(self->size);

    for (p = self->s; ((n = read(fd, p, buff_inc)) > 0) || (errno == EINTR);) {
        self->size += n;
        self->s = (spif_charptr_t) REALLOC(self->s, self->size);
        p += n;
    }
    self->len = self->size - buff_inc;
    self->size = self->len + 1;
    self->s = (spif_charptr_t) REALLOC(self->s, self->size);
    self->s[self->len] = 0;
    return TRUE;
}
示例#3
0
文件: strings.c 项目: mej/libast
/**
 * Thread-safe way to compare a string to a regular expression.
 */
spif_bool_t
spiftool_regexp_match_r(register const spif_charptr_t str, register const spif_charptr_t pattern, register regex_t **rexp)
{
    register int result;
    char errbuf[256];

    ASSERT_RVAL(rexp != NULL, FALSE);
    if (!*rexp) {
        *rexp = (regex_t *) MALLOC(sizeof(regex_t));
    }

    if (pattern) {
        if ((result = regcomp(*rexp, pattern, REG_EXTENDED)) != 0) {
            regerror(result, *rexp, errbuf, 256);
            libast_print_error("Unable to compile regexp %s -- %s.\n", pattern, errbuf);
            FREE(*rexp);
            return (FALSE);
        }
    }

    if (((result = regexec(*rexp, str, (size_t) 0, (regmatch_t *) NULL, 0))
         != 0) && (result != REG_NOMATCH)) {
        regerror(result, *rexp, errbuf, 256);
        libast_print_error("Error testing input string %s -- %s.\n", str, errbuf);
        return (FALSE);
    }
    return ((result == REG_NOMATCH) ? (FALSE) : (TRUE));
}
示例#4
0
文件: socket.c 项目: mej/libast
spif_bool_t
spif_socket_init_from_urls(spif_socket_t self, spif_url_t surl, spif_url_t durl)
{
    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), FALSE);
    /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
    spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS_VAR(socket));
    self->fd = -1;
    self->fam = AF_INET;
    self->type = SOCK_STREAM;
    self->proto = 0;
    self->addr = (spif_sockaddr_t) NULL;
    self->len = 0;
    self->flags = 0;
    if (!SPIF_URL_ISNULL(surl)) {
        self->local_url = spif_url_dup(surl);
    } else {
        self->local_url = (spif_url_t) NULL;
    }
    if (!SPIF_URL_ISNULL(durl)) {
        self->remote_url = spif_url_dup(durl);
    } else {
        self->remote_url = (spif_url_t) NULL;
    }
    return TRUE;
}
示例#5
0
文件: url.c 项目: Limsik/e17
spif_bool_t
spif_url_done(spif_url_t self)
{
    ASSERT_RVAL(!SPIF_URL_ISNULL(self), FALSE);
    if (!SPIF_STR_ISNULL(self->proto)) {
        spif_str_del(self->proto);
        self->proto = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->user)) {
        spif_str_del(self->user);
        self->user = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->passwd)) {
        spif_str_del(self->passwd);
        self->passwd = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->host)) {
        spif_str_del(self->host);
        self->host = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->port)) {
        spif_str_del(self->port);
        self->port = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->path)) {
        spif_str_del(self->path);
        self->path = (spif_str_t) NULL;
    }
    if (!SPIF_STR_ISNULL(self->query)) {
        spif_str_del(self->query);
        self->query = (spif_str_t) NULL;
    }
    spif_str_done(SPIF_STR(self));
    return TRUE;
}
示例#6
0
文件: socket.c 项目: mej/libast
spif_bool_t
spif_socket_done(spif_socket_t self)
{
    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), FALSE);
    if (self->fd >= 0) {
        spif_socket_close(self);
    }
    self->fam = AF_INET;
    self->type = SOCK_STREAM;
    self->proto = 0;
    if (self->addr != (spif_sockaddr_t) NULL) {
        SPIF_DEALLOC(self->addr);
        self->addr = (spif_sockaddr_t) NULL;
    }
    self->len = 0;
    self->flags = 0;
    if (!SPIF_URL_ISNULL(self->local_url)) {
        spif_url_del(self->local_url);
        self->local_url = (spif_url_t) NULL;
    }
    if (!SPIF_URL_ISNULL(self->remote_url)) {
        spif_url_del(self->remote_url);
        self->remote_url = (spif_url_t) NULL;
    }
    return TRUE;
}
示例#7
0
文件: socket.c 项目: mej/libast
spif_socket_t
spif_socket_dup(spif_socket_t self)
{
    spif_socket_t tmp;

    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), (spif_socket_t) NULL);
    tmp = spif_socket_new();
    if (self->fd >= 0) {
        tmp->fd = dup(self->fd);
    }
    tmp->fam = self->fam;
    tmp->type = self->type;
    tmp->proto = self->proto;
    tmp->len = self->len;
    if (self->addr != (spif_sockaddr_t) NULL) {
        tmp->addr = (spif_sockaddr_t) MALLOC(tmp->len);
        memcpy(tmp->addr, self->addr, tmp->len);
    }
    tmp->flags = self->flags;
    if (!SPIF_URL_ISNULL(self->local_url)) {
        tmp->local_url = spif_url_dup(self->local_url);
    }
    if (!SPIF_URL_ISNULL(self->remote_url)) {
        tmp->remote_url = spif_url_dup(self->remote_url);
    }
    return tmp;
}
示例#8
0
文件: strings.c 项目: mej/libast
spif_charptr_t 
spiftool_join(spif_charptr_t sep, spif_charptr_t *slist)
{
    register unsigned long i;
    size_t len, slen;
    spif_charptr_t new_str;

    ASSERT_RVAL(slist != (spif_ptr_t) NULL, (spif_ptr_t) NULL);
    REQUIRE_RVAL(*slist != (spif_ptr_t) NULL, (spif_ptr_t) NULL);
    if (!sep) {
        sep = SPIF_CHARPTR("");
    }
    slen = strlen((char *) sep);
    for (i = len = 0; slist[i]; i++) {
        len += strlen((char *) slist[i]);
    }
    len += slen * (i - 1);
    new_str = (spif_charptr_t) MALLOC(len + 1);
    strcpy((char *) new_str, (char *) slist[0]);
    for (i = 1; slist[i]; i++) {
        if (slen) {
            strcat((char *) new_str, (char *) sep);
        }
        strcat((char *) new_str, (char *) slist[i]);
    }
    return new_str;
}
示例#9
0
文件: strings.c 项目: mej/libast
/* Returns the number of words in str, for use with get_word() and get_pword().  "..." counts as 1 word. */
unsigned long
spiftool_num_words(const spif_charptr_t str)
{
    register unsigned long cnt = 0;
    char delim = 0;
    register unsigned long i;

    ASSERT_RVAL(str != (spif_ptr_t) NULL, (unsigned long) -1);
    for (i = 0; str[i] && IS_DELIM(str[i]); i++);
    for (; str[i]; cnt++) {
        switch (str[i]) {
          case '\"':
              delim = '\"';
              i++;
              break;
          case '\'':
              delim = '\'';
              i++;
              break;
          default:
              delim = 0;
        }
        for (; str[i] && !IS_DELIM(str[i]); i++);
        switch (str[i]) {
          case '\"':
          case '\'':
              i++;
              break;
        }
        for (; str[i] && isspace(str[i]); i++);
    }

    D_STRINGS(("num_words() returning %lu\n", cnt));
    return (cnt);
}
示例#10
0
文件: socket.c 项目: mej/libast
static spif_bool_t
spif_url_init_from_ipaddr(spif_url_t self, spif_ipsockaddr_t ipaddr)
{
    spif_uint8_t tries;
    spif_hostinfo_t hinfo;

    ASSERT_RVAL(!SPIF_URL_ISNULL(self), FALSE);
    spif_str_init(SPIF_STR(self));
    spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS_VAR(url));
    self->proto = (spif_str_t) NULL;
    self->user = (spif_str_t) NULL;
    self->passwd = (spif_str_t) NULL;
    self->path = (spif_str_t) NULL;
    self->query = (spif_str_t) NULL;

    /* Try up to 3 times to resolve the hostname. */
    h_errno = 0;
    tries = 0;
    do {
        tries++;
        hinfo = gethostbyaddr((const char *) &(ipaddr->sin_addr), sizeof(ipaddr->sin_addr), AF_INET);
    } while ((tries <= 3) && (!hinfo) && (h_errno == TRY_AGAIN));
    if (!hinfo || !hinfo->h_name) {
        spif_charptr_t buff;

        buff = SPIF_CHARPTR(inet_ntoa(ipaddr->sin_addr));
        self->host = spif_str_new_from_ptr(buff);
    } else {
        self->host = spif_str_new_from_ptr(SPIF_CHARPTR(hinfo->h_name));
    }

    self->port = spif_str_new_from_num(ntohs(ipaddr->sin_port));
    return TRUE;
}
示例#11
0
文件: socket.c 项目: mej/libast
spif_bool_t
spif_socket_check_io(spif_socket_t self)
{
    static struct timeval tv = { 0, 0 };
    fd_set read_fds, write_fds;

    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), FALSE);
    REQUIRE_RVAL(self->fd >= 0, FALSE);

    FD_ZERO(&read_fds);
    FD_SET(self->fd, &read_fds);
    FD_ZERO(&write_fds);
    FD_SET(self->fd, &write_fds);
    if ((select(self->fd + 1, &read_fds, &write_fds, NULL, &tv)) < 0) {
        libast_print_error("Unable to select() on %d -- %s\n", self->fd, strerror(errno));
        return FALSE;
    }

    if (FD_ISSET(self->fd, &read_fds)) {
        SPIF_SOCKET_FLAGS_SET(self, SPIF_SOCKET_FLAGS_HAVE_INPUT);
    } else {
        SPIF_SOCKET_FLAGS_CLEAR(self, SPIF_SOCKET_FLAGS_HAVE_INPUT);
    }
    if (FD_ISSET(self->fd, &write_fds)) {
        SPIF_SOCKET_FLAGS_SET(self, SPIF_SOCKET_FLAGS_CAN_OUTPUT);
    } else {
        SPIF_SOCKET_FLAGS_CLEAR(self, SPIF_SOCKET_FLAGS_CAN_OUTPUT);
    }
    return TRUE;
}
示例#12
0
文件: strings.c 项目: mej/libast
spif_charptr_t 
spiftool_condense_whitespace(spif_charptr_t s)
{

    register unsigned char gotspc = 0;
    register spif_charptr_t pbuff = s, pbuff2 = s;

    ASSERT_RVAL(s != (spif_ptr_t) NULL, (spif_ptr_t) NULL);
    D_STRINGS(("condense_whitespace(%s) called.\n", s));
    for (; *pbuff2; pbuff2++) {
        if (isspace(*pbuff2)) {
            if (!gotspc) {
                *pbuff = ' ';
                gotspc = 1;
                pbuff++;
            }
        } else {
            *pbuff = *pbuff2;
            gotspc = 0;
            pbuff++;
        }
    }
    if ((pbuff >= s) && (isspace(*(pbuff - 1))))
        pbuff--;
    *pbuff = 0;
    D_STRINGS(("condense_whitespace() returning \"%s\".\n", s));
    return ((spif_charptr_t) REALLOC(s, strlen((char *) s) + 1));
}
示例#13
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_clear(spif_str_t self, spif_char_t c)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    memset(self->s, c, self->size);
    self->s[self->len] = 0;
    return TRUE;
}
示例#14
0
文件: url.c 项目: Limsik/e17
spif_bool_t
spif_url_del(spif_url_t self)
{
    ASSERT_RVAL(!SPIF_URL_ISNULL(self), FALSE);
    spif_url_done(self);
    SPIF_DEALLOC(self);
    return TRUE;
}
示例#15
0
文件: socket.c 项目: mej/libast
spif_bool_t
spif_socket_del(spif_socket_t self)
{
    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), FALSE);
    spif_socket_done(self);
    SPIF_DEALLOC(self);
    return TRUE;
}
示例#16
0
文件: socket.c 项目: mej/libast
spif_bool_t
spif_socket_send(spif_socket_t self, spif_str_t data)
{
    size_t len;
    int num_written;
    struct timeval tv = { 0, 0 };

    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), FALSE);
    REQUIRE_RVAL(!SPIF_STR_ISNULL(data), FALSE);

    len = spif_str_get_len(data);
    REQUIRE_RVAL(len > 0, FALSE);

    num_written = write(self->fd, SPIF_STR_STR(data), len);
    for (; (num_written < 0) && ((errno == EAGAIN) || (errno == EINTR)); ) {
        tv.tv_usec += 10000;
        if (tv.tv_usec == 1000000) {
            tv.tv_usec = 0;
            tv.tv_sec++;
        }
        select(0, NULL, NULL, NULL, &tv);
        num_written = write(self->fd, SPIF_STR_STR(data), len);
    }
    if (num_written < 0) {
        D_OBJ(("Unable to write to socket %d -- %s\n", self->fd, strerror(errno)));
        switch (errno) {
            case EFBIG:
                {
                    spif_bool_t b;
                    spif_str_t tmp_buf;
                    spif_charptr_t s;
                    long left;

                    for (left = len, s = SPIF_CHARPTR(SPIF_STR_STR(data)); left > 0; s += 1024, left -= 1024) {
                        tmp_buf = spif_str_new_from_buff(s, 1024);
                        b = spif_socket_send(self, tmp_buf);
                        if (b == FALSE) {
                            spif_str_del(tmp_buf);
                            return b;
                        }
                    }
                }
                break;
            case EIO:
            case EPIPE:
                close(self->fd);
                /* Drop */
            case EBADF:
            case EINVAL:
            default:
                self->fd = -1;
                SPIF_SOCKET_FLAGS_CLEAR(self, SPIF_SOCKET_FLAGS_IOSTATE);
                return FALSE;
                break;
        }
    }
    return TRUE;
}
示例#17
0
文件: socket.c 项目: mej/libast
spif_str_t
spif_socket_recv(spif_socket_t self)
{
    spif_str_t new_str;

    ASSERT_RVAL(!SPIF_SOCKET_ISNULL(self), (spif_str_t) NULL);
    new_str = spif_str_new_from_fd(self->fd);
    return new_str;
}
示例#18
0
文件: url.c 项目: Limsik/e17
spif_url_t
spif_url_dup(spif_url_t self)
{
    spif_url_t tmp;

    ASSERT_RVAL(!SPIF_URL_ISNULL(self), (spif_url_t) NULL);
    tmp = spif_url_new_from_str(SPIF_STR(self));
    return tmp;
}
示例#19
0
文件: tok.c 项目: Limsik/e17
spif_bool_t
spif_tok_del(spif_tok_t self)
{
    spif_bool_t t;

    ASSERT_RVAL(!SPIF_TOK_ISNULL(self), FALSE);
    t = spif_tok_done(self);
    SPIF_DEALLOC(self);
    return t;
}
示例#20
0
文件: strings.c 项目: mej/libast
spif_charptr_t 
spiftool_get_word(unsigned long index, const spif_charptr_t str)
{
    spif_charptr_t tmpstr;
    char delim = 0;
    register unsigned long i, j, k;

    ASSERT_RVAL(str != (spif_ptr_t) NULL, (spif_ptr_t) NULL);
    k = strlen((char *) str) + 1;
    if (!(tmpstr = (spif_charptr_t)MALLOC(k))) {
        libast_print_error("get_word(%lu, %s):  Unable to allocate memory -- %s.\n", index, str, strerror(errno));
        return ((spif_charptr_t) NULL);
    }
    *tmpstr = 0;
    for (i = 0, j = 0; j < index && str[i]; j++) {
        for (; isspace(str[i]); i++);
        switch (str[i]) {
          case '\"':
              delim = '\"';
              i++;
              break;
          case '\'':
              delim = '\'';
              i++;
              break;
          default:
              delim = 0;
        }
        for (k = 0; str[i] && !IS_DELIM(str[i]);) {
            if (str[i] == '\\') {
                if (str[i + 1] == '\'' || str[i + 1] == '\"') {
                    i++;
                }
            }
            tmpstr[k++] = str[i++];
        }
        switch (str[i]) {
          case '\"':
          case '\'':
              i++;
              break;
        }
        tmpstr[k] = 0;
    }

    if (j != index) {
        FREE(tmpstr);
        D_STRINGS(("get_word(%lu, %s) returning NULL.\n", index, str));
        return ((spif_charptr_t) NULL);
    } else {
        tmpstr = (spif_charptr_t) REALLOC(tmpstr, strlen((char *) tmpstr) + 1);
        D_STRINGS(("get_word(%lu, %s) returning \"%s\".\n", index, str, tmpstr));
        return (tmpstr);
    }
}
示例#21
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_upcase(spif_str_t self)
{
    spif_charptr_t tmp;

    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    for (tmp = self->s; *tmp; tmp++) {
        *tmp = toupper(*tmp);
    }
    return TRUE;
}
示例#22
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_init(spif_str_t self)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    /* ***NOT NEEDED*** spif_obj_init(SPIF_OBJ(self)); */
    spif_obj_set_class(SPIF_OBJ(self), SPIF_CLASS(SPIF_STRCLASS_VAR(str)));
    self->s = (spif_charptr_t) NULL;
    self->len = 0;
    self->size = 0;
    return TRUE;
}
示例#23
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_done(spif_str_t self)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    if (self->size) {
        FREE(self->s);
        self->len = 0;
        self->size = 0;
        self->s = (spif_charptr_t) NULL;
    }
    return TRUE;
}
示例#24
0
文件: strings.c 项目: mej/libast
spif_charptr_t 
spiftool_upcase_str(spif_charptr_t str)
{
    register spif_charptr_t tmp;

    ASSERT_RVAL(str != (spif_ptr_t) NULL, (spif_ptr_t) NULL);
    for (tmp = str; *tmp; tmp++) {
        *tmp = toupper(*tmp);
    }
    D_STRINGS(("upcase_str() returning %s\n", str));
    return (str);
}
示例#25
0
spif_bool_t
eterm_action_dispatch(event_t *ev)
{
    spif_eterm_action_t action;
    spif_iterator_t iter;

    ASSERT_RVAL(ev != NULL, FALSE);
    ASSERT_RVAL(ev->xany.type == ButtonPress || ev->xany.type == KeyPress, FALSE);
    D_ACTIONS(("Event %8p:  Button %d, Keycode %d, Key State 0x%08x (modifiers %c%c%c%c)\n",
               ev, ev->xbutton.button, (int) ev->xkey.keycode, ev->xkey.state, SHOW_X_MODS(ev->xkey.state)));
    D_ACTIONS(("Searching %d actions to find match.\n", SPIF_VECTOR_COUNT(actions)));

    for (iter = SPIF_VECTOR_ITERATOR(actions); SPIF_ITERATOR_HAS_NEXT(iter);) {
        action = (spif_eterm_action_t) SPIF_ITERATOR_NEXT(iter);
        if (action_matches_event(action, ev)) {
            D_ACTIONS(("Spawning handler for action object %10p.\n", action));
            return (spif_bool_t) (((spif_eterm_action_handler_t) (action->handler)) (ev, action));
        }
    }
    return FALSE;
}
示例#26
0
文件: str.c 项目: mej/libast
spif_str_t
spif_str_dup(spif_str_t self)
{
    spif_str_t tmp;

    ASSERT_RVAL(!SPIF_STR_ISNULL(self), (spif_str_t) NULL);
    tmp = SPIF_ALLOC(str);
    memcpy(tmp, self, SPIF_SIZEOF_TYPE(str));
    tmp->s = (spif_charptr_t) STRDUP((const char *) SPIF_STR_STR(self));
    tmp->len = self->len;
    tmp->size = self->size;
    return tmp;
}
示例#27
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_append_char(spif_str_t self, spif_char_t c)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    self->len++;
    if (self->size <= self->len) {
        self->size++;
        self->s = (spif_charptr_t) REALLOC(self->s, self->size);
    }
    self->s[self->len - 1] = c;
    self->s[self->len] = 0;
    return TRUE;
}
示例#28
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_prepend_char(spif_str_t self, spif_char_t c)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    self->len++;
    if (self->size <= self->len) {
        self->size++;
        self->s = (spif_charptr_t) REALLOC(self->s, self->size);
    }
    memmove(self->s + 1, self->s, self->len + 1);
    self->s[0] = (spif_uchar_t) c;
    return TRUE;
}
示例#29
0
文件: str.c 项目: mej/libast
spif_stridx_t
spif_str_rindex(spif_str_t self, spif_char_t c)
{
    char *tmp;

    ASSERT_RVAL(!SPIF_STR_ISNULL(self), ((spif_stridx_t) -1));
    tmp = rindex((const char *) SPIF_STR_STR(self), c);
    if (tmp) {
        return (spif_stridx_t) ((spif_long_t) tmp - (spif_long_t) (SPIF_STR_STR(self)));
    } else {
        return (spif_stridx_t) (self->len);
    }
}
示例#30
0
文件: str.c 项目: mej/libast
spif_bool_t
spif_str_append(spif_str_t self, spif_str_t other)
{
    ASSERT_RVAL(!SPIF_STR_ISNULL(self), FALSE);
    REQUIRE_RVAL(!SPIF_STR_ISNULL(other), FALSE);
    if (other->size && other->len) {
        self->size += other->size - 1;
        self->s = (spif_charptr_t) REALLOC(self->s, self->size);
        memcpy(self->s + self->len, SPIF_STR_STR(other), other->len + 1);
        self->len += other->len;
    }
    return TRUE;
}