Blame src/xstring.h

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