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