diff options
Diffstat (limited to 'src/htsstrings.h')
-rwxr-xr-x | src/htsstrings.h | 298 |
1 files changed, 221 insertions, 77 deletions
diff --git a/src/htsstrings.h b/src/htsstrings.h index 14e851f..6dba2b0 100755 --- a/src/htsstrings.h +++ b/src/htsstrings.h @@ -34,105 +34,249 @@ Please visit our Website: http://www.httrack.com /* Author: Xavier Roche */ /* ------------------------------------------------------------ */ -// Strings a bit safer than static buffers +/* Safer Strings ; standalone .h library */ #ifndef HTS_STRINGS_DEFSTATIC #define HTS_STRINGS_DEFSTATIC -typedef struct String { - char* buff; - int len; - int capa; -} String; - -#define STRING_EMPTY {NULL, 0, 0} -#define STRING_BLK_SIZE 256 -#define StringBuff(blk) ((blk).buff) -#define StringLength(blk) ((blk).len) -#define StringCapacity(blk) ((blk).capa) -#define StringRoom(blk, size) do { \ - if ((blk).len + (int)(size) + 1 > (blk).capa) { \ - (blk).capa = ((blk).len + (size) + 1) * 2; \ - (blk).buff = (char*) realloct((blk).buff, (blk).capa); \ - assertf((blk).buff != NULL); \ +/* System definitions. */ +#include <string.h> + +/* GCC extension */ +#ifndef HTS_UNUSED +#ifdef __GNUC__ +#define HTS_UNUSED __attribute__ ((unused)) +#define HTS_STATIC static __attribute__ ((unused)) +#else +#define HTS_UNUSED +#define HTS_STATIC static +#endif +#endif + +/** Forward definitions **/ +#ifndef HTS_DEF_FWSTRUCT_String +#define HTS_DEF_FWSTRUCT_String +typedef struct String String; +#endif +#ifndef HTS_DEF_STRUCT_String +#define HTS_DEF_STRUCT_String +struct String { + char* buffer_; + size_t length_; + size_t capacity_; +}; +#endif + +/** Allocator **/ +#ifndef STRING_REALLOC +#define STRING_REALLOC(BUFF, SIZE) ( (char*) realloc(BUFF, SIZE) ) +#define STRING_FREE(BUFF) free(BUFF) +#endif +#ifndef STRING_ASSERT +#include <assert.h> +#define STRING_ASSERT(EXP) assert(EXP) +#endif + +/** An empty string **/ +#define STRING_EMPTY { (char*) NULL, 0, 0 } + +/** String buffer **/ +#define StringBuff(BLK) ( (const char*) ((BLK).buffer_) ) + +/** String buffer (read/write) **/ +#define StringBuffRW(BLK) ((BLK).buffer_) + +/** String length **/ +#define StringLength(BLK) ((BLK).length_) + +/** String not empty ? **/ +#define StringNotEmpty(BLK) ( StringLength(BLK) > 0 ) + +/** String capacity **/ +#define StringCapacity(BLK) ((BLK).capacity_) + +/** Subcharacter **/ +#define StringSub(BLK, POS) ( StringBuff(BLK)[POS] ) + +/** Subcharacter (read/write) **/ +#define StringSubRW(BLK, POS) ( StringBuffRW(BLK)[POS] ) + +/** Subcharacter (read/write) **/ +#define StringSubRW(BLK, POS) ( StringBuffRW(BLK)[POS] ) + +/** Right subcharacter **/ +#define StringRight(BLK, POS) ( StringBuff(BLK)[StringLength(BLK) - POS] ) + +/** Right subcharacter (read/write) **/ +#define StringRightRW(BLK, POS) ( StringBuffRW(BLK)[StringLength(BLK) - POS] ) + +/** Remove the utter right character from the string. **/ +#define StringPopRight(BLK) do { \ + StringBuffRW(BLK)[--StringLength(BLK)] = '\0'; \ +} while(0) + +/** Ensure the string is large enough **/ +#define StringRoom(BLK, SIZE) do { \ + if ((BLK).length_ + (int)(SIZE) + 1 > (BLK).capacity_) { \ + (BLK).capacity_ = ((BLK).length_ + (SIZE) + 1) * 2; \ + (BLK).buffer_ = (char*) STRING_REALLOC((BLK).buffer_, (BLK).capacity_); \ + STRING_ASSERT((BLK).buffer_ != NULL); \ } \ } while(0) -#define StringBuffN(blk, size) StringBuffN_(&(blk), size) -static char* StringBuffN_(String* blk, int size) { - StringRoom(*blk, (blk->len) + size); - return StringBuff(*blk); +#define StringBuffN(BLK, SIZE) StringBuffN_(&(BLK), SIZE) +HTS_STATIC char* StringBuffN_(String* blk, int size) { + StringRoom(*blk, StringLength(*blk) + size); + return StringBuffRW(*blk); } -#define StringClear(blk) do { \ - StringRoom(blk, 0); \ - (blk).buff[0] = '\0'; \ - (blk).len = 0; \ + +/** Initialize a string. **/ +#define StringInit(BLK) do { \ + (BLK).buffer_ = NULL; \ + (BLK).capacity_ = 0; \ + (BLK).length_ = 0; \ +} while(0) + +/** Clear a string (set its length to 0) **/ +#define StringClear(BLK) do { \ + StringRoom(BLK, 0); \ + (BLK).buffer_[0] = '\0'; \ + (BLK).length_ = 0; \ } while(0) -#define StringFree(blk) do { \ - if ((blk).buff != NULL) { \ - freet((blk).buff); \ - (blk).buff = NULL; \ + +/** Set the length of a string to 'SIZE'. If SIZE is negative, check the size using strlen(). **/ +#define StringSetLength(BLK, SIZE) do { \ + if (SIZE >= 0) { \ + (BLK).length_ = SIZE; \ + } else { \ + (BLK).length_ = strlen((BLK).buffer_); \ } \ - (blk).capa = 0; \ - (blk).len = 0; \ } while(0) -#define StringMemcat(blk, str, size) do { \ - StringRoom(blk, size); \ - if ((int)(size) > 0) { \ - memcpy((blk).buff + (blk).len, (str), (size)); \ - (blk).len += (size); \ + +/** Free a string (release memory) **/ +#define StringFree(BLK) do { \ + if ((BLK).buffer_ != NULL) { \ + STRING_FREE((BLK).buffer_); \ + (BLK).buffer_ = NULL; \ } \ - *((blk).buff + (blk).len) = '\0'; \ + (BLK).capacity_ = 0; \ + (BLK).length_ = 0; \ } while(0) -#define StringAddchar(blk, c) do { \ - char __c = (c); \ - StringMemcat(blk, &__c, 1); \ + +/** Assign an allocated pointer to a a string. +The pointer _MUST_ be compatible with STRING_REALLOC() and STRING_FREE() **/ +#define StringSetBuffer(BLK, STR) do { \ + size_t len__ = strlen( STR ); \ + StringFree(BLK); \ + (BLK).buffer_ = ( STR ); \ + (BLK).capacity_ = len__; \ + (BLK).length_ = len__; \ } while(0) -static void* StringAcquire(String* blk) { - void* buff = blk->buff; - blk->buff = NULL; - blk->capa = 0; - blk->len = 0; - return buff; -} -#define StringStrcat(blk, str) StringMemcat(blk, str, ((str) != NULL) ? (int)strlen(str) : 0) -#define StringStrcpy(blk, str) do { \ - StringClear(blk); \ - StringStrcat(blk, str); \ + +/** Append a memory block to a string **/ +#define StringMemcat(BLK, STR, SIZE) do { \ + StringRoom(BLK, SIZE); \ + if ((int)(SIZE) > 0) { \ + memcpy((BLK).buffer_ + (BLK).length_, (STR), (SIZE)); \ + (BLK).length_ += (int)(SIZE); \ + } \ + *((BLK).buffer_ + (BLK).length_) = '\0'; \ } while(0) -/* Tools */ +/** Copy a memory block to a string **/ +#define StringMemcpy(BLK, STR, SIZE) do { \ + (BLK).length_ = 0; \ + StringMemcat(BLK, STR, SIZE); \ +} while(0) + +/** Add a character **/ +#define StringAddchar(BLK, c) do { \ + String * const s__ = &(BLK); \ + char c__ = (c); \ + StringRoom(*s__, 1); \ + StringBuffRW(*s__)[StringLength(*s__)++] = c__; \ + StringBuffRW(*s__)[StringLength(*s__) ] = 0; \ +} while(0) -static int ehexh(char c) { - if ((c>='0') && (c<='9')) return c-'0'; - if ((c>='a') && (c<='f')) c-=('a'-'A'); - if ((c>='A') && (c<='F')) return (c-'A'+10); - return 0; +/** Acquire a string ; it's the client's responsability to free() it **/ +HTS_STATIC char* StringAcquire(String* blk) { + char* buff = StringBuffRW(*blk); + StringBuffRW(*blk) = NULL; + StringCapacity(*blk) = 0; + StringLength(*blk) = 0; + return buff; } -static int ehex(char* s) { - return 16*ehexh(*s)+ehexh(*(s+1)); +/** Clone a string. **/ +HTS_STATIC String StringDup(const String* src) { + String s = STRING_EMPTY; + StringMemcat(s, StringBuff(*src), StringLength(*src)); + return s; } -static void unescapehttp(char* s, String* tempo) { - int i; - for (i=0;i<(int) strlen(s);i++) { - if (s[i]=='%' && s[i+1]=='%') { - i++; - StringAddchar(*tempo, '%'); - } else if (s[i]=='%') { - char hc; - i++; - hc = (char) ehex(s+i); - StringAddchar(*tempo, (char) hc); - i++; // sauter 2 caractères finalement - } - else if (s[i]=='+') { - StringAddchar(*tempo, ' '); - } - else - StringAddchar(*tempo, s[i]); +/** Attach a string using a pointer. **/ +HTS_STATIC void StringAttach(String* blk, char** str) { + StringFree(*blk); + if (str != NULL && *str != NULL) { + StringBuffRW(*blk) = *str; + StringCapacity(*blk) = StringLength(*blk) = strlen(StringBuff(*blk)); + *str = NULL; } } +/** Append a string to another one. **/ +#define StringCat(BLK, STR) do { \ + const char *str__ = ( STR ); \ + if (str__ != NULL) { \ + size_t size__ = strlen(str__); \ + StringMemcat(BLK, str__, size__); \ + } \ +} while(0) + +#define StringCatN(BLK, STR, SIZE) do { \ + const char *str__ = ( STR ); \ + if (str__ != NULL) { \ + size_t size__ = strlen(str__); \ + if (size__ > (SIZE)) { \ + size__ = (SIZE); \ + } \ + StringMemcat(BLK, str__, size__); \ + } \ +} while(0) + +#define StringCopyN(BLK, STR, SIZE) do { \ + const char *str__ = ( STR ); \ + const size_t usize__ = (SIZE); \ + (BLK).length_ = 0; \ + if (str__ != NULL) { \ + size_t size__ = strlen(str__); \ + if (size__ > usize__ ) { \ + size__ = usize__; \ + } \ + StringMemcat(BLK, str__, size__); \ + } else { \ + StringClear(BLK); \ + } \ +} while(0) + +#define StringCopyS(blk, blk2) StringCopyN(blk, (blk2).buffer_, (blk2).length_) + +/** Copy a string to another one. **/ +#define StringCopy(BLK, STR) do { \ + const char *str__ = ( STR ); \ + if (str__ != NULL) { \ + size_t size__ = strlen(str__); \ + StringMemcpy(BLK, str__, size__); \ + } else { \ + StringClear(BLK); \ + } \ +} while(0) + +/** Copy a (potentially overlapping) string to another one. **/ +#define StringCopyOverlapped(BLK, STR) do { \ + String s__ = STRING_EMPTY; \ + StringCopy(s__, STR); \ + StringCopyS(BLK, s__); \ + StringFree(s__); \ +} while(0) #endif |