Skip to content

Instantly share code, notes, and snippets.

@rlapz
Last active May 27, 2024 16:11
Show Gist options
  • Save rlapz/5cabf620a6d6551a4050053550e8d46c to your computer and use it in GitHub Desktop.
Save rlapz/5cabf620a6d6551a4050053550e8d46c to your computer and use it in GitHub Desktop.
C String library
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "str.h"
static int
_str_resize(Str *s, size_t len)
{
const size_t size = s->size;
const size_t remn_size = (size > len)? (size - s->len):0;
if (len < remn_size)
return 0;
if (s->is_alloc == 0) {
errno = ENOMEM;
return -1;
}
const size_t new_size = (len - remn_size) + size + 1;
char *const new_cstr = realloc(s->cstr, new_size);
if (new_cstr == NULL)
return -1;
s->size = new_size;
s->cstr = new_cstr;
return 0;
}
int
str_init(Str *s, char buffer[], size_t size)
{
if (size == 0) {
errno = EINVAL;
return -1;
}
buffer[0] = '\0';
s->len = 0;
s->size = size;
s->cstr = buffer;
s->is_alloc = 0;
return 0;
}
int
str_init_alloc(Str *s, size_t size)
{
size = (size == 0)? 1:size;
char *const cstr = malloc(size);
if (cstr == NULL)
return -1;
cstr[0] = '\0';
s->len = 0;
s->size = size;
s->cstr = cstr;
s->is_alloc = 1;
return 0;
}
void
str_deinit(Str *s)
{
if (s->is_alloc != 0)
free(s->cstr);
}
const char *
str_set(Str *s, const char cstr[])
{
const size_t cstr_len = strlen(cstr);
if (cstr_len == 0) {
s->len = 0;
s->cstr[0] = '\0';
return s->cstr;
}
if (_str_resize(s, cstr_len) < 0)
return NULL;
memcpy(s->cstr, cstr, cstr_len + 1);
s->len = cstr_len;
return s->cstr;
}
const char *
str_set_n(Str *s, const char cstr[], size_t len)
{
if (len == 0) {
s->len = 0;
s->cstr[0] = '\0';
return s->cstr;
}
if (_str_resize(s, len) < 0)
return NULL;
memcpy(s->cstr, cstr, len);
s->len = len;
s->cstr[len] = '\0';
return s->cstr;
}
const char *
str_set_fmt(Str *s, const char fmt[], ...)
{
int ret;
va_list va;
/* determine required size */
va_start(va, fmt);
ret = vsnprintf(NULL, 0, fmt, va);
va_end(va);
if (ret < 0)
return NULL;
const size_t cstr_len = (size_t)ret;
if (cstr_len == 0) {
s->len = 0;
s->cstr[0] = '\0';
return s->cstr;
}
if (_str_resize(s, cstr_len) < 0)
return NULL;
va_start(va, fmt);
ret = vsnprintf(s->cstr, cstr_len + 1, fmt, va);
va_end(va);
if (ret < 0)
return NULL;
s->len = (size_t)ret;
s->cstr[ret] = '\0';
return s->cstr;
}
const char *
str_append(Str *s, const char cstr[])
{
const size_t cstr_len = strlen(cstr);
if (cstr_len == 0)
return s->cstr;
if (_str_resize(s, cstr_len) < 0)
return NULL;
const size_t len = s->len;
memcpy(s->cstr + len, cstr, cstr_len + 1);
s->len = len + cstr_len;
return s->cstr;
}
const char *
str_append_n(Str *s, const char cstr[], size_t len)
{
if (len == 0)
return s->cstr;
if (_str_resize(s, len) < 0)
return NULL;
size_t slen = s->len;
memcpy(s->cstr + slen, cstr, len);
slen += len;
s->len = slen;
s->cstr[slen] = '\0';
return s->cstr;
}
const char *
str_append_fmt(Str *s, const char fmt[], ...)
{
int ret;
va_list va;
/* determine required size */
va_start(va, fmt);
ret = vsnprintf(NULL, 0, fmt, va);
va_end(va);
if (ret < 0)
return NULL;
const size_t cstr_len = (size_t)ret;
if (cstr_len == 0)
return s->cstr;
if (_str_resize(s, cstr_len) < 0)
return NULL;
size_t len = s->len;
va_start(va, fmt);
ret = vsnprintf(s->cstr + len, cstr_len + 1, fmt, va);
va_end(va);
if (ret < 0)
return NULL;
len += (size_t)ret;
s->len = len;
s->cstr[len] = '\0';
return s->cstr;
}
char *
str_dup(Str *s)
{
const size_t len = s->len + 1; /* including '\0' */
char *const ret = malloc(len);
if (ret == NULL)
return NULL;
return (char *)memcpy(ret, s->cstr, len);
}
#ifndef __STR_H__
#define __STR_H__
#include <stddef.h>
typedef struct str {
int is_alloc;
char *cstr;
size_t size;
size_t len;
} Str;
int str_init(Str *s, char buffer[], size_t size);
int str_init_alloc(Str *s, size_t len);
void str_deinit(Str *s);
const char *str_set(Str *s, const char cstr[]);
const char *str_set_n(Str *s, const char cstr[], size_t len);
const char *str_set_fmt(Str *s, const char fmt[], ...);
const char *str_append(Str *s, const char cstr[]);
const char *str_append_n(Str *s, const char cstr[], size_t len);
const char *str_append_fmt(Str *s, const char fmt[], ...);
char *str_dup(Str *s);
#endif
#include <stdio.h>
#include "str.h"
static void
test_static(void)
{
char buffer[4096];
Str str;
if (str_init(&str, buffer, sizeof(buffer)) < 0)
return;
const char *const ret = str_set_fmt(&str, "aaa: %d: %s", 10, "eeeee");
if (ret == NULL)
goto out0;
puts(ret);
out0:
/* optional */
str_deinit(&str);
}
static void
test_dynamic(void)
{
Str str;
if (str_init_alloc(&str, 1) < 0)
return;
const char *const ret = str_set_fmt(&str, "aaa: %d: %s", 10, "eeeee");
if (ret == NULL)
goto out0;
puts(ret);
out0:
str_deinit(&str);
}
int
main(void)
{
puts("test static alloc");
test_static();
puts("test dynamic alloc");
test_dynamic();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment