#include "sds.h"
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include "zmalloc.h"
return newsh->buf;
}
+/* Grow the sds to have the specified length. Bytes that were not part of
+ * the original length of the sds will be set to zero. */
+sds sdsgrowzero(sds s, size_t len) {
+ struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
+ size_t totlen, curlen = sh->len;
+
+ if (len <= curlen) return s;
+ s = sdsMakeRoomFor(s,len-curlen);
+ if (s == NULL) return NULL;
+
+ /* Make sure added region doesn't contain garbage */
+ sh = (void*)(s-(sizeof(struct sdshdr)));
+ memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
+ totlen = sh->len+sh->free;
+ sh->len = len;
+ sh->free = totlen-sh->len;
+ return s;
+}
+
sds sdscatlen(sds s, void *t, size_t len) {
struct sdshdr *sh;
size_t curlen = sdslen(s);
return sdscpylen(s, t, strlen(t));
}
-sds sdscatprintf(sds s, const char *fmt, ...) {
- va_list ap;
+sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
+ va_list cpy;
char *buf, *t;
size_t buflen = 16;
if (buf == NULL) return NULL;
#endif
buf[buflen-2] = '\0';
- va_start(ap, fmt);
- vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
+ va_copy(cpy,ap);
+ vsnprintf(buf, buflen, fmt, cpy);
if (buf[buflen-2] != '\0') {
zfree(buf);
buflen *= 2;
return t;
}
+sds sdscatprintf(sds s, const char *fmt, ...) {
+ va_list ap;
+ char *t;
+ va_start(ap, fmt);
+ t = sdscatvprintf(s,fmt,ap);
+ va_end(ap);
+ return t;
+}
+
sds sdstrim(sds s, const char *cset) {
struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
char *start, *end, *sp, *ep;
}
newlen = (start > end) ? 0 : (end-start)+1;
if (newlen != 0) {
- if (start >= (signed)len) start = len-1;
- if (end >= (signed)len) end = len-1;
- newlen = (start > end) ? 0 : (end-start)+1;
+ if (start >= (signed)len) {
+ newlen = 0;
+ } else if (end >= (signed)len) {
+ end = len-1;
+ newlen = (start > end) ? 0 : (end-start)+1;
+ }
} else {
start = 0;
}
- if (start != 0) memmove(sh->buf, sh->buf+start, newlen);
+ if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
sh->buf[newlen] = 0;
sh->free = sh->free+(sh->len-newlen);
sh->len = newlen;
#ifdef SDS_ABORT_ON_OOM
if (tokens == NULL) sdsOomAbort();
#endif
- if (seplen < 1 || len < 0 || tokens == NULL) return NULL;
+ if (seplen < 1 || len < 0 || tokens == NULL) {
+ *count = 0;
+ return NULL;
+ }
if (len == 0) {
*count = 0;
return tokens;
int i;
for (i = 0; i < elements; i++) sdsfree(tokens[i]);
zfree(tokens);
+ *count = 0;
return NULL;
}
#endif
case '"':
s = sdscatprintf(s,"\\%c",*p);
break;
- case '\n': s = sdscatlen(s,"\\n",1); break;
- case '\r': s = sdscatlen(s,"\\r",1); break;
- case '\t': s = sdscatlen(s,"\\t",1); break;
- case '\a': s = sdscatlen(s,"\\a",1); break;
- case '\b': s = sdscatlen(s,"\\b",1); break;
+ case '\n': s = sdscatlen(s,"\\n",2); break;
+ case '\r': s = sdscatlen(s,"\\r",2); break;
+ case '\t': s = sdscatlen(s,"\\t",2); break;
+ case '\a': s = sdscatlen(s,"\\a",2); break;
+ case '\b': s = sdscatlen(s,"\\b",2); break;
default:
if (isprint(*p))
s = sdscatprintf(s,"%c",*p);
if (*p) {
/* get a token */
int inq=0; /* set to 1 if we are in "quotes" */
- int done = 0;
+ int done=0;
if (current == NULL) current = sdsempty();
while(!done) {
}
current = sdscatlen(current,&c,1);
} else if (*p == '"') {
- done = 1;
+ /* closing quote must be followed by a space */
+ if (*(p+1) && !isspace(*(p+1))) goto err;
+ done=1;
+ } else if (!*p) {
+ /* unterminated quotes */
+ goto err;
} else {
current = sdscatlen(current,p,1);
}
return vector;
}
}
+
+err:
+ while((*argc)--)
+ sdsfree(vector[*argc]);
+ zfree(vector);
+ if (current) sdsfree(current);
+ return NULL;
+}
+
+#ifdef SDS_TEST_MAIN
+#include <stdio.h>
+#include "testhelp.h"
+
+int main(void) {
+ {
+ sds x = sdsnew("foo"), y;
+
+ test_cond("Create a string and obtain the length",
+ sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
+
+ sdsfree(x);
+ x = sdsnewlen("foo",2);
+ test_cond("Create a string with specified length",
+ sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
+
+ x = sdscat(x,"bar");
+ test_cond("Strings concatenation",
+ sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
+
+ x = sdscpy(x,"a");
+ test_cond("sdscpy() against an originally longer string",
+ sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
+
+ x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
+ test_cond("sdscpy() against an originally shorter string",
+ sdslen(x) == 33 &&
+ memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
+
+ sdsfree(x);
+ x = sdscatprintf(sdsempty(),"%d",123);
+ test_cond("sdscatprintf() seems working in the base case",
+ sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
+
+ sdsfree(x);
+ x = sdstrim(sdsnew("xxciaoyyy"),"xy");
+ test_cond("sdstrim() correctly trims characters",
+ sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
+
+ y = sdsrange(sdsdup(x),1,1);
+ test_cond("sdsrange(...,1,1)",
+ sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
+
+ sdsfree(y);
+ y = sdsrange(sdsdup(x),1,-1);
+ test_cond("sdsrange(...,1,-1)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsrange(sdsdup(x),-2,-1);
+ test_cond("sdsrange(...,-2,-1)",
+ sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
+
+ sdsfree(y);
+ y = sdsrange(sdsdup(x),2,1);
+ test_cond("sdsrange(...,2,1)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ y = sdsrange(sdsdup(x),1,100);
+ test_cond("sdsrange(...,1,100)",
+ sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
+
+ sdsfree(y);
+ y = sdsrange(sdsdup(x),100,100);
+ test_cond("sdsrange(...,100,100)",
+ sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("foo");
+ y = sdsnew("foa");
+ test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("bar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
+
+ sdsfree(y);
+ sdsfree(x);
+ x = sdsnew("aar");
+ y = sdsnew("bar");
+ test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
+ }
+ test_report()
}
+#endif