]>
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.
39 static void sdsOomAbort(void) {
40 fprintf(stderr
,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
44 sds
sdsnewlen(const void *init
, size_t initlen
) {
47 sh
= zmalloc(sizeof(struct sdshdr
)+initlen
+1);
48 #ifdef SDS_ABORT_ON_OOM
49 if (sh
== NULL
) sdsOomAbort();
51 if (sh
== NULL
) return NULL
;
56 if (init
) memcpy(sh
->buf
, init
, initlen
);
57 else memset(sh
->buf
,0,initlen
);
59 sh
->buf
[initlen
] = '\0';
60 return (char*)sh
->buf
;
64 return sdsnewlen("",0);
67 sds
sdsnew(const char *init
) {
68 size_t initlen
= (init
== NULL
) ? 0 : strlen(init
);
69 return sdsnewlen(init
, initlen
);
72 size_t sdslen(const sds s
) {
73 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
77 sds
sdsdup(const sds s
) {
78 return sdsnewlen(s
, sdslen(s
));
82 if (s
== NULL
) return;
83 zfree(s
-sizeof(struct sdshdr
));
86 size_t sdsavail(sds s
) {
87 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
91 void sdsupdatelen(sds s
) {
92 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
93 int reallen
= strlen(s
);
94 sh
->free
+= (sh
->len
-reallen
);
98 static sds
sdsMakeRoomFor(sds s
, size_t addlen
) {
99 struct sdshdr
*sh
, *newsh
;
100 size_t free
= sdsavail(s
);
103 if (free
>= addlen
) return s
;
105 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
106 newlen
= (len
+addlen
)*2;
107 newsh
= zrealloc(sh
, sizeof(struct sdshdr
)+newlen
+1);
108 #ifdef SDS_ABORT_ON_OOM
109 if (newsh
== NULL
) sdsOomAbort();
111 if (newsh
== NULL
) return NULL
;
114 newsh
->free
= newlen
- len
;
118 sds
sdscatlen(sds s
, void *t
, size_t len
) {
120 size_t curlen
= sdslen(s
);
122 s
= sdsMakeRoomFor(s
,len
);
123 if (s
== NULL
) return NULL
;
124 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
125 memcpy(s
+curlen
, t
, len
);
126 sh
->len
= curlen
+len
;
127 sh
->free
= sh
->free
-len
;
128 s
[curlen
+len
] = '\0';
132 sds
sdscat(sds s
, char *t
) {
133 return sdscatlen(s
, t
, strlen(t
));
136 sds
sdscpylen(sds s
, char *t
, size_t len
) {
137 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
138 size_t totlen
= sh
->free
+sh
->len
;
141 s
= sdsMakeRoomFor(s
,len
-totlen
);
142 if (s
== NULL
) return NULL
;
143 sh
= (void*) (s
-(sizeof(struct sdshdr
)));
144 totlen
= sh
->free
+sh
->len
;
149 sh
->free
= totlen
-len
;
153 sds
sdscpy(sds s
, char *t
) {
154 return sdscpylen(s
, t
, strlen(t
));
157 sds
sdscatprintf(sds s
, const char *fmt
, ...) {
163 buf
= zmalloc(buflen
);
164 #ifdef SDS_ABORT_ON_OOM
165 if (buf
== NULL
) sdsOomAbort();
167 if (buf
== NULL
) return NULL
;
169 buf
[buflen
-2] = '\0';
171 vsnprintf(buf
, buflen
, fmt
, ap
);
173 if (buf
[buflen
-2] != '\0') {
185 sds
sdstrim(sds s
, const char *cset
) {
186 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
187 char *start
, *end
, *sp
, *ep
;
191 ep
= end
= s
+sdslen(s
)-1;
192 while(sp
<= end
&& strchr(cset
, *sp
)) sp
++;
193 while(ep
> start
&& strchr(cset
, *ep
)) ep
--;
194 len
= (sp
> ep
) ? 0 : ((ep
-sp
)+1);
195 if (sh
->buf
!= sp
) memmove(sh
->buf
, sp
, len
);
197 sh
->free
= sh
->free
+(sh
->len
-len
);
202 sds
sdsrange(sds s
, long start
, long end
) {
203 struct sdshdr
*sh
= (void*) (s
-(sizeof(struct sdshdr
)));
204 size_t newlen
, len
= sdslen(s
);
206 if (len
== 0) return s
;
209 if (start
< 0) start
= 0;
213 if (end
< 0) end
= 0;
215 newlen
= (start
> end
) ? 0 : (end
-start
)+1;
217 if (start
>= (signed)len
) start
= len
-1;
218 if (end
>= (signed)len
) end
= len
-1;
219 newlen
= (start
> end
) ? 0 : (end
-start
)+1;
223 if (start
!= 0) memmove(sh
->buf
, sh
->buf
+start
, newlen
);
225 sh
->free
= sh
->free
+(sh
->len
-newlen
);
230 void sdstolower(sds s
) {
231 int len
= sdslen(s
), j
;
233 for (j
= 0; j
< len
; j
++) s
[j
] = tolower(s
[j
]);
236 void sdstoupper(sds s
) {
237 int len
= sdslen(s
), j
;
239 for (j
= 0; j
< len
; j
++) s
[j
] = toupper(s
[j
]);
242 int sdscmp(sds s1
, sds s2
) {
243 size_t l1
, l2
, minlen
;
248 minlen
= (l1
< l2
) ? l1
: l2
;
249 cmp
= memcmp(s1
,s2
,minlen
);
250 if (cmp
== 0) return l1
-l2
;
254 /* Split 's' with separator in 'sep'. An array
255 * of sds strings is returned. *count will be set
256 * by reference to the number of tokens returned.
258 * On out of memory, zero length string, zero length
259 * separator, NULL is returned.
261 * Note that 'sep' is able to split a string using
262 * a multi-character separator. For example
263 * sdssplit("foo_-_bar","_-_"); will return two
264 * elements "foo" and "bar".
266 * This version of the function is binary-safe but
267 * requires length arguments. sdssplit() is just the
268 * same function but for zero-terminated strings.
270 sds
*sdssplitlen(char *s
, int len
, char *sep
, int seplen
, int *count
) {
271 int elements
= 0, slots
= 5, start
= 0, j
;
273 sds
*tokens
= zmalloc(sizeof(sds
)*slots
);
274 #ifdef SDS_ABORT_ON_OOM
275 if (tokens
== NULL
) sdsOomAbort();
277 if (seplen
< 1 || len
< 0 || tokens
== NULL
) return NULL
;
278 for (j
= 0; j
< (len
-(seplen
-1)); j
++) {
279 /* make sure there is room for the next element and the final one */
280 if (slots
< elements
+2) {
284 newtokens
= zrealloc(tokens
,sizeof(sds
)*slots
);
285 if (newtokens
== NULL
) {
286 #ifdef SDS_ABORT_ON_OOM
294 /* search the separator */
295 if ((seplen
== 1 && *(s
+j
) == sep
[0]) || (memcmp(s
+j
,sep
,seplen
) == 0)) {
296 tokens
[elements
] = sdsnewlen(s
+start
,j
-start
);
297 if (tokens
[elements
] == NULL
) {
298 #ifdef SDS_ABORT_ON_OOM
306 j
= j
+seplen
-1; /* skip the separator */
309 /* Add the final element. We are sure there is room in the tokens array. */
310 tokens
[elements
] = sdsnewlen(s
+start
,len
-start
);
311 if (tokens
[elements
] == NULL
) {
312 #ifdef SDS_ABORT_ON_OOM
322 #ifndef SDS_ABORT_ON_OOM
326 for (i
= 0; i
< elements
; i
++) sdsfree(tokens
[i
]);