You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sds.c 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. /* SDS (Simple Dynamic Strings), A C dynamic strings library.
  2. *
  3. * Copyright (c) 2006-2014, Salvatore Sanfilippo <antirez at gmail dot com>
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  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.
  17. *
  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.
  29. */
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33. #include <ctype.h>
  34. #include <assert.h>
  35. #include "sds.h"
  36. /* Create a new sds string with the content specified by the 'init' pointer
  37. * and 'initlen'.
  38. * If NULL is used for 'init' the string is initialized with zero bytes.
  39. *
  40. * The string is always null-termined (all the sds strings are, always) so
  41. * even if you create an sds string with:
  42. *
  43. * mystring = sdsnewlen("abc",3");
  44. *
  45. * You can print the string with printf() as there is an implicit \0 at the
  46. * end of the string. However the string is binary safe and can contain
  47. * \0 characters in the middle, as the length is stored in the sds header. */
  48. sds sdsnewlen(const void *init, size_t initlen) {
  49. struct sdshdr *sh;
  50. if (init) {
  51. sh = malloc(sizeof *sh+initlen+1);
  52. } else {
  53. sh = calloc(sizeof *sh+initlen+1,1);
  54. }
  55. if (sh == NULL) return NULL;
  56. sh->len = initlen;
  57. sh->free = 0;
  58. if (initlen && init)
  59. memcpy(sh->buf, init, initlen);
  60. sh->buf[initlen] = '\0';
  61. return (char*)sh->buf;
  62. }
  63. /* Create an empty (zero length) sds string. Even in this case the string
  64. * always has an implicit null term. */
  65. sds sdsempty(void) {
  66. return sdsnewlen("",0);
  67. }
  68. /* Create a new sds string starting from a null termined C string. */
  69. sds sdsnew(const char *init) {
  70. size_t initlen = (init == NULL) ? 0 : strlen(init);
  71. return sdsnewlen(init, initlen);
  72. }
  73. /* Duplicate an sds string. */
  74. sds sdsdup(const sds s) {
  75. return sdsnewlen(s, sdslen(s));
  76. }
  77. /* Free an sds string. No operation is performed if 's' is NULL. */
  78. void sdsfree(sds s) {
  79. if (s == NULL) return;
  80. free(s-sizeof(struct sdshdr));
  81. }
  82. /* Set the sds string length to the length as obtained with strlen(), so
  83. * considering as content only up to the first null term character.
  84. *
  85. * This function is useful when the sds string is hacked manually in some
  86. * way, like in the following example:
  87. *
  88. * s = sdsnew("foobar");
  89. * s[2] = '\0';
  90. * sdsupdatelen(s);
  91. * printf("%d\n", sdslen(s));
  92. *
  93. * The output will be "2", but if we comment out the call to sdsupdatelen()
  94. * the output will be "6" as the string was modified but the logical length
  95. * remains 6 bytes. */
  96. void sdsupdatelen(sds s) {
  97. struct sdshdr *sh = (void*) (s-sizeof *sh);
  98. int reallen = strlen(s);
  99. sh->free += (sh->len-reallen);
  100. sh->len = reallen;
  101. }
  102. /* Modify an sds string on-place to make it empty (zero length).
  103. * However all the existing buffer is not discarded but set as free space
  104. * so that next append operations will not require allocations up to the
  105. * number of bytes previously available. */
  106. void sdsclear(sds s) {
  107. struct sdshdr *sh = (void*) (s-sizeof *sh);
  108. sh->free += sh->len;
  109. sh->len = 0;
  110. sh->buf[0] = '\0';
  111. }
  112. /* Enlarge the free space at the end of the sds string so that the caller
  113. * is sure that after calling this function can overwrite up to addlen
  114. * bytes after the end of the string, plus one more byte for nul term.
  115. *
  116. * Note: this does not change the *length* of the sds string as returned
  117. * by sdslen(), but only the free buffer space we have. */
  118. sds sdsMakeRoomFor(sds s, size_t addlen) {
  119. struct sdshdr *sh, *newsh;
  120. size_t free = sdsavail(s);
  121. size_t len, newlen;
  122. if (free >= addlen) return s;
  123. len = sdslen(s);
  124. sh = (void*) (s-sizeof *sh);
  125. newlen = (len+addlen);
  126. if (newlen < SDS_MAX_PREALLOC)
  127. newlen *= 2;
  128. else
  129. newlen += SDS_MAX_PREALLOC;
  130. newsh = realloc(sh, sizeof *newsh+newlen+1);
  131. if (newsh == NULL) return NULL;
  132. newsh->free = newlen - len;
  133. return newsh->buf;
  134. }
  135. /* Reallocate the sds string so that it has no free space at the end. The
  136. * contained string remains not altered, but next concatenation operations
  137. * will require a reallocation.
  138. *
  139. * After the call, the passed sds string is no longer valid and all the
  140. * references must be substituted with the new pointer returned by the call. */
  141. sds sdsRemoveFreeSpace(sds s) {
  142. struct sdshdr *sh;
  143. sh = (void*) (s-sizeof *sh);
  144. sh = realloc(sh, sizeof *sh+sh->len+1);
  145. sh->free = 0;
  146. return sh->buf;
  147. }
  148. /* Return the total size of the allocation of the specified sds string,
  149. * including:
  150. * 1) The sds header before the pointer.
  151. * 2) The string.
  152. * 3) The free buffer at the end if any.
  153. * 4) The implicit null term.
  154. */
  155. size_t sdsAllocSize(sds s) {
  156. struct sdshdr *sh = (void*) (s-sizeof *sh);
  157. return sizeof(*sh)+sh->len+sh->free+1;
  158. }
  159. /* Increment the sds length and decrements the left free space at the
  160. * end of the string according to 'incr'. Also set the null term
  161. * in the new end of the string.
  162. *
  163. * This function is used in order to fix the string length after the
  164. * user calls sdsMakeRoomFor(), writes something after the end of
  165. * the current string, and finally needs to set the new length.
  166. *
  167. * Note: it is possible to use a negative increment in order to
  168. * right-trim the string.
  169. *
  170. * Usage example:
  171. *
  172. * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
  173. * following schema, to cat bytes coming from the kernel to the end of an
  174. * sds string without copying into an intermediate buffer:
  175. *
  176. * oldlen = sdslen(s);
  177. * s = sdsMakeRoomFor(s, BUFFER_SIZE);
  178. * nread = read(fd, s+oldlen, BUFFER_SIZE);
  179. * ... check for nread <= 0 and handle it ...
  180. * sdsIncrLen(s, nread);
  181. */
  182. void sdsIncrLen(sds s, int incr) {
  183. struct sdshdr *sh = (void*) (s-sizeof *sh);
  184. assert(sh->free >= incr);
  185. sh->len += incr;
  186. sh->free -= incr;
  187. assert(sh->free >= 0);
  188. s[sh->len] = '\0';
  189. }
  190. /* Grow the sds to have the specified length. Bytes that were not part of
  191. * the original length of the sds will be set to zero.
  192. *
  193. * if the specified length is smaller than the current length, no operation
  194. * is performed. */
  195. sds sdsgrowzero(sds s, size_t len) {
  196. struct sdshdr *sh = (void*) (s-sizeof *sh);
  197. size_t totlen, curlen = sh->len;
  198. if (len <= curlen) return s;
  199. s = sdsMakeRoomFor(s,len-curlen);
  200. if (s == NULL) return NULL;
  201. /* Make sure added region doesn't contain garbage */
  202. sh = (void*)(s-sizeof *sh);
  203. memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */
  204. totlen = sh->len+sh->free;
  205. sh->len = len;
  206. sh->free = totlen-sh->len;
  207. return s;
  208. }
  209. /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
  210. * end of the specified sds string 's'.
  211. *
  212. * After the call, the passed sds string is no longer valid and all the
  213. * references must be substituted with the new pointer returned by the call. */
  214. sds sdscatlen(sds s, const void *t, size_t len) {
  215. struct sdshdr *sh;
  216. size_t curlen = sdslen(s);
  217. s = sdsMakeRoomFor(s,len);
  218. if (s == NULL) return NULL;
  219. sh = (void*) (s-sizeof *sh);
  220. memcpy(s+curlen, t, len);
  221. sh->len = curlen+len;
  222. sh->free = sh->free-len;
  223. s[curlen+len] = '\0';
  224. return s;
  225. }
  226. /* Append the specified null termianted C string to the sds string 's'.
  227. *
  228. * After the call, the passed sds string is no longer valid and all the
  229. * references must be substituted with the new pointer returned by the call. */
  230. sds sdscat(sds s, const char *t) {
  231. return sdscatlen(s, t, strlen(t));
  232. }
  233. /* Append the specified sds 't' to the existing sds 's'.
  234. *
  235. * After the call, the modified sds string is no longer valid and all the
  236. * references must be substituted with the new pointer returned by the call. */
  237. sds sdscatsds(sds s, const sds t) {
  238. return sdscatlen(s, t, sdslen(t));
  239. }
  240. /* Destructively modify the sds string 's' to hold the specified binary
  241. * safe string pointed by 't' of length 'len' bytes. */
  242. sds sdscpylen(sds s, const char *t, size_t len) {
  243. struct sdshdr *sh = (void*) (s-sizeof *sh);
  244. size_t totlen = sh->free+sh->len;
  245. if (totlen < len) {
  246. s = sdsMakeRoomFor(s,len-sh->len);
  247. if (s == NULL) return NULL;
  248. sh = (void*) (s-sizeof *sh);
  249. totlen = sh->free+sh->len;
  250. }
  251. memcpy(s, t, len);
  252. s[len] = '\0';
  253. sh->len = len;
  254. sh->free = totlen-len;
  255. return s;
  256. }
  257. /* Like sdscpylen() but 't' must be a null-termined string so that the length
  258. * of the string is obtained with strlen(). */
  259. sds sdscpy(sds s, const char *t) {
  260. return sdscpylen(s, t, strlen(t));
  261. }
  262. /* Helper for sdscatlonglong() doing the actual number -> string
  263. * conversion. 's' must point to a string with room for at least
  264. * SDS_LLSTR_SIZE bytes.
  265. *
  266. * The function returns the length of the null-terminated string
  267. * representation stored at 's'. */
  268. #define SDS_LLSTR_SIZE 21
  269. int sdsll2str(char *s, long long value) {
  270. char *p, aux;
  271. unsigned long long v;
  272. size_t l;
  273. /* Generate the string representation, this method produces
  274. * an reversed string. */
  275. v = (value < 0) ? -value : value;
  276. p = s;
  277. do {
  278. *p++ = '0'+(v%10);
  279. v /= 10;
  280. } while(v);
  281. if (value < 0) *p++ = '-';
  282. /* Compute length and add null term. */
  283. l = p-s;
  284. *p = '\0';
  285. /* Reverse the string. */
  286. p--;
  287. while(s < p) {
  288. aux = *s;
  289. *s = *p;
  290. *p = aux;
  291. s++;
  292. p--;
  293. }
  294. return l;
  295. }
  296. /* Identical sdsll2str(), but for unsigned long long type. */
  297. int sdsull2str(char *s, unsigned long long v) {
  298. char *p, aux;
  299. size_t l;
  300. /* Generate the string representation, this method produces
  301. * an reversed string. */
  302. p = s;
  303. do {
  304. *p++ = '0'+(v%10);
  305. v /= 10;
  306. } while(v);
  307. /* Compute length and add null term. */
  308. l = p-s;
  309. *p = '\0';
  310. /* Reverse the string. */
  311. p--;
  312. while(s < p) {
  313. aux = *s;
  314. *s = *p;
  315. *p = aux;
  316. s++;
  317. p--;
  318. }
  319. return l;
  320. }
  321. /* Like sdscatpritf() but gets va_list instead of being variadic. */
  322. sds sdscatvprintf(sds s, const char *fmt, va_list ap) {
  323. va_list cpy;
  324. char *buf, *t;
  325. size_t buflen = 16;
  326. while(1) {
  327. buf = malloc(buflen);
  328. if (buf == NULL) return NULL;
  329. buf[buflen-2] = '\0';
  330. va_copy(cpy,ap);
  331. vsnprintf(buf, buflen, fmt, cpy);
  332. if (buf[buflen-2] != '\0') {
  333. free(buf);
  334. buflen *= 2;
  335. continue;
  336. }
  337. break;
  338. }
  339. t = sdscat(s, buf);
  340. free(buf);
  341. return t;
  342. }
  343. /* Append to the sds string 's' a string obtained using printf-alike format
  344. * specifier.
  345. *
  346. * After the call, the modified sds string is no longer valid and all the
  347. * references must be substituted with the new pointer returned by the call.
  348. *
  349. * Example:
  350. *
  351. * s = sdsnew("Sum is: ");
  352. * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b);
  353. *
  354. * Often you need to create a string from scratch with the printf-alike
  355. * format. When this is the need, just use sdsempty() as the target string:
  356. *
  357. * s = sdscatprintf(sdsempty(), "... your format ...", args);
  358. */
  359. sds sdscatprintf(sds s, const char *fmt, ...) {
  360. va_list ap;
  361. char *t;
  362. va_start(ap, fmt);
  363. t = sdscatvprintf(s,fmt,ap);
  364. va_end(ap);
  365. return t;
  366. }
  367. /* This function is similar to sdscatprintf, but much faster as it does
  368. * not rely on sprintf() family functions implemented by the libc that
  369. * are often very slow. Moreover directly handling the sds string as
  370. * new data is concatenated provides a performance improvement.
  371. *
  372. * However this function only handles an incompatible subset of printf-alike
  373. * format specifiers:
  374. *
  375. * %s - C String
  376. * %S - SDS string
  377. * %i - signed int
  378. * %I - 64 bit signed integer (long long, int64_t)
  379. * %u - unsigned int
  380. * %U - 64 bit unsigned integer (unsigned long long, uint64_t)
  381. * %T - A size_t variable.
  382. * %% - Verbatim "%" character.
  383. */
  384. sds sdscatfmt(sds s, char const *fmt, ...) {
  385. struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
  386. size_t initlen = sdslen(s);
  387. const char *f = fmt;
  388. int i;
  389. va_list ap;
  390. va_start(ap,fmt);
  391. f = fmt; /* Next format specifier byte to process. */
  392. i = initlen; /* Position of the next byte to write to dest str. */
  393. while(*f) {
  394. char next, *str;
  395. int l;
  396. long long num;
  397. unsigned long long unum;
  398. /* Make sure there is always space for at least 1 char. */
  399. if (sh->free == 0) {
  400. s = sdsMakeRoomFor(s,1);
  401. sh = (void*) (s-(sizeof(struct sdshdr)));
  402. }
  403. switch(*f) {
  404. case '%':
  405. next = *(f+1);
  406. f++;
  407. switch(next) {
  408. case 's':
  409. case 'S':
  410. str = va_arg(ap,char*);
  411. l = (next == 's') ? strlen(str) : sdslen(str);
  412. if (sh->free < l) {
  413. s = sdsMakeRoomFor(s,l);
  414. sh = (void*) (s-(sizeof(struct sdshdr)));
  415. }
  416. memcpy(s+i,str,l);
  417. sh->len += l;
  418. sh->free -= l;
  419. i += l;
  420. break;
  421. case 'i':
  422. case 'I':
  423. if (next == 'i')
  424. num = va_arg(ap,int);
  425. else
  426. num = va_arg(ap,long long);
  427. {
  428. char buf[SDS_LLSTR_SIZE];
  429. l = sdsll2str(buf,num);
  430. if (sh->free < l) {
  431. s = sdsMakeRoomFor(s,l);
  432. sh = (void*) (s-(sizeof(struct sdshdr)));
  433. }
  434. memcpy(s+i,buf,l);
  435. sh->len += l;
  436. sh->free -= l;
  437. i += l;
  438. }
  439. break;
  440. case 'u':
  441. case 'U':
  442. case 'T':
  443. if (next == 'u')
  444. unum = va_arg(ap,unsigned int);
  445. else if(next == 'U')
  446. unum = va_arg(ap,unsigned long long);
  447. else
  448. unum = (unsigned long long)va_arg(ap,size_t);
  449. {
  450. char buf[SDS_LLSTR_SIZE];
  451. l = sdsull2str(buf,unum);
  452. if (sh->free < l) {
  453. s = sdsMakeRoomFor(s,l);
  454. sh = (void*) (s-(sizeof(struct sdshdr)));
  455. }
  456. memcpy(s+i,buf,l);
  457. sh->len += l;
  458. sh->free -= l;
  459. i += l;
  460. }
  461. break;
  462. default: /* Handle %% and generally %<unknown>. */
  463. s[i++] = next;
  464. sh->len += 1;
  465. sh->free -= 1;
  466. break;
  467. }
  468. break;
  469. default:
  470. s[i++] = *f;
  471. sh->len += 1;
  472. sh->free -= 1;
  473. break;
  474. }
  475. f++;
  476. }
  477. va_end(ap);
  478. /* Add null-term */
  479. s[i] = '\0';
  480. return s;
  481. }
  482. /* Remove the part of the string from left and from right composed just of
  483. * contiguous characters found in 'cset', that is a null terminted C string.
  484. *
  485. * After the call, the modified sds string is no longer valid and all the
  486. * references must be substituted with the new pointer returned by the call.
  487. *
  488. * Example:
  489. *
  490. * s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
  491. * s = sdstrim(s,"A. :");
  492. * printf("%s\n", s);
  493. *
  494. * Output will be just "Hello World".
  495. */
  496. void sdstrim(sds s, const char *cset) {
  497. struct sdshdr *sh = (void*) (s-sizeof *sh);
  498. char *start, *end, *sp, *ep;
  499. size_t len;
  500. sp = start = s;
  501. ep = end = s+sdslen(s)-1;
  502. while(sp <= end && strchr(cset, *sp)) sp++;
  503. while(ep > start && strchr(cset, *ep)) ep--;
  504. len = (sp > ep) ? 0 : ((ep-sp)+1);
  505. if (sh->buf != sp) memmove(sh->buf, sp, len);
  506. sh->buf[len] = '\0';
  507. sh->free = sh->free+(sh->len-len);
  508. sh->len = len;
  509. }
  510. /* Turn the string into a smaller (or equal) string containing only the
  511. * substring specified by the 'start' and 'end' indexes.
  512. *
  513. * start and end can be negative, where -1 means the last character of the
  514. * string, -2 the penultimate character, and so forth.
  515. *
  516. * The interval is inclusive, so the start and end characters will be part
  517. * of the resulting string.
  518. *
  519. * The string is modified in-place.
  520. *
  521. * Example:
  522. *
  523. * s = sdsnew("Hello World");
  524. * sdsrange(s,1,-1); => "ello World"
  525. */
  526. void sdsrange(sds s, int start, int end) {
  527. struct sdshdr *sh = (void*) (s-sizeof *sh);
  528. size_t newlen, len = sdslen(s);
  529. if (len == 0) return;
  530. if (start < 0) {
  531. start = len+start;
  532. if (start < 0) start = 0;
  533. }
  534. if (end < 0) {
  535. end = len+end;
  536. if (end < 0) end = 0;
  537. }
  538. newlen = (start > end) ? 0 : (end-start)+1;
  539. if (newlen != 0) {
  540. if (start >= (signed)len) {
  541. newlen = 0;
  542. } else if (end >= (signed)len) {
  543. end = len-1;
  544. newlen = (start > end) ? 0 : (end-start)+1;
  545. }
  546. } else {
  547. start = 0;
  548. }
  549. if (start && newlen) memmove(sh->buf, sh->buf+start, newlen);
  550. sh->buf[newlen] = 0;
  551. sh->free = sh->free+(sh->len-newlen);
  552. sh->len = newlen;
  553. }
  554. /* Apply tolower() to every character of the sds string 's'. */
  555. void sdstolower(sds s) {
  556. int len = sdslen(s), j;
  557. for (j = 0; j < len; j++) s[j] = tolower(s[j]);
  558. }
  559. /* Apply toupper() to every character of the sds string 's'. */
  560. void sdstoupper(sds s) {
  561. int len = sdslen(s), j;
  562. for (j = 0; j < len; j++) s[j] = toupper(s[j]);
  563. }
  564. /* Compare two sds strings s1 and s2 with memcmp().
  565. *
  566. * Return value:
  567. *
  568. * 1 if s1 > s2.
  569. * -1 if s1 < s2.
  570. * 0 if s1 and s2 are exactly the same binary string.
  571. *
  572. * If two strings share exactly the same prefix, but one of the two has
  573. * additional characters, the longer string is considered to be greater than
  574. * the smaller one. */
  575. int sdscmp(const sds s1, const sds s2) {
  576. size_t l1, l2, minlen;
  577. int cmp;
  578. l1 = sdslen(s1);
  579. l2 = sdslen(s2);
  580. minlen = (l1 < l2) ? l1 : l2;
  581. cmp = memcmp(s1,s2,minlen);
  582. if (cmp == 0) return l1-l2;
  583. return cmp;
  584. }
  585. /* Split 's' with separator in 'sep'. An array
  586. * of sds strings is returned. *count will be set
  587. * by reference to the number of tokens returned.
  588. *
  589. * On out of memory, zero length string, zero length
  590. * separator, NULL is returned.
  591. *
  592. * Note that 'sep' is able to split a string using
  593. * a multi-character separator. For example
  594. * sdssplit("foo_-_bar","_-_"); will return two
  595. * elements "foo" and "bar".
  596. *
  597. * This version of the function is binary-safe but
  598. * requires length arguments. sdssplit() is just the
  599. * same function but for zero-terminated strings.
  600. */
  601. sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) {
  602. int elements = 0, slots = 5, start = 0, j;
  603. sds *tokens;
  604. if (seplen < 1 || len < 0) return NULL;
  605. tokens = malloc(sizeof(sds)*slots);
  606. if (tokens == NULL) return NULL;
  607. if (len == 0) {
  608. *count = 0;
  609. return tokens;
  610. }
  611. for (j = 0; j < (len-(seplen-1)); j++) {
  612. /* make sure there is room for the next element and the final one */
  613. if (slots < elements+2) {
  614. sds *newtokens;
  615. slots *= 2;
  616. newtokens = realloc(tokens,sizeof(sds)*slots);
  617. if (newtokens == NULL) goto cleanup;
  618. tokens = newtokens;
  619. }
  620. /* search the separator */
  621. if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) {
  622. tokens[elements] = sdsnewlen(s+start,j-start);
  623. if (tokens[elements] == NULL) goto cleanup;
  624. elements++;
  625. start = j+seplen;
  626. j = j+seplen-1; /* skip the separator */
  627. }
  628. }
  629. /* Add the final element. We are sure there is room in the tokens array. */
  630. tokens[elements] = sdsnewlen(s+start,len-start);
  631. if (tokens[elements] == NULL) goto cleanup;
  632. elements++;
  633. *count = elements;
  634. return tokens;
  635. cleanup:
  636. {
  637. int i;
  638. for (i = 0; i < elements; i++) sdsfree(tokens[i]);
  639. free(tokens);
  640. *count = 0;
  641. return NULL;
  642. }
  643. }
  644. /* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */
  645. void sdsfreesplitres(sds *tokens, int count) {
  646. if (!tokens) return;
  647. while(count--)
  648. sdsfree(tokens[count]);
  649. free(tokens);
  650. }
  651. /* Create an sds string from a long long value. It is much faster than:
  652. *
  653. * sdscatprintf(sdsempty(),"%lld\n", value);
  654. */
  655. sds sdsfromlonglong(long long value) {
  656. char buf[32], *p;
  657. unsigned long long v;
  658. v = (value < 0) ? -value : value;
  659. p = buf+31; /* point to the last character */
  660. do {
  661. *p-- = '0'+(v%10);
  662. v /= 10;
  663. } while(v);
  664. if (value < 0) *p-- = '-';
  665. p++;
  666. return sdsnewlen(p,32-(p-buf));
  667. }
  668. /* Append to the sds string "s" an escaped string representation where
  669. * all the non-printable characters (tested with isprint()) are turned into
  670. * escapes in the form "\n\r\a...." or "\x<hex-number>".
  671. *
  672. * After the call, the modified sds string is no longer valid and all the
  673. * references must be substituted with the new pointer returned by the call. */
  674. sds sdscatrepr(sds s, const char *p, size_t len) {
  675. s = sdscatlen(s,"\"",1);
  676. while(len--) {
  677. switch(*p) {
  678. case '\\':
  679. case '"':
  680. s = sdscatprintf(s,"\\%c",*p);
  681. break;
  682. case '\n': s = sdscatlen(s,"\\n",2); break;
  683. case '\r': s = sdscatlen(s,"\\r",2); break;
  684. case '\t': s = sdscatlen(s,"\\t",2); break;
  685. case '\a': s = sdscatlen(s,"\\a",2); break;
  686. case '\b': s = sdscatlen(s,"\\b",2); break;
  687. default:
  688. if (isprint(*p))
  689. s = sdscatprintf(s,"%c",*p);
  690. else
  691. s = sdscatprintf(s,"\\x%02x",(unsigned char)*p);
  692. break;
  693. }
  694. p++;
  695. }
  696. return sdscatlen(s,"\"",1);
  697. }
  698. /* Helper function for sdssplitargs() that returns non zero if 'c'
  699. * is a valid hex digit. */
  700. int is_hex_digit(char c) {
  701. return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  702. (c >= 'A' && c <= 'F');
  703. }
  704. /* Helper function for sdssplitargs() that converts a hex digit into an
  705. * integer from 0 to 15 */
  706. int hex_digit_to_int(char c) {
  707. switch(c) {
  708. case '0': return 0;
  709. case '1': return 1;
  710. case '2': return 2;
  711. case '3': return 3;
  712. case '4': return 4;
  713. case '5': return 5;
  714. case '6': return 6;
  715. case '7': return 7;
  716. case '8': return 8;
  717. case '9': return 9;
  718. case 'a': case 'A': return 10;
  719. case 'b': case 'B': return 11;
  720. case 'c': case 'C': return 12;
  721. case 'd': case 'D': return 13;
  722. case 'e': case 'E': return 14;
  723. case 'f': case 'F': return 15;
  724. default: return 0;
  725. }
  726. }
  727. /* Split a line into arguments, where every argument can be in the
  728. * following programming-language REPL-alike form:
  729. *
  730. * foo bar "newline are supported\n" and "\xff\x00otherstuff"
  731. *
  732. * The number of arguments is stored into *argc, and an array
  733. * of sds is returned.
  734. *
  735. * The caller should free the resulting array of sds strings with
  736. * sdsfreesplitres().
  737. *
  738. * Note that sdscatrepr() is able to convert back a string into
  739. * a quoted string in the same format sdssplitargs() is able to parse.
  740. *
  741. * The function returns the allocated tokens on success, even when the
  742. * input string is empty, or NULL if the input contains unbalanced
  743. * quotes or closed quotes followed by non space characters
  744. * as in: "foo"bar or "foo'
  745. */
  746. sds *sdssplitargs(const char *line, int *argc) {
  747. const char *p = line;
  748. char *current = NULL;
  749. char **vector = NULL;
  750. *argc = 0;
  751. while(1) {
  752. /* skip blanks */
  753. while(*p && isspace(*p)) p++;
  754. if (*p) {
  755. /* get a token */
  756. int inq=0; /* set to 1 if we are in "quotes" */
  757. int insq=0; /* set to 1 if we are in 'single quotes' */
  758. int done=0;
  759. if (current == NULL) current = sdsempty();
  760. while(!done) {
  761. if (inq) {
  762. if (*p == '\\' && *(p+1) == 'x' &&
  763. is_hex_digit(*(p+2)) &&
  764. is_hex_digit(*(p+3)))
  765. {
  766. unsigned char byte;
  767. byte = (hex_digit_to_int(*(p+2))*16)+
  768. hex_digit_to_int(*(p+3));
  769. current = sdscatlen(current,(char*)&byte,1);
  770. p += 3;
  771. } else if (*p == '\\' && *(p+1)) {
  772. char c;
  773. p++;
  774. switch(*p) {
  775. case 'n': c = '\n'; break;
  776. case 'r': c = '\r'; break;
  777. case 't': c = '\t'; break;
  778. case 'b': c = '\b'; break;
  779. case 'a': c = '\a'; break;
  780. default: c = *p; break;
  781. }
  782. current = sdscatlen(current,&c,1);
  783. } else if (*p == '"') {
  784. /* closing quote must be followed by a space or
  785. * nothing at all. */
  786. if (*(p+1) && !isspace(*(p+1))) goto err;
  787. done=1;
  788. } else if (!*p) {
  789. /* unterminated quotes */
  790. goto err;
  791. } else {
  792. current = sdscatlen(current,p,1);
  793. }
  794. } else if (insq) {
  795. if (*p == '\\' && *(p+1) == '\'') {
  796. p++;
  797. current = sdscatlen(current,"'",1);
  798. } else if (*p == '\'') {
  799. /* closing quote must be followed by a space or
  800. * nothing at all. */
  801. if (*(p+1) && !isspace(*(p+1))) goto err;
  802. done=1;
  803. } else if (!*p) {
  804. /* unterminated quotes */
  805. goto err;
  806. } else {
  807. current = sdscatlen(current,p,1);
  808. }
  809. } else {
  810. switch(*p) {
  811. case ' ':
  812. case '\n':
  813. case '\r':
  814. case '\t':
  815. case '\0':
  816. done=1;
  817. break;
  818. case '"':
  819. inq=1;
  820. break;
  821. case '\'':
  822. insq=1;
  823. break;
  824. default:
  825. current = sdscatlen(current,p,1);
  826. break;
  827. }
  828. }
  829. if (*p) p++;
  830. }
  831. /* add the token to the vector */
  832. vector = realloc(vector,((*argc)+1)*sizeof(char*));
  833. vector[*argc] = current;
  834. (*argc)++;
  835. current = NULL;
  836. } else {
  837. /* Even on empty input string return something not NULL. */
  838. if (vector == NULL) vector = malloc(sizeof(void*));
  839. return vector;
  840. }
  841. }
  842. err:
  843. while((*argc)--)
  844. sdsfree(vector[*argc]);
  845. free(vector);
  846. if (current) sdsfree(current);
  847. *argc = 0;
  848. return NULL;
  849. }
  850. /* Modify the string substituting all the occurrences of the set of
  851. * characters specified in the 'from' string to the corresponding character
  852. * in the 'to' array.
  853. *
  854. * For instance: sdsmapchars(mystring, "ho", "01", 2)
  855. * will have the effect of turning the string "hello" into "0ell1".
  856. *
  857. * The function returns the sds string pointer, that is always the same
  858. * as the input pointer since no resize is needed. */
  859. sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) {
  860. size_t j, i, l = sdslen(s);
  861. for (j = 0; j < l; j++) {
  862. for (i = 0; i < setlen; i++) {
  863. if (s[j] == from[i]) {
  864. s[j] = to[i];
  865. break;
  866. }
  867. }
  868. }
  869. return s;
  870. }
  871. /* Join an array of C strings using the specified separator (also a C string).
  872. * Returns the result as an sds string. */
  873. sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) {
  874. sds join = sdsempty();
  875. int j;
  876. for (j = 0; j < argc; j++) {
  877. join = sdscat(join, argv[j]);
  878. if (j != argc-1) join = sdscatlen(join,sep,seplen);
  879. }
  880. return join;
  881. }
  882. /* Like sdsjoin, but joins an array of SDS strings. */
  883. sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) {
  884. sds join = sdsempty();
  885. int j;
  886. for (j = 0; j < argc; j++) {
  887. join = sdscatsds(join, argv[j]);
  888. if (j != argc-1) join = sdscatlen(join,sep,seplen);
  889. }
  890. return join;
  891. }
  892. #ifdef SDS_TEST_MAIN
  893. #include <stdio.h>
  894. #include "testhelp.h"
  895. int main(void) {
  896. {
  897. struct sdshdr *sh;
  898. sds x = sdsnew("foo"), y;
  899. test_cond("Create a string and obtain the length",
  900. sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0)
  901. sdsfree(x);
  902. x = sdsnewlen("foo",2);
  903. test_cond("Create a string with specified length",
  904. sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0)
  905. x = sdscat(x,"bar");
  906. test_cond("Strings concatenation",
  907. sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0);
  908. x = sdscpy(x,"a");
  909. test_cond("sdscpy() against an originally longer string",
  910. sdslen(x) == 1 && memcmp(x,"a\0",2) == 0)
  911. x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
  912. test_cond("sdscpy() against an originally shorter string",
  913. sdslen(x) == 33 &&
  914. memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0)
  915. sdsfree(x);
  916. x = sdscatprintf(sdsempty(),"%d",123);
  917. test_cond("sdscatprintf() seems working in the base case",
  918. sdslen(x) == 3 && memcmp(x,"123\0",4) ==0)
  919. sdsfree(x);
  920. x = sdsnew("xxciaoyyy");
  921. sdstrim(x,"xy");
  922. test_cond("sdstrim() correctly trims characters",
  923. sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0)
  924. y = sdsdup(x);
  925. sdsrange(y,1,1);
  926. test_cond("sdsrange(...,1,1)",
  927. sdslen(y) == 1 && memcmp(y,"i\0",2) == 0)
  928. sdsfree(y);
  929. y = sdsdup(x);
  930. sdsrange(y,1,-1);
  931. test_cond("sdsrange(...,1,-1)",
  932. sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
  933. sdsfree(y);
  934. y = sdsdup(x);
  935. sdsrange(y,-2,-1);
  936. test_cond("sdsrange(...,-2,-1)",
  937. sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0)
  938. sdsfree(y);
  939. y = sdsdup(x);
  940. sdsrange(y,2,1);
  941. test_cond("sdsrange(...,2,1)",
  942. sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
  943. sdsfree(y);
  944. y = sdsdup(x);
  945. sdsrange(y,1,100);
  946. test_cond("sdsrange(...,1,100)",
  947. sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0)
  948. sdsfree(y);
  949. y = sdsdup(x);
  950. sdsrange(y,100,100);
  951. test_cond("sdsrange(...,100,100)",
  952. sdslen(y) == 0 && memcmp(y,"\0",1) == 0)
  953. sdsfree(y);
  954. sdsfree(x);
  955. x = sdsnew("foo");
  956. y = sdsnew("foa");
  957. test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0)
  958. sdsfree(y);
  959. sdsfree(x);
  960. x = sdsnew("bar");
  961. y = sdsnew("bar");
  962. test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
  963. sdsfree(y);
  964. sdsfree(x);
  965. x = sdsnew("aar");
  966. y = sdsnew("bar");
  967. test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
  968. sdsfree(y);
  969. sdsfree(x);
  970. x = sdsnewlen("\a\n\0foo\r",7);
  971. y = sdscatrepr(sdsempty(),x,sdslen(x));
  972. test_cond("sdscatrepr(...data...)",
  973. memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0)
  974. {
  975. int oldfree;
  976. sdsfree(x);
  977. x = sdsnew("0");
  978. sh = (void*) (x-(sizeof(struct sdshdr)));
  979. test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0);
  980. x = sdsMakeRoomFor(x,1);
  981. sh = (void*) (x-(sizeof(struct sdshdr)));
  982. test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0);
  983. oldfree = sh->free;
  984. x[1] = '1';
  985. sdsIncrLen(x,1);
  986. test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1');
  987. test_cond("sdsIncrLen() -- len", sh->len == 2);
  988. test_cond("sdsIncrLen() -- free", sh->free == oldfree-1);
  989. }
  990. }
  991. test_report()
  992. return 0;
  993. }
  994. #endif