|
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 |
#ifndef XSTRING_H
|
|
Packit |
8f70b4 |
#define XSTRING_H
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Declare string and memory handling routines. Take care that an ANSI
|
|
Packit |
8f70b4 |
string.h and pre-ANSI memory.h might conflict, and that memory.h and
|
|
Packit |
8f70b4 |
strings.h conflict on some systems. */
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if STDC_HEADERS || HAVE_STRING_H
|
|
Packit |
8f70b4 |
# include <string.h>
|
|
Packit |
8f70b4 |
# if !STDC_HEADERS && HAVE_MEMORY_H
|
|
Packit |
8f70b4 |
# include <memory.h>
|
|
Packit |
8f70b4 |
# endif
|
|
Packit |
8f70b4 |
#else
|
|
Packit |
8f70b4 |
# include <strings.h>
|
|
Packit |
8f70b4 |
# ifndef strchr
|
|
Packit |
8f70b4 |
# define strchr index
|
|
Packit |
8f70b4 |
# endif
|
|
Packit |
8f70b4 |
# ifndef strrchr
|
|
Packit |
8f70b4 |
# define strrchr rindex
|
|
Packit |
8f70b4 |
# endif
|
|
Packit |
8f70b4 |
# ifndef memcpy
|
|
Packit |
8f70b4 |
# define memcpy(Dst, Src, Num) bcopy (Src, Dst, Num)
|
|
Packit |
8f70b4 |
# endif
|
|
Packit |
8f70b4 |
# ifndef memcmp
|
|
Packit |
8f70b4 |
# define memcmp(Src1, Src2, Num) bcmp (Src1, Src2, Num)
|
|
Packit |
8f70b4 |
# endif
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <stdarg.h>
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define string_alloca(len) ((char*)alloca((len)))
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if !HAVE_DECL_STRCASECMP
|
|
Packit |
8f70b4 |
CDECL int strcasecmp(const char *s1,const char *s2);
|
|
Packit |
8f70b4 |
CDECL int strncasecmp(const char *s1,const char *s2,size_t n);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#if !HAVE_DECL_VSNPRINTF
|
|
Packit |
8f70b4 |
CDECL int vsnprintf(char *,size_t,const char *,va_list);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#if !HAVE_DECL_SNPRINTF
|
|
Packit |
8f70b4 |
CDECL int snprintf(char *,size_t,const char *,...);
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static inline int xstrcmp(const char *s1,const char *s2)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s1==s2)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(s1==0 || s2==0)
|
|
Packit |
8f70b4 |
return 1;
|
|
Packit |
8f70b4 |
return strcmp(s1,s2);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static inline int xstrncmp(const char *s1,const char *s2,size_t len)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s1==s2 || len==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(s1==0 || s2==0)
|
|
Packit |
8f70b4 |
return 1;
|
|
Packit |
8f70b4 |
return strncmp(s1,s2,len);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static inline int xstrcasecmp(const char *s1,const char *s2)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s1==s2)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
if(s1==0 || s2==0)
|
|
Packit |
8f70b4 |
return 1;
|
|
Packit |
8f70b4 |
return strcasecmp(s1,s2);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
static inline size_t xstrlen(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(s==0)
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return strlen(s);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <stdarg.h>
|
|
Packit |
8f70b4 |
#include "xmalloc.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* this is a small and fast dynamic string class */
|
|
Packit |
8f70b4 |
/* mostly used as xstrdup/xfree replacement */
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
enum { URL_DECODE_PLUS=1, URL_ALLOW_8BIT=2 };
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class xstring0 // base class
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
protected:
|
|
Packit |
8f70b4 |
char *buf;
|
|
Packit |
8f70b4 |
xstring0() {}
|
|
Packit |
8f70b4 |
xstring0(const xstring0&); // disable cloning
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int _url_decode(size_t len,int flags);
|
|
Packit |
8f70b4 |
int _hex_decode(size_t len);
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
~xstring0() { xfree(buf); }
|
|
Packit |
8f70b4 |
operator const char *() const { return buf; }
|
|
Packit |
8f70b4 |
const char *get() const { return buf; }
|
|
Packit |
8f70b4 |
char *get_non_const() { return buf; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void _clear() { buf=0; }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// compact variant
|
|
Packit |
8f70b4 |
class xstring_c : public xstring0
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// make xstring_c = xstrdup() fail:
|
|
Packit |
8f70b4 |
xstring_c& operator=(char *);
|
|
Packit |
8f70b4 |
const char *operator=(const char *s);
|
|
Packit |
8f70b4 |
const char *operator=(const xstring_c& s);
|
|
Packit |
8f70b4 |
xstring_c(const xstring_c&); // disable cloning
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xstring_c() { buf=0; }
|
|
Packit |
8f70b4 |
xstring_c(const char *s) { _set(s); }
|
|
Packit |
8f70b4 |
const char *set(const char *s) { return xstrset(buf,s); }
|
|
Packit |
8f70b4 |
const char *nset(const char *s,int n) { return xstrset(buf,s,n); }
|
|
Packit |
8f70b4 |
const char *set_allocated(char *s) { xfree(buf); return buf=s; }
|
|
Packit |
8f70b4 |
template<class STR> const char *move_here(STR& s) { return set_allocated(s.borrow()); }
|
|
Packit |
8f70b4 |
const char *vset(...) ATTRIBUTE_SENTINEL;
|
|
Packit |
8f70b4 |
void truncate(size_t n=0) { if(buf) buf[n]=0; }
|
|
Packit |
8f70b4 |
char *borrow() { return replace_value(buf,(char*)0); }
|
|
Packit |
8f70b4 |
bool begins_with(const char *s) const { return !strncmp(buf,s,strlen(s)); };
|
|
Packit |
8f70b4 |
bool prefixes(const char *s) const { return !strncmp(buf,s,length()); };
|
|
Packit |
8f70b4 |
bool eq(const char *s) const { return !xstrcmp(buf,s); }
|
|
Packit |
8f70b4 |
bool ne(const char *s) const { return !eq(s); }
|
|
Packit |
8f70b4 |
bool eq_nc(const char *s) const { return !xstrcasecmp(buf,s); }
|
|
Packit |
8f70b4 |
size_t length() const { return xstrlen(buf); }
|
|
Packit |
8f70b4 |
void set_length(size_t n) { if(buf) buf[n]=0; }
|
|
Packit |
8f70b4 |
char last_char() const { size_t len=length(); return len>0?buf[len-1]:0; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void unset() { xfree(buf); buf=0; }
|
|
Packit |
8f70b4 |
void _set(const char *s) { buf=xstrdup(s); }
|
|
Packit |
8f70b4 |
char **buf_ptr() { unset(); return &buf; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring_c& url_decode(int flags=0);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static const xstring_c null;
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class xstring_ca : public xstring_c
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring_ca& operator=(const xstring_ca& s); // disable assigning
|
|
Packit |
8f70b4 |
xstring_ca(const xstring_ca&); // disable cloning
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xstring_ca(char *s) { buf=s; }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
class xstring_clonable;
|
|
Packit |
8f70b4 |
// full implementation
|
|
Packit |
8f70b4 |
class xstring : public xstring0
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
size_t size;
|
|
Packit |
8f70b4 |
size_t len;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void init() { buf=0; size=len=0; }
|
|
Packit |
8f70b4 |
void init(const char *s,int l);
|
|
Packit |
8f70b4 |
void init(const char *s);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// make xstring = xstrdup() fail:
|
|
Packit |
8f70b4 |
xstring& operator=(char *);
|
|
Packit |
8f70b4 |
const char *operator=(const char *s) { return set(s); }
|
|
Packit |
8f70b4 |
const char *operator=(const xstring& s) { return set(s); }
|
|
Packit |
8f70b4 |
xstring(const xstring&); // disable cloning
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
public:
|
|
Packit |
8f70b4 |
xstring() { init(); }
|
|
Packit |
8f70b4 |
xstring(const char *s) { init(s); }
|
|
Packit |
8f70b4 |
xstring(const char *s,int l) { init(s,l); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// explicit cloning
|
|
Packit |
8f70b4 |
xstring(const xstring_clonable& c);
|
|
Packit |
8f70b4 |
const xstring_clonable& copy() const { return *(xstring_clonable*)(this); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void get_space(size_t s);
|
|
Packit |
8f70b4 |
void get_space2(size_t s,size_t g);
|
|
Packit |
8f70b4 |
void shrink_space();
|
|
Packit |
8f70b4 |
char *add_space(size_t s);
|
|
Packit |
8f70b4 |
void add_commit(int new_len) { len+=new_len; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
size_t length() const { return len; }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& set(const xstring &s) { return nset(s,s.length()); }
|
|
Packit |
8f70b4 |
xstring& set(const char *s);
|
|
Packit |
8f70b4 |
xstring& nset(const char *s,int len);
|
|
Packit |
8f70b4 |
xstring& set_allocated(char *s);
|
|
Packit |
8f70b4 |
xstring& move_here(xstring&);
|
|
Packit |
8f70b4 |
xstring& move_here(xstring_c& s) { return set_allocated(s.borrow()); }
|
|
Packit |
8f70b4 |
void swap(xstring& o);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& set_substr(int start,size_t sublen,const char *,size_t);
|
|
Packit |
8f70b4 |
xstring& set_substr(int start,size_t sublen,const char *);
|
|
Packit |
8f70b4 |
xstring& set_substr(int start,size_t sublen,const xstring &s) { return set_substr(start,sublen,s.get(),s.length()); }
|
|
Packit |
8f70b4 |
xstring& prepend(const char *s,size_t len) { return set_substr(0,0,s,len); }
|
|
Packit |
8f70b4 |
xstring& prepend(const xstring &s) { return prepend(s.get(),s.length()); }
|
|
Packit |
8f70b4 |
xstring& prepend(char c) { return prepend(&c,1); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& append(const char *s);
|
|
Packit |
8f70b4 |
xstring& append(char c);
|
|
Packit |
8f70b4 |
xstring& append(const char *s,size_t len);
|
|
Packit |
8f70b4 |
xstring& append(const xstring &s) { return append(s.get(),s.length()); }
|
|
Packit |
8f70b4 |
xstring& append_padding(int len,char ch);
|
|
Packit |
8f70b4 |
xstring& vappend(va_list);
|
|
Packit |
8f70b4 |
xstring& vappend(...) ATTRIBUTE_SENTINEL;
|
|
Packit |
8f70b4 |
xstring& vset(...) ATTRIBUTE_SENTINEL;
|
|
Packit |
8f70b4 |
xstring& vsetf(const char *fmt, va_list ap) { truncate(0); return vappendf(fmt,ap); }
|
|
Packit |
8f70b4 |
xstring& setf(const char *fmt,...) PRINTF_LIKE(2,3);
|
|
Packit |
8f70b4 |
xstring& vappendf(const char *fmt, va_list ap);
|
|
Packit |
8f70b4 |
xstring& appendf(const char *fmt,...) PRINTF_LIKE(2,3);
|
|
Packit |
8f70b4 |
static xstring& get_tmp();
|
|
Packit |
8f70b4 |
static xstring& get_tmp(const char *s) { return get_tmp().set(s); }
|
|
Packit |
8f70b4 |
static xstring& get_tmp(const char *s,int n) { return get_tmp().nset(s,n); }
|
|
Packit |
8f70b4 |
static char *tmp_buf(int n);
|
|
Packit |
8f70b4 |
static xstring& vformat(const char *fmt,va_list ap) { return get_tmp().vsetf(fmt,ap); }
|
|
Packit |
8f70b4 |
static xstring& format(const char *fmt,...) PRINTF_LIKE(1,2);
|
|
Packit |
8f70b4 |
static xstring& cat(const char *first,...) ATTRIBUTE_SENTINEL;
|
|
Packit |
8f70b4 |
static xstring& join(const char *sep,int n,...);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void truncate() { set_length(0); }
|
|
Packit |
8f70b4 |
void truncate(size_t n);
|
|
Packit |
8f70b4 |
void truncate_at(char c);
|
|
Packit |
8f70b4 |
/* set_length can be used to extend the string, e.g. after modification
|
|
Packit |
8f70b4 |
with get_space+get_non_const. */
|
|
Packit |
8f70b4 |
void set_length(size_t n) { if(buf) buf[len=n]=0; }
|
|
Packit |
8f70b4 |
void set_length_no_z(size_t n) { len=n; }
|
|
Packit |
8f70b4 |
char *borrow() { size=len=0; return replace_value(buf,(char*)0); }
|
|
Packit |
8f70b4 |
bool begins_with(const char *o_buf,size_t o_len) const;
|
|
Packit |
8f70b4 |
bool begins_with(const char *s) const { return begins_with(s,strlen(s)); };
|
|
Packit |
8f70b4 |
bool ends_with(const char *o_buf,size_t o_len) const;
|
|
Packit |
8f70b4 |
bool ends_with(const char *s) const { return ends_with(s,strlen(s)); };
|
|
Packit |
8f70b4 |
bool prefixes(const char *s) const { return !strncmp(buf,s,length()); };
|
|
Packit |
8f70b4 |
bool eq(const char *o_buf,size_t o_len) const;
|
|
Packit |
8f70b4 |
bool eq(const char *s) const { return eq(s,strlen(s)); }
|
|
Packit |
8f70b4 |
bool eq(const xstring&o) const { return eq(o.get(),o.length()); }
|
|
Packit |
8f70b4 |
bool ne(const xstring&o) const { return !eq(o); }
|
|
Packit |
8f70b4 |
int cmp(const char *o_buf,size_t o_len) const;
|
|
Packit |
8f70b4 |
int cmp(const xstring&o) const { return cmp(o.get(),o.length()); }
|
|
Packit |
8f70b4 |
bool eq_nc(const char *o_buf,size_t o_len) const;
|
|
Packit |
8f70b4 |
bool eq_nc(const char *s) const { return eq_nc(s,strlen(s)); }
|
|
Packit |
8f70b4 |
bool eq_nc(const xstring&o) const { return eq_nc(o.get(),o.length()); }
|
|
Packit |
8f70b4 |
bool chomp(char c='\n');
|
|
Packit |
8f70b4 |
void rtrim(char c=' ');
|
|
Packit |
8f70b4 |
char last_char() const { return len>0?buf[len-1]:0; }
|
|
Packit |
8f70b4 |
unsigned skip_all(unsigned i,char c) const;
|
|
Packit |
8f70b4 |
int instr(char c) const;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void _clear() { init(); }
|
|
Packit |
8f70b4 |
void _set(const char *s) { init(s); }
|
|
Packit |
8f70b4 |
void unset() { xfree(buf); _clear(); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool is_binary() const;
|
|
Packit |
8f70b4 |
const char *dump_to(xstring &out) const;
|
|
Packit |
8f70b4 |
const char *dump() const;
|
|
Packit |
8f70b4 |
const char *hexdump_to(xstring &out) const;
|
|
Packit |
8f70b4 |
const char *hexdump() const;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& url_decode(int flags=0);
|
|
Packit |
8f70b4 |
xstring& append_url_encoded(const char *s,int len,const char *unsafe,unsigned flags=0);
|
|
Packit |
8f70b4 |
xstring& append_url_encoded(const char *s,const char *unsafe,unsigned flags=0) { return append_url_encoded(s,strlen(s),unsafe,flags); }
|
|
Packit |
8f70b4 |
xstring& append_url_encoded(const xstring& s,const char *unsafe,unsigned flags=0) { return append_url_encoded(s,s.length(),unsafe,flags); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& append_quoted(const char *s,int len);
|
|
Packit |
8f70b4 |
xstring& append_quoted(const char *s) { return append_quoted(s,strlen(s)); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& hex_decode();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring& c_lc();
|
|
Packit |
8f70b4 |
xstring& c_ucfirst();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static const xstring null;
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
class xstring_clonable : public xstring {};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
static inline size_t strlen(const xstring& s) { return s.length(); }
|
|
Packit |
8f70b4 |
static inline size_t xstrlen(const xstring& s) { return s.length(); }
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#endif//XSTRING_H
|