Skip to content

Instantly share code, notes, and snippets.

@61131
Last active December 27, 2021 08:44
Show Gist options
  • Save 61131/e42049bec1e97cc03ca3bf945e4e0878 to your computer and use it in GitHub Desktop.
Save 61131/e42049bec1e97cc03ca3bf945e4e0878 to your computer and use it in GitHub Desktop.
Fat pointer implementation for dynamic string allocation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include "sstr.h"
static void * __salloc (size_t n);
static void * __srealloc (void *p, size_t n);
static struct __SSTR_NAME(str) * __svalid (char *s);
/*!
\fn static void * __salloc (size_t n)
\brief Allocates memory associated with a sstr string
\param n Number of bytes to allocate
\returns Returns pointer to initialised memory on success, NULL on error
*/
static void * __salloc (size_t n) {
struct __SSTR_NAME(str) *sp;
size_t len;
len = sizeof(struct __SSTR_NAME(str)) + n + 1;
if((sp = realloc(NULL, len)) == NULL) {
return NULL;
}
( void ) memset(sp, 0, len);
sp->realloc = __srealloc;
// sp->free = __SSTR_NAME(free);
sp->magic = __SSTR_MAGIC;
sp->len = n;
return sp;
}
static void * __srealloc (void *p, size_t n) {
struct __SSTR_NAME(str) *r, *sp;
size_t curr, len;
// The following cast should be safe due to the pointer having been validated
// as referencing a valid sstr data structure in the calling code. Code which
// builds upon this library should take care to ensure that this approach is
// maintained.
sp = (struct __SSTR_NAME(str) *) p;
len = sizeof(struct __SSTR_NAME(str)) + n + 1;
curr = __SSTR_NAME(strlen)(sp->buf);
if((r = realloc(sp, len)) != NULL) {
if((r->len = n) < curr) {
r->buf[r->len] = '\0';
}
else {
}
}
return r;
}
/*!
\fn static struct sstr * __svalid (char *s)
\brief Validate string as sstr string
\param s Pointer to string constant
\returns Returns pointer to data structure for sstr string, NULL otherwise
*/
static struct __SSTR_NAME(str) * __svalid (char *s) {
struct __SSTR_NAME(str) *sp;
if(s != NULL) {
sp = container_of(s, struct __SSTR_NAME(str), buf);
if(sp->magic == __SSTR_MAGIC) {
return sp;
}
}
return NULL;
}
/*!
\fn size_t sstrlen (const char *s)
\brief Return length of string
\param s Pointer to string constant
\returns Returns number of bytes in string
The sstrlen() function returns the number of bytes in the string pointed by
s, not including the terminating null byte. If the string is a sstr string,
a maximum value of the allocated memory size associated with this string
shall be returned.
*/
size_t __SSTR_NAME(strlen) (const char *s) {
struct __SSTR_NAME(str) *sp;
size_t i;
if(s == NULL) {
return 0;
}
if((sp = __svalid((char *) s)) != NULL) {
for(i = 0; i < sp->len; ++i) {
if(sp->buf[i] == 0) {
break;
}
}
return i;
}
else {
return strlen(s);
}
}
char * __SSTR_NAME(strcpy) (char *dest, const char *src) {
return __SSTR_NAME(strncpy)(dest, src, __SSTR_NAME(strlen)(src));
}
char * __SSTR_NAME(strncpy) (char *dest, const char *src, size_t n) {
struct __SSTR_NAME(str) *sp;
size_t len;
if((len = __SSTR_NAME(strlen)(src)) > n) {
len = n;
}
if(len > 0) {
if((sp = __svalid(dest)) != NULL) {
if((sp = sp->realloc(sp, len)) == NULL) {
return NULL;
}
}
strncpy(dest, src, n);
}
return dest;
}
char * __SSTR_NAME(strcat) (char *dest, const char *src) {
return __SSTR_NAME(strncat)(dest, src, __SSTR_NAME(strlen)(src));
}
char * __SSTR_NAME(strncat) (char *dest, const char *src, size_t n) {
struct __SSTR_NAME(str) *sp;
size_t len;
if((len = __SSTR_NAME(strlen)(src)) > n) {
len = n;
}
if(len > 0) {
if((sp = __svalid(dest)) != NULL) {
if((sp = sp->realloc(sp, __SSTR_NAME(strlen)(dest) + len + 1)) == NULL) {
return NULL;
}
}
strncat(dest, src, n);
}
return dest;
}
int __SSTR_NAME(strcmp) (const char *s1, const char *s2) {
size_t len1, len2, min;
int r;
len1 = __SSTR_NAME(strlen)(s1);
len2 = __SSTR_NAME(strlen)(s2);
min = (len1 < len2) ? len1 : len2;
if((r = memcmp(s1, s2, min)) == 0) {
return (len1 - len2);
}
return r;
}
int __SSTR_NAME(strncmp) (const char *s1, const char *s2, size_t n) {
size_t len1, len2, min;
int r;
len1 = __SSTR_NAME(strlen)(s1);
len2 = __SSTR_NAME(strlen)(s2);
if((min = (len1 < len2) ? len1 : len2) > n) {
min = n;
}
if((r = memcmp(s1, s2, min)) == 0) {
return (len1 - len2);
}
return r;
}
/*!
\fn char * sstrdup (const char *s)
\brief Duplicate string constant
\param s Pointer to string constant
\returns Returns pointer to sstr string on success, NULL on failure
The sstrdup() function allocates space for a sstr string, creating it as a
duplicate to the string constant s. The returned pointer can be passed to
sstrfree(). A NULL pointer is returned if the sstr string cannot be created.
*/
char * __SSTR_NAME(strdup) (const char *s) {
size_t len;
len = (s == NULL) ? 0 : __SSTR_NAME(strlen)(s);
return __SSTR_NAME(strndup)(s, len);
}
/*!
\fn char * sstrndup (const char *s, size_t n)
\brief Duplicate string constant
\param s Pointer to string constant
\param n Number of bytes of string constant to duplicate
\returns Returns pointer to sstr string on success, NULL on failure
The sstrdup() function allocates space for a sstr string, creating it as a
duplicate for the first n bytes of the string constant s. If s is longer
than n, only n bytes are copied and a terminating null byte ('\0') is added.
The returned pointer can be passed to sstrfree(). A NULL pointer is returned
if the sstr string cannot be created.
*/
char * __SSTR_NAME(strndup) (const char *s, size_t n) {
struct __SSTR_NAME(str) *sp;
char *ss;
if((sp = __salloc(n)) == NULL) {
return NULL;
}
ss = ((char *) sp + offsetof(struct __SSTR_NAME(str), buf));
return __SSTR_NAME(strncat)(ss, s, n);
}
/*!
\fn void sfree (void *p)
\brief Free memory associated with a sstr string
\param p Pointer to sstr string
\returns No return value
The sstrfree() function frees the space associated with the sstr string p, which
should have been returned by a previous call to sstrdup(). If p has not been
returned from such a call and this library has been compiled without debugging
support, no operation is performed. Similarly, if p is NULL, no operation is
performed.
*/
void __SSTR_NAME(free) (void *p) {
struct __SSTR_NAME(str) *sp;
if(p != NULL) {
if((sp = __svalid(p)) != NULL) {
free(sp);
p = NULL;
return;
}
assert(0);
}
}
#ifndef _SSTR_H
#define _SSTR_H 1
#define __need_size_t
#define __need_NULL
#include <stddef.h>
#include <assert.h>
#include <stdint.h>
#ifndef offsetof
#define offsetof(type, member) ((size_t) &((type *)0)->member)
#endif
#ifndef container_of
#define container_of(ptr, type, member) ({ \
(type *)((char *)ptr - offsetof(type, member)); })
#endif
/*
The following represents a horrid abuse of the C preprocessor system but
allows for the prefix associated with all functions implemented within this
library to be changed as necessary to meet local integration requirements.
*/
#define __SSTR_PREFIX s
#define __SSTR_PASTE(x,y) x ## y
#define __SSTR_EVAL(x,y) __SSTR_PASTE(x,y)
#define __SSTR_NAME(x) __SSTR_EVAL( __SSTR_PREFIX, x )
#define __SSTR_MAGIC (0xdeadbeef)
struct __SSTR_NAME(str) { // struct sstr
void *(*realloc)(void *, size_t);
uint32_t magic;
size_t len;
char buf[];
};
extern size_t __SSTR_NAME(strlen) (const char *s);
extern char * __SSTR_NAME(strcpy) (char *dest, const char *src);
extern char * __SSTR_NAME(strncpy) (char *dest, const char *src, size_t n);
extern char * __SSTR_NAME(strcat) (char *dest, const char *src);
extern char * __SSTR_NAME(strncat) (char *dest, const char *src, size_t n);
extern int __SSTR_NAME(strcmp) (const char *s1, const char *s2);
extern int __SSTR_NAME(strncmp) (const char *s1, const char *s2, size_t n);
extern char * __SSTR_NAME(strdup) (const char *s);
extern char * __SSTR_NAME(strndup) (const char *s, size_t n);
extern void __SSTR_NAME(free) (void *p);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment