Skip to content

Instantly share code, notes, and snippets.

@Charles0429
Created July 30, 2014 00:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Charles0429/bed283d6a20900b9789a to your computer and use it in GitHub Desktop.
Save Charles0429/bed283d6a20900b9789a to your computer and use it in GitHub Desktop.
an automatically expandable buffer
#include "cstr.h"
cstr cstr_new_len(const char *str, int len)
{
cstr_internal *ci;
int size;
size = sizeof(cstr_internal) + len + 1;
if(str)
{
ci = (cstr_internal *)malloc(size);
}
else
{
ci = (cstr_internal *)calloc(size, 1);
}
if(ci == NULL)
{
return NULL;
}
ci->free = 0;
ci->len = len;
if(str && len)
{
memcpy(ci->content, str, len);
}
ci->content[len] = '\0';
return ci->content;
}
cstr cstr_new(const char *str)
{
int len;
if(str)
{
len = strlen(str);
}
else
{
len = 0;
}
return cstr_new_len(str, len);
}
int cstr_len(cstr str)
{
cstr_internal *ci;
if(str == NULL)
{
return 0;
}
else
{
ci = get_cstr_internal(str);
return ci->len;
}
}
int cstr_size(cstr str)
{
cstr_internal *ci;
if(str == NULL)
{
return 0;
}
else
{
ci = get_cstr_internal(str);
return ci->len + ci->free + 1;
}
}
int cstr_is_empty(cstr str)
{
cstr_internal *ci;
if(str == NULL)
{
return 1;
}
else
{
ci = get_cstr_internal(str);
return ci->len == 0;
}
}
int cstr_is_full(cstr str)
{
cstr_internal *ci;
assert(str != NULL);
ci = get_cstr_internal(str);
return ci->free == 0;
}
cstr cstr_resize(cstr str, int add_len)
{
int total_len;
int new_len;
cstr_internal *ci;
cstr_internal *tmp;
assert(str != NULL);
ci = get_cstr_internal(str);
total_len = ci->free + ci->len;
new_len = ci->len + add_len;
if(total_len >= new_len)
{
return str;
}
if(new_len < MAX_PREALLOC_SIZE)
{
total_len = new_len * 2;
}
else
{
total_len = new_len + MAX_PREALLOC_SIZE;
}
tmp = (cstr_internal *)realloc(ci, sizeof(cstr_internal) + total_len + 1);
if(tmp == NULL)
{
return NULL;
}
tmp->free = total_len - tmp->len;
return tmp->content;
}
cstr cstr_cat_len(cstr str, const char *t, int len)
{
cstr_internal *ci;
int old_len;
str = cstr_resize(str, len);
if(str == NULL)
{
return NULL;
}
ci = get_cstr_internal(str);
old_len = ci->len;
memcpy(str + old_len, t, len);
ci->len += len;
ci->free -= len;
str[ci->len] = '\0';
return str;
}
cstr cstr_cat(cstr str, const char *t)
{
return cstr_cat_len(str, t, strlen(t));
}
cstr cstr_cpy_len(cstr str, const char *t, int len)
{
cstr_internal *ci;
int total_len;
ci = get_cstr_internal(str);
total_len = ci->free + ci->len;
if(total_len < len)
{
str = cstr_resize(str, len - total_len); /*fix bug:ci->len - total_len*/
if(str == NULL)
{
return NULL;
}
ci = get_cstr_internal(str);
total_len = ci->free + ci->len;
}
memcpy(str, t, len);
ci->len = len;
ci->free = total_len - len;
str[len] = '\0';
return str;
}
cstr cstr_cpy(cstr str, const char *t)
{
return cstr_cpy_len(str, t, strlen(t));
}
cstr cstr_substr(cstr str, int off, int count)
{
cstr_internal *ci;
int len;
ci = get_cstr_internal(str);
len = ci->len;
if(off <0 || off >=len)
{
off = 0;
}
if(count < 0)
{
count = 0;
}
if(off + count >= len)
{
count = len - off;
}
return cstr_new_len(str + off, count);
}
int cstr_cmp(cstr s, cstr t)
{
int len_s = cstr_len(s);
int len_t = cstr_len(t);
int result;
result = strcmp(s, t);
if(result == 0)
{
return len_s - len_t;
}
return result;
}
int cstr_strstr(cstr s, cstr t)
{
char *result;
result = strstr(s, t);
if(result == NULL)
{
return -1;
}
return result - s;
}
cstr *cstr_split(cstr s, const char *t, int *argc)
{
int len_s;
cstr_internal *ci;
int start = 0;
int count = 0;
int i;
cstr *vector = NULL;
cstr tmp;
ci = get_cstr_internal(s);
len_s = ci->len;
*argc = 0;
for(i = 0; i < len_s; i++)
{
if(strchr(t, s[i]) == NULL)
{
break;
}
}
start = i;
for( ; i < len_s; i++)
{
if(strchr(t, s[i]) == NULL)
{
count++;
continue;
}
*argc += 1;
if(*argc == 1)
{
vector = (cstr *)malloc(sizeof(char *));
}
else
{
vector = (cstr *)realloc(vector, sizeof(char *) * (*argc));
}
tmp = cstr_substr(s, start, count);
vector[*argc - 1] = tmp;
while( i < len_s && strchr(t, s[i])) /*fix bug: Conditional jump or move depends on uninitialised value*/
{
i++;
}
start = i;
i = i - 1;
count = 0;
}
if(count > 0)
{
*argc += 1;
vector = (cstr *)realloc(vector, sizeof(char *) * (*argc));
tmp = cstr_substr(s, start, count);
vector[*argc - 1] = tmp;
}
return vector;
}
void cstr_free(cstr s)
{
cstr_internal *ci;
ci = get_cstr_internal(s);
free(ci);
}
#ifndef _CSTR_H
#define _CSTR_H
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef char *cstr;
typedef struct cstr_internal
{
int free;
int len;
char content[];
}cstr_internal;
#define MAX_PREALLOC_SIZE 1024
#define get_cstr_internal(p) (cstr_internal *)((p) - sizeof(cstr_internal))
cstr cstr_new_len(const char *str, int len);
cstr cstr_new(const char *str);
int cstr_len(cstr str);
int cstr_size(cstr str);
int cstr_is_empty(cstr str);
int cstr_is_full(cstr str);
cstr cstr_resize(cstr str, int add_len);
cstr cstr_cat_len(cstr str, const char *t, int len);
cstr cstr_cat(cstr str, const char *t);
cstr cstr_cpy_len(cstr str, const char *t, int len);
cstr cstr_cpy(cstr str, const char *t);
cstr cstr_substr(cstr str, int off, int count);
int cstr_cmp(cstr s, cstr t);
int cstr_strstr(cstr s, cstr t);
cstr *cstr_split(cstr s, const char *t, int *argc);
void cstr_free(cstr s);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment