]> jfr.im git - irc/quakenet/newserv.git/blob - lib/sstring.c
Lua version now excludes "Lua engine", at least for MODULEVERSION.
[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 /* Allow people to call this with a NULL value */
164 if (inval==NULL)
165 return;
166
167 /* Only count calls that actually did something */
168 freecalls++;
169
170 alloc=inval->u.l.alloc;
171 assert(alloc<=SSTRING_MAXLEN);
172 inval->u.next=freelist[alloc];
173 freelist[alloc]=inval;
174 }
175
176 void sstringstats(int hooknum, void *arg) {
177 char buf[512];
178 int i,j;
179 sstring *ssp;
180 long statslev=(long)arg;
181
182 if (statslev>10) {
183 for(i=0,j=0;i<=SSTRING_MAXLEN;i++) {
184 for(ssp=freelist[i];ssp;ssp=ssp->u.next)
185 j++;
186 }
187
188 snprintf(buf,512,"SString : %7d get calls, %7d free calls, %7d struct allocs, %7d string allocs, %7d strings free",getcalls,freecalls,allocstruct,allocstring,j);
189 triggerhook(HOOK_CORE_STATSREPLY,(void *)buf);
190 }
191 }
192
193 #else /* USE_VALGRIND */
194
195 typedef struct sstringlist {
196 struct sstringlist *prev;
197 struct sstringlist *next;
198 sstring s[];
199 } sstringlist;
200
201 static sstringlist *head;
202
203 void initsstring() {
204 }
205
206 void finisstring() {
207 sstringlist *s, *sn;
208
209 /* here we deliberately don't free the pointers so valgrind can tell us where they were allocated, in theory */
210
211 for(s=head;s;s=sn) {
212 sn = s->next;
213 s->next = NULL;
214 s->prev = NULL;
215
216 Error("sstring", ERR_WARNING, "sstring of length %d still allocated: %s", s->s->u.l.length, s->s->content);
217 }
218
219 head = NULL;
220 }
221
222 sstring *getsstring(const char *inputstr, int maxlen) {
223 sstringlist *s;
224 size_t len;
225 char *p;
226
227 if(!inputstr)
228 return NULL;
229
230 for(p=(char *)inputstr;*p&&maxlen;maxlen--,p++)
231 ; /* empty */
232
233 len = p - inputstr;
234 s=(sstringlist *)malloc(sizeof(sstringlist) + sizeof(sstring));
235
236 s->s->u.l.length = len;
237 s->s->content=(char *)malloc(len + 1);
238
239 memcpy(s->s->content, inputstr, len);
240 s->s->content[len] = '\0';
241
242 s->next = head;
243 s->prev = NULL;
244 if(head)
245 head->prev = s;
246 head = s;
247
248 return s->s;
249 }
250
251 void freesstring(sstring *inval) {
252 sstringlist *s;
253 if(!inval)
254 return;
255
256 s = (sstringlist *)inval - 1;
257
258 if(s->prev) {
259 s->prev->next = s->next;
260 if(s->next)
261 s->next->prev = s->prev;
262 } else {
263 head = s->next;
264 if(head)
265 head->prev = NULL;
266 }
267
268 free(inval->content);
269 free(s);
270 }
271 #endif
272
273 int sstringcompare(sstring *ss1, sstring *ss2) {
274 if (ss1->u.l.length != ss2->u.l.length)
275 return -1;
276
277 return strncmp(ss1->content, ss2->content, ss1->u.l.length);
278 }
279