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