|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <string.h>
|
|
Packit |
8f70b4 |
#include <mbswidth.h>
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include "c-ctype.h"
|
|
Packit |
8f70b4 |
CDECL_BEGIN
|
|
Packit |
8f70b4 |
#include "memcasecmp.h"
|
|
Packit |
8f70b4 |
CDECL_END
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void xstring::get_space(size_t s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get_space2(s,32);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::get_space2(size_t s,size_t g)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!buf)
|
|
Packit |
8f70b4 |
buf=(char*)xmalloc(size=s+1);
|
|
Packit |
8f70b4 |
else if(size
|
|
Packit |
8f70b4 |
buf=(char*)xrealloc(buf,size=(s|(g-1))+1);
|
|
Packit |
8f70b4 |
buf[s]=0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::shrink_space()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
enum { MIN_SIZE=128 };
|
|
Packit |
8f70b4 |
if(buf && size>MIN_SIZE)
|
|
Packit |
8f70b4 |
buf=(char*)xrealloc(buf,((len+1)|(MIN_SIZE-1))+1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
char *xstring::add_space(size_t s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size<=len+s)
|
|
Packit |
8f70b4 |
get_space(len+s);
|
|
Packit |
8f70b4 |
return get_non_const()+len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void xstring::init(const char *s,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
init();
|
|
Packit |
8f70b4 |
nset(s,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::init(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
init();
|
|
Packit |
8f70b4 |
set(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::nset(const char *s,int len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xfree(buf);
|
|
Packit |
8f70b4 |
init();
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
this->len=len;
|
|
Packit |
8f70b4 |
if(s==buf)
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
if(s>buf && s
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memmove(buf,s,len);
|
|
Packit |
8f70b4 |
get_space(len);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
get_space(len);
|
|
Packit |
8f70b4 |
memcpy(buf,s,len);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::set(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return nset(s,xstrlen(s));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring::xstring(const xstring_clonable& c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
init();
|
|
Packit |
8f70b4 |
if(!c.buf)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
len=c.len;
|
|
Packit |
8f70b4 |
get_space(c.len);
|
|
Packit |
8f70b4 |
memcpy(buf,c.buf,c.len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::set_allocated(char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!s) {
|
|
Packit |
8f70b4 |
unset();
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
len=strlen(s);
|
|
Packit |
8f70b4 |
size=len+1;
|
|
Packit |
8f70b4 |
xfree(buf);
|
|
Packit |
8f70b4 |
buf=s;
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::move_here(xstring& o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!o) {
|
|
Packit |
8f70b4 |
unset();
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
len=o.len; o.len=0;
|
|
Packit |
8f70b4 |
size=o.size; o.size=0;
|
|
Packit |
8f70b4 |
xfree(buf);
|
|
Packit |
8f70b4 |
buf=o.buf; o.buf=0;
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::swap(xstring& o)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
buf=replace_value(o.buf,buf);
|
|
Packit |
8f70b4 |
size=replace_value(o.size,size);
|
|
Packit |
8f70b4 |
len=replace_value(o.len,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::append(const char *s,size_t s_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!s || s_len==0)
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
get_space(len+s_len);
|
|
Packit |
8f70b4 |
memcpy(buf+len,s,s_len);
|
|
Packit |
8f70b4 |
len+=s_len;
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::append(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return append(s,strlen(s));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::append(char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
get_space(len+1);
|
|
Packit |
8f70b4 |
buf[len++]=c;
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::append_padding(int len,char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
memset(add_space(len),c,len);
|
|
Packit |
8f70b4 |
add_commit(len);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool xstring::begins_with(const char *o_buf,size_t o_len) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(buf==o_buf)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(!buf || !o_buf)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(o_len==0)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return !memcmp(buf,o_buf,o_len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool xstring::ends_with(const char *o_buf,size_t o_len) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(buf+len-o_len==o_buf)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(!buf || !o_buf)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(o_len==0)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
return !memcmp(buf+len-o_len,o_buf,o_len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool xstring::eq(const char *o_buf,size_t o_len) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return len==o_len && begins_with(o_buf,o_len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
bool xstring::eq_nc(const char *o_buf,size_t o_len) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(len!=o_len)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
if(buf==o_buf)
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
if(!buf || !o_buf)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return !memcasecmp(buf,o_buf,o_len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int xstring::cmp(const char *o_buf,size_t o_len) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(buf!=o_buf) {
|
|
Packit |
8f70b4 |
if(!buf)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
if(!o_buf)
|
|
Packit |
8f70b4 |
return 1;
|
|
Packit |
8f70b4 |
size_t cmp_len=len;
|
|
Packit |
8f70b4 |
if(cmp_len>o_len)
|
|
Packit |
8f70b4 |
cmp_len=o_len;
|
|
Packit |
8f70b4 |
if(cmp_len>0) {
|
|
Packit |
8f70b4 |
int cmp_res=memcmp(buf,o_buf,cmp_len);
|
|
Packit |
8f70b4 |
if(cmp_res)
|
|
Packit |
8f70b4 |
return cmp_res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(len==o_len)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return len-o_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static size_t vstrlen(va_list va0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
VA_COPY(va,va0);
|
|
Packit |
8f70b4 |
size_t len=0;
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *s=va_arg(va,const char *);
|
|
Packit |
8f70b4 |
if(!s)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
len+=strlen(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static void vstrcpy(char *buf,va_list va0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
VA_COPY(va,va0);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *s=va_arg(va,const char *);
|
|
Packit |
8f70b4 |
if(!s)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
size_t s_len=strlen(s);
|
|
Packit |
8f70b4 |
memcpy(buf,s,s_len);
|
|
Packit |
8f70b4 |
buf+=s_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*buf=0;
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::vappend(va_list va)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size_t va_len=vstrlen(va);
|
|
Packit |
8f70b4 |
get_space(len+va_len);
|
|
Packit |
8f70b4 |
vstrcpy(buf+len,va);
|
|
Packit |
8f70b4 |
len+=va_len;
|
|
Packit |
8f70b4 |
return *this;;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::vappend(...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,this);
|
|
Packit |
8f70b4 |
vappend(va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return *this;;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::vset(...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
truncate(0);
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,this);
|
|
Packit |
8f70b4 |
vappend(va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void xstring::truncate(size_t n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(n
|
|
Packit |
8f70b4 |
set_length(n);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::truncate_at(char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!buf)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
char *p=(char*)memchr(buf,c,len);
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*p=0;
|
|
Packit |
8f70b4 |
len=p-buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::set_substr(int start,size_t sublen,const char *s,size_t s_len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(start+sublen>len)
|
|
Packit |
8f70b4 |
sublen=len-start;
|
|
Packit |
8f70b4 |
if(sublen
|
|
Packit |
8f70b4 |
get_space(len+s_len-sublen);
|
|
Packit |
8f70b4 |
if(sublen!=s_len)
|
|
Packit |
8f70b4 |
memmove(buf+start+s_len,buf+start+sublen,len-(start+sublen)+1);
|
|
Packit |
8f70b4 |
memcpy(buf+start,s,s_len);
|
|
Packit |
8f70b4 |
len+=s_len-sublen;
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::set_substr(int start,size_t sublen,const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return set_substr(start,sublen,s,xstrlen(s));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool xstring::chomp(char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!len || buf[len-1]!=c)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
buf[--len]=0;
|
|
Packit |
8f70b4 |
return true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void xstring::rtrim(char c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(chomp(c));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
unsigned xstring::skip_all(unsigned i,char c) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
while(i
|
|
Packit |
8f70b4 |
i++;
|
|
Packit |
8f70b4 |
return i;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int xstring::instr(char c) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char *pos=(char*)memchr(buf,c,len);
|
|
Packit |
8f70b4 |
if(!pos)
|
|
Packit |
8f70b4 |
return -1;
|
|
Packit |
8f70b4 |
return pos-buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::vappendf(const char *format, va_list ap)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(size-len<32 || size-len>512)
|
|
Packit |
8f70b4 |
get_space(len+strlen(format)+32);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list tmp;
|
|
Packit |
8f70b4 |
VA_COPY(tmp,ap);
|
|
Packit |
8f70b4 |
int res=vsnprintf(buf+len, size-len, format, tmp);
|
|
Packit |
8f70b4 |
va_end(tmp);
|
|
Packit |
8f70b4 |
if(res<0)
|
|
Packit |
8f70b4 |
return *this; // error
|
|
Packit |
8f70b4 |
if((size_t)res
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_length(len+res);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
get_space((size_t)res>size-len ? len+res+1 : len+(size-len)*2);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::setf(const char *format, ...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va, format);
|
|
Packit |
8f70b4 |
vsetf(format, va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::appendf(const char *format, ...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va, format);
|
|
Packit |
8f70b4 |
vappendf(format, va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// don't use it in nested loops
|
|
Packit |
8f70b4 |
xstring& xstring::get_tmp()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
static xstring revolver[16];
|
|
Packit |
8f70b4 |
static int i;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
enum { MAX_REVOLVER_SIZE=0x1000 };
|
|
Packit |
8f70b4 |
if(revolver[i].size>MAX_REVOLVER_SIZE)
|
|
Packit |
8f70b4 |
revolver[i].shrink_space();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int next=(i+1)&1;;
|
|
Packit |
8f70b4 |
xstring& tmp=revolver[i];
|
|
Packit |
8f70b4 |
// keep the oldest tmp clear to trigger NULL dereference
|
|
Packit |
8f70b4 |
tmp.move_here(revolver[next]);
|
|
Packit |
8f70b4 |
i=next;
|
|
Packit |
8f70b4 |
return tmp;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
char *xstring::tmp_buf(int n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring& buf=get_tmp();
|
|
Packit |
8f70b4 |
buf.get_space(n-1); // get_space adds a tail byte again
|
|
Packit |
8f70b4 |
return buf.get_non_const();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::format(const char *fmt, ...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,fmt);
|
|
Packit |
8f70b4 |
xstring& res=vformat(fmt, va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring &xstring::cat(const char *first,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,first);
|
|
Packit |
8f70b4 |
xstring& str=get_tmp(first);
|
|
Packit |
8f70b4 |
str.vappend(va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return str;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring &xstring::join(const char *sep,int n,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,n);
|
|
Packit |
8f70b4 |
xstring& str=get_tmp();
|
|
Packit |
8f70b4 |
str.truncate(0);
|
|
Packit |
8f70b4 |
while(n-->0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *a=va_arg(va,const char*);
|
|
Packit |
8f70b4 |
if(!a || !*a)
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
if(str.length())
|
|
Packit |
8f70b4 |
str.append(sep);
|
|
Packit |
8f70b4 |
str.append(a);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return str;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *xstring_c::vset(...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list va;
|
|
Packit |
8f70b4 |
va_start(va,this);
|
|
Packit |
8f70b4 |
size_t va_len=vstrlen(va);
|
|
Packit |
8f70b4 |
if(!buf || strlen(buf)
|
|
Packit |
8f70b4 |
buf=(char*)xrealloc(buf,va_len+1);
|
|
Packit |
8f70b4 |
vstrcpy(buf,va);
|
|
Packit |
8f70b4 |
va_end(va);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool xstring::is_binary() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
unsigned bin_count=0;
|
|
Packit |
8f70b4 |
for(unsigned i=0; i
|
|
Packit |
8f70b4 |
bin_count+=((unsigned char)buf[i] < 32);
|
|
Packit |
8f70b4 |
return bin_count*32>len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *xstring::hexdump_to(xstring& buf) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=length();
|
|
Packit |
8f70b4 |
const char *s=get();
|
|
Packit |
8f70b4 |
while(len-->0)
|
|
Packit |
8f70b4 |
buf.appendf("%02X",(unsigned char)*s++);
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *xstring::hexdump() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return hexdump_to(get_tmp(""));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *xstring::dump() const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
return dump_to(get_tmp(""));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
const char *xstring::dump_to(xstring& buf) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(is_binary()) {
|
|
Packit |
8f70b4 |
binary:
|
|
Packit |
8f70b4 |
if(len<1024) {
|
|
Packit |
8f70b4 |
buf.append("
|
|
Packit |
8f70b4 |
hexdump_to(buf);
|
|
Packit |
8f70b4 |
buf.append('>');
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
buf.appendf("<long binary, %d bytes>",(int)length());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
int old_buf_len=buf.length();
|
|
Packit |
8f70b4 |
int len=length();
|
|
Packit |
8f70b4 |
const char *s=get();
|
|
Packit |
8f70b4 |
size_t invalid=0;
|
|
Packit |
8f70b4 |
while(len>0) {
|
|
Packit |
8f70b4 |
int ch_len=mblen(s,len);
|
|
Packit |
8f70b4 |
int ch_width=-1;
|
|
Packit |
8f70b4 |
if(ch_len<1) {
|
|
Packit |
8f70b4 |
ch_len=1;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
ch_width=mbsnwidth(s,ch_len,0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(ch_width>=0) {
|
|
Packit |
8f70b4 |
buf.append(s,ch_len);
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
while(ch_len>0) {
|
|
Packit |
8f70b4 |
buf.appendf("\\%03o",(unsigned char)*s++);
|
|
Packit |
8f70b4 |
ch_len--;
|
|
Packit |
8f70b4 |
len--;
|
|
Packit |
8f70b4 |
invalid++;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
s+=ch_len;
|
|
Packit |
8f70b4 |
len-=ch_len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(invalid*32>length()) {
|
|
Packit |
8f70b4 |
buf.truncate(old_buf_len);
|
|
Packit |
8f70b4 |
goto binary;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int xstring0::_url_decode(size_t len,int flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!buf)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
char *store=buf;
|
|
Packit |
8f70b4 |
const char *p=buf;
|
|
Packit |
8f70b4 |
int rest=len;
|
|
Packit |
8f70b4 |
while(rest>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(rest>=3 && *p=='%' && c_isxdigit(p[1]) && c_isxdigit(p[2]))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int n;
|
|
Packit |
8f70b4 |
if(sscanf(p+1,"%2x",&n)==1)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*store++=n;
|
|
Packit |
8f70b4 |
p+=3;
|
|
Packit |
8f70b4 |
rest-=3;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else if(*p=='+' && (flags&URL_DECODE_PLUS))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
*store++=' ';
|
|
Packit |
8f70b4 |
p++;
|
|
Packit |
8f70b4 |
rest--;
|
|
Packit |
8f70b4 |
continue;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
*store++=*p++;
|
|
Packit |
8f70b4 |
rest--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return store-buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
int xstring0::_hex_decode(size_t len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!buf)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
char *store=buf;
|
|
Packit |
8f70b4 |
const char *p=store;
|
|
Packit |
8f70b4 |
int rest=len;
|
|
Packit |
8f70b4 |
while(rest>=2)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int n;
|
|
Packit |
8f70b4 |
if(!c_isxdigit(p[0]) || !c_isxdigit(p[1])
|
|
Packit |
8f70b4 |
|| sscanf(p,"%2x",&n)!=1)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
*store++=n;
|
|
Packit |
8f70b4 |
p+=2;
|
|
Packit |
8f70b4 |
rest-=2;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return store-buf;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::url_decode(int flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_length(_url_decode(length(),flags));
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring_c& xstring_c::url_decode(int flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_length(_url_decode(length(),flags));
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::hex_decode()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
set_length(_hex_decode(length()));
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Encode the unsafe characters in a given string, producing %XX encoded string. */
|
|
Packit |
8f70b4 |
#define need_quote(c) (c_iscntrl((c)) \
|
|
Packit |
8f70b4 |
|| (!(flags&URL_ALLOW_8BIT) && !c_isascii((c))) \
|
|
Packit |
8f70b4 |
|| strchr(unsafe,(c)))
|
|
Packit |
8f70b4 |
xstring& xstring::append_url_encoded(const char *s,int len,const char *unsafe,unsigned flags)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!s)
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
add_space(len+len/4);
|
|
Packit |
8f70b4 |
while(len-->0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
char c=*s++;
|
|
Packit |
8f70b4 |
if (need_quote(c))
|
|
Packit |
8f70b4 |
appendf("%%%02X",(unsigned char)c);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
append(c);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& xstring::c_lc() {
|
|
Packit |
8f70b4 |
char *p=buf;
|
|
Packit |
8f70b4 |
int r=len;
|
|
Packit |
8f70b4 |
while(r>0) {
|
|
Packit |
8f70b4 |
*p=c_tolower(*p);
|
|
Packit |
8f70b4 |
p++,r--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
xstring& xstring::c_ucfirst() {
|
|
Packit |
8f70b4 |
char *p=buf;
|
|
Packit |
8f70b4 |
int r=len;
|
|
Packit |
8f70b4 |
bool first=true;
|
|
Packit |
8f70b4 |
while(r>0) {
|
|
Packit |
8f70b4 |
if(c_isalpha(*p)) {
|
|
Packit |
8f70b4 |
*p=(first?c_toupper(*p):c_tolower(*p));
|
|
Packit |
8f70b4 |
first=false;
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
first=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
p++,r--;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return *this;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const xstring xstring::null;
|
|
Packit |
8f70b4 |
const xstring_c xstring_c::null;
|