]> jfr.im git - irc/quakenet/newserv.git/blob - lib/sstring.c
98fbcaeb5b73d7e99985be458a0aaaf52885539e
[irc/quakenet/newserv.git] / lib / sstring.c
1 /* sstring.h - Declaration of "static strings" functions */
2
3 #define COMPILING_SSTRING
4 #include "sstring.h"
5
6 #include "../core/hooks.h"
7 #include "../core/nsmalloc.h"
8 #include "../core/error.h"
9
10 #include <stdio.h>
11
12 #include <assert.h>
13 #include <stdlib.h>
14 #define __USE_GNU
15 #include <string.h>
16
17 #ifndef USE_VALGRIND
18
19 /* List of free stuff */
20 sstring *freelist[SSTRING_MAXLEN+1];
21
22 /* Global variables to track allocated memory */
23 sstring *structmem;
24 char *stringmem;
25 int structfree;
26 int stringfree;
27
28 /* Statistics counters */
29 int getcalls;
30 int freecalls;
31 int allocstruct;
32 int allocstring;
33
34 /* Internal function */
35 void sstringstats(int hooknum, void *arg);
36
37 void initsstring() {
38 int i;
39 for(i=0;i<=SSTRING_MAXLEN;i++)
40 freelist[i]=NULL;
41
42 structfree=0;
43 stringfree=0;
44 structmem=NULL;
45 stringmem=NULL;
46
47 /* Initialise statistics counters */
48 getcalls=0;
49 freecalls=0;
50 allocstruct=0;
51 allocstring=0;
52
53 registerhook(HOOK_CORE_STATSREQUEST,&sstringstats);
54 }
55
56 void finisstring() {
57 nsfreeall(POOL_SSTRING);
58 }
59
60 sstring *getsstring(const char *inputstr, int maxlen) {
61 int i;
62 sstring *retval=NULL;
63 int length;
64
65
66 /* getsstring() on a NULL pointer returns a NULL sstring.. */
67 if (inputstr==NULL) {
68 return NULL;
69 }
70
71 if (inputstr[0]=='\0') {
72 return NULL;
73 }
74
75 /* Only count calls that actually did something */
76 getcalls++;
77
78 length=strlen(inputstr)+1;
79 if (length>maxlen) {
80 length=maxlen+1;
81 }
82 assert(length<=SSTRING_MAXLEN);
83
84 /* Check to see if an approximately correct
85 * sized string is available */
86 for(i=0;i<SSTRING_SLACK;i++) {
87 if (length+i>SSTRING_MAXLEN)
88 break;
89
90 if (freelist[length+i]!=NULL) {
91 retval=freelist[length+i];
92 freelist[length+i]=retval->u.next;
93 retval->u.l.alloc=(length+i);
94 break;
95 }
96 }
97
98 /* None found, allocate a new one */
99 if (retval==NULL) {
100 getstruct:
101 if (structfree < sizeof(sstring)) {
102 /* We always allocate an exact multiple of these.
103 * Therefore, if there is enough for a partial structure we broke something */
104 assert(structfree==0);
105
106 /* Allocate more RAM */
107 allocstruct++;
108 structmem=(sstring *)nsmalloc(POOL_SSTRING,SSTRING_STRUCTALLOC);
109 assert(structmem!=NULL);
110 structfree=SSTRING_STRUCTALLOC;
111 }
112
113 retval=structmem;
114 structmem++;
115 structfree-=sizeof(sstring);
116
117 if (stringfree < length) {
118 /* Not enough left for what we want.
119 * Allocate the remainder of our chunk (if any)
120 * to something and immediately free it.
121 * Decrement the freecalls counter to fix the stats */
122 if (stringfree > 0) {
123 retval->content=stringmem;
124 retval->u.l.alloc=stringfree;
125 stringfree=0;
126 freecalls--;
127 freesstring(retval);
128
129 /* GOTO GOTO GOTO: We need to allocate
130 * another new struct here. Goto is the cleanest
131 * way to do this */
132 goto getstruct;
133 } else {
134 /* Grab some more string space */
135 allocstring++;
136 stringmem=(char *)nsmalloc(POOL_SSTRING,SSTRING_DATAALLOC);
137 assert(stringmem!=NULL);
138 stringfree=SSTRING_DATAALLOC;
139 }
140 }
141
142 retval->content=stringmem;
143 retval->u.l.alloc=length;
144 stringfree-=length;
145 stringmem+=length;
146 }
147
148 /*
149 * At this point, retval points to a valid structure which is at
150 * least the right size and has the "alloc" value set correctly
151 */
152
153 retval->u.l.length=(length-1);
154 strncpy(retval->content,inputstr,(length-1));
155 retval->content[length-1]='\0';
156
157 return retval;
158 }
159
160 void freesstring(sstring *inval) {
161 int alloc;
162
163
164 /* Allow people to call this with a NULL value */
165 if (inval==NULL)
166 return;
167
168 /* Only count calls that actually did something */
169 freecalls++;
170
171 alloc=inval->u.l.alloc;
172 assert(alloc<=SSTRING_MAXLEN);
173 inval->u.next=freelist[alloc];
174 freelist[alloc]=inval;
175 }
176
177 void sstringstats(int hooknum, void *arg) {
178 char buf[512];
179 int i,j;
180 sstring *ssp;
181 long statslev=(long)arg;
182
183 if (statslev>10) {
184 for(i=0,j=0;i<=SSTRING_MAXLEN;i++) {
185 for(ssp=freelist[i];ssp;ssp=ssp->u.next)
186 j++;
187 }
188
189 snprintf(buf,512,"SString : %7d get calls, %7d free calls, %7d struct allocs, %7d string allocs, %7d strings free",getcalls,freecalls,allocstruct,allocstring,j);
190 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
191 }
192 }
193
194 #else /* USE_VALGRIND */
195
196 typedef struct sstringlist {
197 struct sstringlist *prev;
198 struct sstringlist *next;
199 sstring s[];
200 } sstringlist;
201
202 static sstringlist *head;
203
204 void initsstring() {
205 }
206
207 void finisstring() {
208 sstringlist *s, *sn;
209
210 /* here we deliberately don't free the pointers so valgrind can tell us where they were allocated, in theory */
211
212 for(s=head;s;s=sn) {
213 sn = s->next;
214 s->next = NULL;
215 s->prev = NULL;
216
217 Error("sstring", ERR_WARNING, "sstring of length %d still allocated: %s", s->s->u.l.length, s->s->content);
218 }
219
220 head = NULL;
221 }
222
223 sstring *getsstring(const char *inputstr, int maxlen) {
224 size_t len = strlen(inputstr);
225 sstringlist *s;
226
227 s=(sstringlist *)malloc(sizeof(sstringlist) + sizeof(sstring));
228
229 s->s->u.l.length = strlen(inputstr);
230 s->s->content=(char *)malloc(s->s->u.l.length + 1);
231
232 memcpy(s->s->content, inputstr, len);
233 s->s->content[len] = '\0';
234
235 s->next = head;
236 s->prev = NULL;
237 if(head)
238 head->prev = s;
239 head = s;
240
241 return s->s;
242 }
243
244 void freesstring(sstring *inval) {
245 sstringlist *s, *ss, *sp;
246 if(!inval)
247 return;
248
249 s = (sstringlist *)inval - 1;
250
251 if(s->prev) {
252 s->prev->next = s->next;
253 if(s->next)
254 s->next->prev = s->prev;
255 } else {
256 head = s->next;
257 if(head)
258 head->prev = NULL;
259 }
260
261 free(inval->content);
262 free(s);
263 }
264 #endif
265
266 int sstringcompare(sstring *ss1, sstring *ss2) {
267 if (ss1->u.l.length != ss2->u.l.length)
268 return -1;
269
270 return strncmp(ss1->content, ss2->content, ss1->u.l.length);
271 }
272