summaryrefslogtreecommitdiff
path: root/src/htsstrings.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/htsstrings.h')
-rwxr-xr-xsrc/htsstrings.h298
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