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