1    	/* A really basic expanding/appendable string type */
2    	
3    	#include <stdlib.h>
4    	#include <sys/time.h>
5    	#include <sys/stat.h>
6    	#include <time.h>
7    	#include <assert.h>
8    	#include <stdio.h>
9    	#include <limits.h>
10   	#include <string.h>
11   	#include <getopt.h>
12   	#include <errno.h>
13   	#include "cstring.h"
14   	
15   	#define INITIAL_SIZE 1024
16   	#define INCREMENT    1024
17   	#define CHECKER_WORD 0xbcd6712a
18   	
19   	struct cstring_header
20   	{
21   		size_t checker;
22   		size_t allocated;
23   		size_t used;
24   		char the_string[];
25   	};
26   	
27   	cstring_t cstring_alloc(void)
28   	{
29   		char *cstring = malloc(INITIAL_SIZE);
30   		if (cstring) {
31   			struct cstring_header *h = (struct cstring_header *)cstring;
32   			h->checker = CHECKER_WORD;
33   			h->allocated = INITIAL_SIZE;
34   			h->used = 0;
35   			h->the_string[0] = '\0';
36   			return cstring;
37   		} else {
38   			return NULL;
39   		}
40   	}
41   	
42   	char *cstring_to_chars(cstring_t cstring)
43   	{
44   		struct cstring_header *h = (struct cstring_header *)cstring;
45   	
(1) Event cond_false: Condition "!h", taking false branch.
46   		if (!h) {
47   			return NULL;
(2) Event if_end: End of if statement.
48   		}
49   	
(3) Event cond_true: Condition "h->checker == 3168170282U", taking true branch.
(4) Event if_fallthrough: Falling through to end of if statement.
(5) Event if_end: End of if statement.
50   		assert(h->checker == CHECKER_WORD);
(6) Event alloc_fn: Storage is returned from allocation function "strdup".
(7) Event return_alloc_fn: Directly returning storage allocated by "strdup".
51   		return strdup(h->the_string);
52   	}
53   	
54   	size_t cstring_len(cstring_t cstring)
55   	{
56   		struct cstring_header *h = (struct cstring_header *)cstring;
57   	
58   		if (!h) {
59   			return 0;
60   		}
61   	
62   		assert(h->checker == CHECKER_WORD);
63   		return h->used;
64   	}
65   	
66   	
67   	cstring_t cstring_append_chars(cstring_t cstring, const char *newstring)
68   	{
69   		struct cstring_header *h = (struct cstring_header *)cstring;
70   		size_t newlen;
71   	
72   		if (!h) {
73   			return NULL;
74   		}
75   	
76   		assert(h->checker == CHECKER_WORD);
77   		if (!newstring) {
78   			return NULL;
79   		}
80   	
81   		newlen = h->used + strlen(newstring)+1 + sizeof(struct cstring_header);
82   		if (newlen > h->allocated) {
83   			size_t new_allocsize = (newlen + 2048) & 0xFFFFFC00;
84   			char *tmp = realloc(cstring, new_allocsize);
85   			if (!tmp) {
86   				return cstring;
87   			}
88   	
89   			cstring = tmp;
90   			h = (struct cstring_header *)cstring;
91   			h->allocated = new_allocsize;
92   		}
93   		strncat(h->the_string, newstring, h->allocated - h->used -1);
94   		h->used += strlen(newstring);
95   		return cstring;
96   	}
97   	
98   	cstring_t cstring_append_cstring(cstring_t cstring, cstring_t newstring)
99   	{
100  		/* Just check the newstring - cstring_append_chars() will check the target */
101  		struct cstring_header *h = (struct cstring_header *)newstring;
102  	
103  		if (!h) {
104  			return NULL;
105  		}
106  	
107  		assert(h->checker == CHECKER_WORD);
108  		return cstring_append_chars(cstring, h->the_string);
109  	}
110  	
111  	cstring_t cstring_from_chars(const char* chars)
112  	{
113  		cstring_t new_string = cstring_alloc();
114  		if (!new_string) {
115  			return NULL;
116  		}
117  		return cstring_append_chars(new_string, chars);
118  	}
119  	
120  	void cstring_free(cstring_t cstring)
121  	{
122  		struct cstring_header *h = (struct cstring_header *)cstring;
123  	
124  		if (!h) {
125  			return;
126  		}
127  		assert(h->checker == CHECKER_WORD);
128  		free(cstring);
129  	}
130  	
131  	
132