Last active
May 27, 2024 16:11
-
-
Save rlapz/5cabf620a6d6551a4050053550e8d46c to your computer and use it in GitHub Desktop.
C String library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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