]>
git.saurik.com Git - redis.git/blob - sds.c
1 /* SDSLib, A C dynamic strings library
3 * Copyright (c) 2006-2009, Salvatore Sanfilippo <antirez at gmail dot com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * * Neither the name of Redis nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without
16 * specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
31 /* TODO: check if it can happen that _len+free > USHRT_MAX */
33 #define SDS_ABORT_ON_OOM
43 static void sdsOomAbort(void) {
44 fprintf(stderr
,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
48 sds
sdsnewlen(const void *init
, size_t initlen
) {
51 if (initlen
>= USHRT_MAX
) {
52 sh
= zmalloc(sizeof(struct sdshdr
)+initlen
+1);
55 #ifdef SDS_ABORT_ON_OOM
56 if (sh
== NULL
) sdsOomAbort();
58 if (sh
== NULL
) return NULL
;
61 sh
= zmalloc(sizeof(int)+initlen
+1);
62 sh
= (struct sdshdr
*) (((char*)sh
)-sizeof(int));
63 #ifdef SDS_ABORT_ON_OOM
64 if (sh
== NULL
) sdsOomAbort();
66 if (sh
== NULL
) return NULL
;
72 if (init
) memcpy(sh
->buf
, init
, initlen
);
73 else memset(sh
->buf
,0,initlen
);
75 sh
->buf
[initlen
] = '\0';
76 return (char*)sh
->buf
;
80 return sdsnewlen("",0);
83 sds
sdsnew(const char *init
) {
84 size_t initlen
= (init
== NULL
) ? 0 : strlen(init
);
85 return sdsnewlen(init
, initlen
);
88 size_t sdslen(const sds s
) {
89 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
90 if (sh
->_len
== USHRT_MAX
)
96 sds
sdsdup(const sds s
) {
97 return sdsnewlen(s
, sdslen(s
));
100 void sdsfree(sds s
) {
103 if (s
== NULL
) return;
104 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
105 if (sh
->_len
== USHRT_MAX
)
106 zfree(s
-sizeof(struct sdshdr
));
108 zfree(s
-sizeof(struct sdshdr
)+sizeof(int));
111 size_t sdsavail(sds s
) {
112 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
116 void sdsupdatelen(sds s
) {
117 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
118 int reallen
= strlen(s
);
120 if (sh
->_len
== USHRT_MAX
) {
121 sh
->free
+= (sh
->len
-reallen
);
124 sh
->free
+= (sh
->_len
-reallen
);
129 static sds
sdsMakeRoomFor(sds s
, size_t addlen
) {
130 struct sdshdr
*sh
, *newsh
;
131 size_t free
= sdsavail(s
);
132 size_t len
, newlen
, newfree
;
134 if (free
>= addlen
) {
135 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
136 if (sh
->_len
== USHRT_MAX
) {
145 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
146 newlen
= (len
+addlen
);
147 newfree
= ((addlen
*2) > USHRT_MAX
) ? USHRT_MAX
: (addlen
*2);
148 if (newlen
+newfree
>= USHRT_MAX
|| sh
->_len
== USHRT_MAX
) {
149 if (sh
->_len
== USHRT_MAX
) {
150 newsh
= zrealloc(sh
, sizeof(struct sdshdr
)+newlen
+1+newfree
);
152 newsh
= zmalloc(sizeof(struct sdshdr
)+newlen
+1+newfree
);
153 if (!newsh
) return NULL
;
154 memcpy(newsh
->buf
,sh
->buf
,len
);
155 newsh
->buf
[len
] = '\0';
156 zfree(((char*)sh
)+sizeof(int));
158 #ifdef SDS_ABORT_ON_OOM
159 if (newsh
== NULL
) sdsOomAbort();
161 if (newsh
== NULL
) return NULL
;
163 newsh
->_len
= USHRT_MAX
;
164 newsh
->free
= newfree
;
167 newsh
= zrealloc(((char*)sh
)+sizeof(int), sizeof(int)+newlen
+1+newfree
);
168 newsh
= (struct sdshdr
*) (((char*)newsh
)-sizeof(int));
169 #ifdef SDS_ABORT_ON_OOM
170 if (newsh
== NULL
) sdsOomAbort();
172 if (newsh
== NULL
) return NULL
;
174 newsh
->_len
= newlen
;
175 newsh
->free
= newfree
;
180 sds
sdscatlen(sds s
, void *t
, size_t len
) {
181 size_t curlen
= sdslen(s
);
183 s
= sdsMakeRoomFor(s
,len
);
184 if (s
== NULL
) return NULL
;
185 memcpy(s
+curlen
, t
, len
);
186 s
[curlen
+len
] = '\0';
190 sds
sdscat(sds s
, char *t
) {
191 return sdscatlen(s
, t
, strlen(t
));
194 sds
sdscpylen(sds s
, char *t
, size_t len
) {
195 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
198 if (sh
->_len
== USHRT_MAX
) {
199 totlen
= sh
->free
+sh
->len
;
201 totlen
= sh
->free
+sh
->_len
;
205 s
= sdsMakeRoomFor(s
,len
-totlen
);
206 if (s
== NULL
) return NULL
;
213 sds
sdscpy(sds s
, char *t
) {
214 return sdscpylen(s
, t
, strlen(t
));
217 sds
sdscatprintf(sds s
, const char *fmt
, ...) {
223 buf
= zmalloc(buflen
);
224 #ifdef SDS_ABORT_ON_OOM
225 if (buf
== NULL
) sdsOomAbort();
227 if (buf
== NULL
) return NULL
;
229 buf
[buflen
-2] = '\0';
231 vsnprintf(buf
, buflen
, fmt
, ap
);
233 if (buf
[buflen
-2] != '\0') {
245 sds
sdstrim(sds s
, const char *cset
) {
246 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
247 char *start
, *end
, *sp
, *ep
;
251 ep
= end
= s
+sdslen(s
)-1;
252 while(sp
<= end
&& strchr(cset
, *sp
)) sp
++;
253 while(ep
> start
&& strchr(cset
, *ep
)) ep
--;
254 len
= (sp
> ep
) ? 0 : ((ep
-sp
)+1);
255 if (sh
->buf
!= sp
) memmove(sh
->buf
, sp
, len
);
257 if (sh
->_len
== USHRT_MAX
) {
258 sh
->free
= sh
->free
+(sh
->len
-len
);
261 sh
->free
= sh
->free
+(sh
->_len
-len
);
267 sds
sdsrange(sds s
, long start
, long end
) {
268 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
269 size_t newlen
, len
= sdslen(s
);
271 if (len
== 0) return s
;
274 if (start
< 0) start
= 0;
278 if (end
< 0) end
= 0;
280 newlen
= (start
> end
) ? 0 : (end
-start
)+1;
282 if (start
>= (signed)len
) start
= len
-1;
283 if (end
>= (signed)len
) end
= len
-1;
284 newlen
= (start
> end
) ? 0 : (end
-start
)+1;
288 if (start
!= 0) memmove(sh
->buf
, sh
->buf
+start
, newlen
);
290 if (sh
->_len
== USHRT_MAX
) {
291 sh
->free
= sh
->free
+(sh
->len
-newlen
);
294 sh
->free
= sh
->free
+(sh
->_len
-newlen
);
300 void sdstolower(sds s
) {
301 int len
= sdslen(s
), j
;
303 for (j
= 0; j
< len
; j
++) s
[j
] = tolower(s
[j
]);
306 void sdstoupper(sds s
) {
307 int len
= sdslen(s
), j
;
309 for (j
= 0; j
< len
; j
++) s
[j
] = toupper(s
[j
]);
312 int sdscmp(sds s1
, sds s2
) {
313 size_t l1
, l2
, minlen
;
318 minlen
= (l1
< l2
) ? l1
: l2
;
319 cmp
= memcmp(s1
,s2
,minlen
);
320 if (cmp
== 0) return l1
-l2
;
324 /* Split 's' with separator in 'sep'. An array
325 * of sds strings is returned. *count will be set
326 * by reference to the number of tokens returned.
328 * On out of memory, zero length string, zero length
329 * separator, NULL is returned.
331 * Note that 'sep' is able to split a string using
332 * a multi-character separator. For example
333 * sdssplit("foo_-_bar","_-_"); will return two
334 * elements "foo" and "bar".
336 * This version of the function is binary-safe but
337 * requires length arguments. sdssplit() is just the
338 * same function but for zero-terminated strings.
340 sds
*sdssplitlen(char *s
, int len
, char *sep
, int seplen
, int *count
) {
341 int elements
= 0, slots
= 5, start
= 0, j
;
343 sds
*tokens
= zmalloc(sizeof(sds
)*slots
);
344 #ifdef SDS_ABORT_ON_OOM
345 if (tokens
== NULL
) sdsOomAbort();
347 if (seplen
< 1 || len
< 0 || tokens
== NULL
) return NULL
;
348 for (j
= 0; j
< (len
-(seplen
-1)); j
++) {
349 /* make sure there is room for the next element and the final one */
350 if (slots
< elements
+2) {
354 newtokens
= zrealloc(tokens
,sizeof(sds
)*slots
);
355 if (newtokens
== NULL
) {
356 #ifdef SDS_ABORT_ON_OOM
364 /* search the separator */
365 if ((seplen
== 1 && *(s
+j
) == sep
[0]) || (memcmp(s
+j
,sep
,seplen
) == 0)) {
366 tokens
[elements
] = sdsnewlen(s
+start
,j
-start
);
367 if (tokens
[elements
] == NULL
) {
368 #ifdef SDS_ABORT_ON_OOM
376 j
= j
+seplen
-1; /* skip the separator */
379 /* Add the final element. We are sure there is room in the tokens array. */
380 tokens
[elements
] = sdsnewlen(s
+start
,len
-start
);
381 if (tokens
[elements
] == NULL
) {
382 #ifdef SDS_ABORT_ON_OOM
392 #ifndef SDS_ABORT_ON_OOM
396 for (i
= 0; i
< elements
; i
++) sdsfree(tokens
[i
]);