sds.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386
  1. /* SDSLib 2.0 -- A C dynamic strings library
  2. *
  3. * Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
  4. * Copyright (c) 2015, Oran Agra
  5. * Copyright (c) 2015, Redis Labs, Inc
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright notice,
  12. * this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. * * Neither the name of Redis nor the names of its contributors may be used
  17. * to endorse or promote products derived from this software without
  18. * specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  24. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <ctype.h>
  36. #include <assert.h>
  37. #include "sds.h"
  38. #include "sdsalloc.h"
  39. static inline int sdsHdrSize(char type)
  40. {
  41. switch (type & SDS_TYPE_MASK) {
  42. case SDS_TYPE_5:
  43. return sizeof(struct sdshdr5);
  44. case SDS_TYPE_8:
  45. return sizeof(struct sdshdr8);
  46. case SDS_TYPE_16:
  47. return sizeof(struct sdshdr16);
  48. case SDS_TYPE_32:
  49. return sizeof(struct sdshdr32);
  50. case SDS_TYPE_64:
  51. return sizeof(struct sdshdr64);
  52. }
  53. return 0;
  54. }
  55. static inline char sdsReqType(size_t string_size)
  56. {
  57. if (string_size < 32)
  58. return SDS_TYPE_5;
  59. if (string_size < 0xff)
  60. return SDS_TYPE_8;
  61. if (string_size < 0xffff)
  62. return SDS_TYPE_16;
  63. if (string_size < 0xffffffff)
  64. return SDS_TYPE_32;
  65. return SDS_TYPE_64;
  66. }
  67. /* Create a new sds string with the content specified by the 'init' pointer
  68. * and 'initlen'.
  69. * If NULL is used for 'init' the string is initialized with zero bytes.
  70. *
  71. * The string is always null-termined (all the sds strings are, always) so
  72. * even if you create an sds string with:
  73. *
  74. * mystring = sdsnewlen("abc",3);
  75. *
  76. * You can print the string with printf() as there is an implicit \0 at the
  77. * end of the string. However the string is binary safe and can contain
  78. * \0 characters in the middle, as the length is stored in the sds header. */
  79. sds sdsnewlen(const void* init, size_t initlen)
  80. {
  81. void* sh;
  82. sds s;
  83. char type = sdsReqType(initlen);
  84. /* Empty strings are usually created in order to append. Use type 8
  85. * since type 5 is not good at this. */
  86. if (type == SDS_TYPE_5 && initlen == 0)
  87. type = SDS_TYPE_8;
  88. int hdrlen = sdsHdrSize(type);
  89. unsigned char* fp; /* flags pointer. */
  90. sh = s_malloc(hdrlen + initlen + 1);
  91. if (!init)
  92. memset(sh, 0, hdrlen + initlen + 1);
  93. if (sh == NULL)
  94. return NULL;
  95. s = (char*) sh + hdrlen;
  96. fp = ((unsigned char*) s) - 1;
  97. switch (type) {
  98. case SDS_TYPE_5: {
  99. *fp = type | (initlen << SDS_TYPE_BITS);
  100. break;
  101. }
  102. case SDS_TYPE_8: {
  103. SDS_HDR_VAR(8, s);
  104. sh->len = initlen;
  105. sh->alloc = initlen;
  106. *fp = type;
  107. break;
  108. }
  109. case SDS_TYPE_16: {
  110. SDS_HDR_VAR(16, s);
  111. sh->len = initlen;
  112. sh->alloc = initlen;
  113. *fp = type;
  114. break;
  115. }
  116. case SDS_TYPE_32: {
  117. SDS_HDR_VAR(32, s);
  118. sh->len = initlen;
  119. sh->alloc = initlen;
  120. *fp = type;
  121. break;
  122. }
  123. case SDS_TYPE_64: {
  124. SDS_HDR_VAR(64, s);
  125. sh->len = initlen;
  126. sh->alloc = initlen;
  127. *fp = type;
  128. break;
  129. }
  130. }
  131. if (initlen && init)
  132. memcpy(s, init, initlen);
  133. s[initlen] = '\0';
  134. return s;
  135. }
  136. /* Create an empty (zero length) sds string. Even in this case the string
  137. * always has an implicit null term. */
  138. sds sdsempty(void) { return sdsnewlen("", 0); }
  139. /* Create a new sds string starting from a null terminated C string. */
  140. sds sdsnew(const char* init)
  141. {
  142. size_t initlen = (init == NULL) ? 0 : strlen(init);
  143. return sdsnewlen(init, initlen);
  144. }
  145. /* Duplicate an sds string. */
  146. sds sdsdup(const sds s) { return sdsnewlen(s, sdslen(s)); }
  147. /* Free an sds string. No operation is performed if 's' is NULL. */
  148. void sdsfree(sds s)
  149. {
  150. if (s == NULL)
  151. return;
  152. s_free((char*) s - sdsHdrSize(s[-1]));
  153. }
  154. /* Set the sds string length to the length as obtained with strlen(), so
  155. * considering as content only up to the first null term character.
  156. *
  157. * This function is useful when the sds string is hacked manually in some
  158. * way, like in the following example:
  159. *
  160. * s = sdsnew("foobar");
  161. * s[2] = '\0';
  162. * sdsupdatelen(s);
  163. * printf("%d\n", sdslen(s));
  164. *
  165. * The output will be "2", but if we comment out the call to sdsupdatelen()
  166. * the output will be "6" as the string was modified but the logical length
  167. * remains 6 bytes. */
  168. void sdsupdatelen(sds s)
  169. {
  170. int reallen = strlen(s);
  171. sdssetlen(s, reallen);
  172. }
  173. /* Modify an sds string in-place to make it empty (zero length).
  174. * However all the existing buffer is not discarded but set as free space
  175. * so that next append operations will not require allocations up to the
  176. * number of bytes previously available. */
  177. void sdsclear(sds s)
  178. {
  179. sdssetlen(s, 0);
  180. s[0] = '\0';
  181. }
  182. /* Enlarge the free space at the end of the sds string so that the caller
  183. * is sure that after calling this function can overwrite up to addlen
  184. * bytes after the end of the string, plus one more byte for nul term.
  185. *
  186. * Note: this does not change the *length* of the sds string as returned
  187. * by sdslen(), but only the free buffer space we have. */
  188. sds sdsMakeRoomFor(sds s, size_t addlen)
  189. {
  190. void *sh, *newsh;
  191. size_t avail = sdsavail(s);
  192. size_t len, newlen;
  193. char type, oldtype = s[-1] & SDS_TYPE_MASK;
  194. int hdrlen;
  195. /* Return ASAP if there is enough space left. */
  196. if (avail >= addlen)
  197. return s;
  198. len = sdslen(s);
  199. sh = (char*) s - sdsHdrSize(oldtype);
  200. newlen = (len + addlen);
  201. if (newlen < SDS_MAX_PREALLOC)
  202. newlen *= 2;
  203. else
  204. newlen += SDS_MAX_PREALLOC;
  205. type = sdsReqType(newlen);
  206. /* Don't use type 5: the user is appending to the string and type 5 is
  207. * not able to remember empty space, so sdsMakeRoomFor() must be called
  208. * at every appending operation. */
  209. if (type == SDS_TYPE_5)
  210. type = SDS_TYPE_8;
  211. hdrlen = sdsHdrSize(type);
  212. if (oldtype == type) {
  213. newsh = s_realloc(sh, hdrlen + newlen + 1);
  214. if (newsh == NULL)
  215. return NULL;
  216. s = (char*) newsh + hdrlen;
  217. } else {
  218. /* Since the header size changes, need to move the string forward,
  219. * and can't use realloc */
  220. newsh = s_malloc(hdrlen + newlen + 1);
  221. if (newsh == NULL)
  222. return NULL;
  223. memcpy((char*) newsh + hdrlen, s, len + 1);
  224. s_free(sh);
  225. s = (char*) newsh + hdrlen;
  226. s[-1] = type;
  227. sdssetlen(s, len);
  228. }
  229. sdssetalloc(s, newlen);
  230. return s;
  231. }
  232. /* Reallocate the sds string so that it has no free space at the end. The
  233. * contained string remains not altered, but next concatenation operations
  234. * will require a reallocation.
  235. *
  236. * After the call, the passed sds string is no longer valid and all the
  237. * references must be substituted with the new pointer returned by the call. */
  238. sds sdsRemoveFreeSpace(sds s)
  239. {
  240. void *sh, *newsh;
  241. char type, oldtype = s[-1] & SDS_TYPE_MASK;
  242. int hdrlen;
  243. size_t len = sdslen(s);
  244. sh = (char*) s - sdsHdrSize(oldtype);
  245. type = sdsReqType(len);
  246. hdrlen = sdsHdrSize(type);
  247. if (oldtype == type) {
  248. newsh = s_realloc(sh, hdrlen + len + 1);
  249. if (newsh == NULL)
  250. return NULL;
  251. s = (char*) newsh + hdrlen;
  252. } else {
  253. newsh = s_malloc(hdrlen + len + 1);
  254. if (newsh == NULL)
  255. return NULL;
  256. memcpy((char*) newsh + hdrlen, s, len + 1);
  257. s_free(sh);
  258. s = (char*) newsh + hdrlen;
  259. s[-1] = type;
  260. sdssetlen(s, len);
  261. }
  262. sdssetalloc(s, len);
  263. return s;
  264. }
  265. /* Return the total size of the allocation of the specifed sds string,
  266. * including:
  267. * 1) The sds header before the pointer.
  268. * 2) The string.
  269. * 3) The free buffer at the end if any.
  270. * 4) The implicit null term.
  271. */
  272. size_t sdsAllocSize(sds s)
  273. {
  274. size_t alloc = sdsalloc(s);
  275. return sdsHdrSize(s[-1]) + alloc + 1;
  276. }
  277. /* Return the pointer of the actual SDS allocation (normally SDS strings
  278. * are referenced by the start of the string buffer). */
  279. void* sdsAllocPtr(sds s) { return (void*) (s - sdsHdrSize(s[-1])); }
  280. /* Increment the sds length and decrements the left free space at the
  281. * end of the string according to 'incr'. Also set the null term
  282. * in the new end of the string.
  283. *
  284. * This function is used in order to fix the string length after the
  285. * user calls sdsMakeRoomFor(), writes something after the end of
  286. * the current string, and finally needs to set the new length.
  287. *
  288. * Note: it is possible to use a negative increment in order to
  289. * right-trim the string.
  290. *
  291. * Usage example:
  292. *
  293. * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the
  294. * following schema, to cat bytes coming from the kernel to the end of an
  295. * sds string without copying into an intermediate buffer:
  296. *
  297. * oldlen = sdslen(s);
  298. * s = sdsMakeRoomFor(s, BUFFER_SIZE);
  299. * nread = read(fd, s+oldlen, BUFFER_SIZE);
  300. * ... check for nread <= 0 and handle it ...
  301. * sdsIncrLen(s, nread);
  302. */
  303. void sdsIncrLen(sds s, int incr)
  304. {
  305. unsigned char flags = s[-1];
  306. size_t len;
  307. switch (flags & SDS_TYPE_MASK) {
  308. case SDS_TYPE_5: {
  309. unsigned char* fp = ((unsigned char*) s) - 1;
  310. unsigned char oldlen = SDS_TYPE_5_LEN(flags);
  311. assert((incr > 0 && oldlen + incr < 32) ||
  312. (incr < 0 && oldlen >= (unsigned int) (-incr)));
  313. *fp = SDS_TYPE_5 | ((oldlen + incr) << SDS_TYPE_BITS);
  314. len = oldlen + incr;
  315. break;
  316. }
  317. case SDS_TYPE_8: {
  318. SDS_HDR_VAR(8, s);
  319. assert((incr >= 0 && sh->alloc - sh->len >= incr) ||
  320. (incr < 0 && sh->len >= (unsigned int) (-incr)));
  321. len = (sh->len += incr);
  322. break;
  323. }
  324. case SDS_TYPE_16: {
  325. SDS_HDR_VAR(16, s);
  326. assert((incr >= 0 && sh->alloc - sh->len >= incr) ||
  327. (incr < 0 && sh->len >= (unsigned int) (-incr)));
  328. len = (sh->len += incr);
  329. break;
  330. }
  331. case SDS_TYPE_32: {
  332. SDS_HDR_VAR(32, s);
  333. assert((incr >= 0 && sh->alloc - sh->len >= (unsigned int) incr) ||
  334. (incr < 0 && sh->len >= (unsigned int) (-incr)));
  335. len = (sh->len += incr);
  336. break;
  337. }
  338. case SDS_TYPE_64: {
  339. SDS_HDR_VAR(64, s);
  340. assert((incr >= 0 && sh->alloc - sh->len >= (uint64_t) incr) ||
  341. (incr < 0 && sh->len >= (uint64_t)(-incr)));
  342. len = (sh->len += incr);
  343. break;
  344. }
  345. default:
  346. len = 0; /* Just to avoid compilation warnings. */
  347. }
  348. s[len] = '\0';
  349. }
  350. /* Grow the sds to have the specified length. Bytes that were not part of
  351. * the original length of the sds will be set to zero.
  352. *
  353. * if the specified length is smaller than the current length, no operation
  354. * is performed. */
  355. sds sdsgrowzero(sds s, size_t len)
  356. {
  357. size_t curlen = sdslen(s);
  358. if (len <= curlen)
  359. return s;
  360. s = sdsMakeRoomFor(s, len - curlen);
  361. if (s == NULL)
  362. return NULL;
  363. /* Make sure added region doesn't contain garbage */
  364. memset(s + curlen, 0, (len - curlen + 1)); /* also set trailing \0 byte */
  365. sdssetlen(s, len);
  366. return s;
  367. }
  368. /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the
  369. * end of the specified sds string 's'.
  370. *
  371. * After the call, the passed sds string is no longer valid and all the
  372. * references must be substituted with the new pointer returned by the call. */
  373. sds sdscatlen(sds s, const void* t, size_t len)
  374. {
  375. size_t curlen = sdslen(s);
  376. s = sdsMakeRoomFor(s, len);
  377. if (s == NULL)
  378. return NULL;
  379. memcpy(s + curlen, t, len);
  380. sdssetlen(s, curlen + len);
  381. s[curlen + len] = '\0';
  382. return s;
  383. }
  384. /* Append the specified null termianted C string to the sds string 's'.
  385. *
  386. * After the call, the passed sds string is no longer valid and all the
  387. * references must be substituted with the new pointer returned by the call. */
  388. sds sdscat(sds s, const char* t) { return sdscatlen(s, t, strlen(t)); }
  389. /* Append the specified sds 't' to the existing sds 's'.
  390. *
  391. * After the call, the modified sds string is no longer valid and all the
  392. * references must be substituted with the new pointer returned by the call. */
  393. sds sdscatsds(sds s, const sds t) { return sdscatlen(s, t, sdslen(t)); }
  394. /* Destructively modify the sds string 's' to hold the specified binary
  395. * safe string pointed by 't' of length 'len' bytes. */
  396. sds sdscpylen(sds s, const char* t, size_t len)
  397. {
  398. if (sdsalloc(s) < len) {
  399. s = sdsMakeRoomFor(s, len - sdslen(s));
  400. if (s == NULL)
  401. return NULL;
  402. }
  403. memcpy(s, t, len);
  404. s[len] = '\0';
  405. sdssetlen(s, len);
  406. return s;
  407. }
  408. /* Like sdscpylen() but 't' must be a null-termined string so that the length
  409. * of the string is obtained with strlen(). */
  410. sds sdscpy(sds s, const char* t) { return sdscpylen(s, t, strlen(t)); }
  411. /* Helper for sdscatlonglong() doing the actual number -> string
  412. * conversion. 's' must point to a string with room for at least
  413. * SDS_LLSTR_SIZE bytes.
  414. *
  415. * The function returns the length of the null-terminated string
  416. * representation stored at 's'. */
  417. #define SDS_LLSTR_SIZE 21
  418. int sdsll2str(char* s, long long value)
  419. {
  420. char *p, aux;
  421. unsigned long long v;
  422. size_t l;
  423. /* Generate the string representation, this method produces
  424. * an reversed string. */
  425. v = (value < 0) ? -value : value;
  426. p = s;
  427. do {
  428. *p++ = '0' + (v % 10);
  429. v /= 10;
  430. } while (v);
  431. if (value < 0)
  432. *p++ = '-';
  433. /* Compute length and add null term. */
  434. l = p - s;
  435. *p = '\0';
  436. /* Reverse the string. */
  437. p--;
  438. while (s < p) {
  439. aux = *s;
  440. *s = *p;
  441. *p = aux;
  442. s++;
  443. p--;
  444. }
  445. return l;
  446. }
  447. /* Identical sdsll2str(), but for unsigned long long type. */
  448. int sdsull2str(char* s, unsigned long long v)
  449. {
  450. char *p, aux;
  451. size_t l;
  452. /* Generate the string representation, this method produces
  453. * an reversed string. */
  454. p = s;
  455. do {
  456. *p++ = '0' + (v % 10);
  457. v /= 10;
  458. } while (v);
  459. /* Compute length and add null term. */
  460. l = p - s;
  461. *p = '\0';
  462. /* Reverse the string. */
  463. p--;
  464. while (s < p) {
  465. aux = *s;
  466. *s = *p;
  467. *p = aux;
  468. s++;
  469. p--;
  470. }
  471. return l;
  472. }
  473. /* Create an sds string from a long long value. It is much faster than:
  474. *
  475. * sdscatprintf(sdsempty(),"%lld\n", value);
  476. */
  477. sds sdsfromlonglong(long long value)
  478. {
  479. char buf[SDS_LLSTR_SIZE];
  480. int len = sdsll2str(buf, value);
  481. return sdsnewlen(buf, len);
  482. }
  483. /* Like sdscatprintf() but gets va_list instead of being variadic. */
  484. sds sdscatvprintf(sds s, const char* fmt, va_list ap)
  485. {
  486. va_list cpy;
  487. char staticbuf[1024], *buf = staticbuf, *t;
  488. size_t buflen = strlen(fmt) * 2;
  489. /* We try to start using a static buffer for speed.
  490. * If not possible we revert to heap allocation. */
  491. if (buflen > sizeof(staticbuf)) {
  492. buf = s_malloc(buflen);
  493. if (buf == NULL)
  494. return NULL;
  495. } else {
  496. buflen = sizeof(staticbuf);
  497. }
  498. /* Try with buffers two times bigger every time we fail to
  499. * fit the string in the current buffer size. */
  500. while (1) {
  501. buf[buflen - 2] = '\0';
  502. va_copy(cpy, ap);
  503. vsnprintf(buf, buflen, fmt, cpy);
  504. va_end(cpy);
  505. if (buf[buflen - 2] != '\0') {
  506. if (buf != staticbuf)
  507. s_free(buf);
  508. buflen *= 2;
  509. buf = s_malloc(buflen);
  510. if (buf == NULL)
  511. return NULL;
  512. continue;
  513. }
  514. break;
  515. }
  516. /* Finally concat the obtained string to the SDS string and return it. */
  517. t = sdscat(s, buf);
  518. if (buf != staticbuf)
  519. s_free(buf);
  520. return t;
  521. }
  522. /* Append to the sds string 's' a string obtained using printf-alike format
  523. * specifier.
  524. *
  525. * After the call, the modified sds string is no longer valid and all the
  526. * references must be substituted with the new pointer returned by the call.
  527. *
  528. * Example:
  529. *
  530. * s = sdsnew("Sum is: ");
  531. * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
  532. *
  533. * Often you need to create a string from scratch with the printf-alike
  534. * format. When this is the need, just use sdsempty() as the target string:
  535. *
  536. * s = sdscatprintf(sdsempty(), "... your format ...", args);
  537. */
  538. sds sdscatprintf(sds s, const char* fmt, ...)
  539. {
  540. va_list ap;
  541. char* t;
  542. va_start(ap, fmt);
  543. t = sdscatvprintf(s, fmt, ap);
  544. va_end(ap);
  545. return t;
  546. }
  547. /* This function is similar to sdscatprintf, but much faster as it does
  548. * not rely on sprintf() family functions implemented by the libc that
  549. * are often very slow. Moreover directly handling the sds string as
  550. * new data is concatenated provides a performance improvement.
  551. *
  552. * However this function only handles an incompatible subset of printf-alike
  553. * format specifiers:
  554. *
  555. * %s - C String
  556. * %S - SDS string
  557. * %i - signed int
  558. * %I - 64 bit signed integer (long long, int64_t)
  559. * %u - unsigned int
  560. * %U - 64 bit unsigned integer (unsigned long long, uint64_t)
  561. * %% - Verbatim "%" character.
  562. */
  563. sds sdscatfmt(sds s, char const* fmt, ...)
  564. {
  565. size_t initlen = sdslen(s);
  566. const char* f = fmt;
  567. int i;
  568. va_list ap;
  569. va_start(ap, fmt);
  570. f = fmt; /* Next format specifier byte to process. */
  571. i = initlen; /* Position of the next byte to write to dest str. */
  572. while (*f) {
  573. char next, *str;
  574. size_t l;
  575. long long num;
  576. unsigned long long unum;
  577. /* Make sure there is always space for at least 1 char. */
  578. if (sdsavail(s) == 0) {
  579. s = sdsMakeRoomFor(s, 1);
  580. }
  581. switch (*f) {
  582. case '%':
  583. next = *(f + 1);
  584. f++;
  585. switch (next) {
  586. case 's':
  587. case 'S':
  588. str = va_arg(ap, char*);
  589. l = (next == 's') ? strlen(str) : sdslen(str);
  590. if (sdsavail(s) < l) {
  591. s = sdsMakeRoomFor(s, l);
  592. }
  593. memcpy(s + i, str, l);
  594. sdsinclen(s, l);
  595. i += l;
  596. break;
  597. case 'i':
  598. case 'I':
  599. if (next == 'i')
  600. num = va_arg(ap, int);
  601. else
  602. num = va_arg(ap, long long);
  603. {
  604. char buf[SDS_LLSTR_SIZE];
  605. l = sdsll2str(buf, num);
  606. if (sdsavail(s) < l) {
  607. s = sdsMakeRoomFor(s, l);
  608. }
  609. memcpy(s + i, buf, l);
  610. sdsinclen(s, l);
  611. i += l;
  612. }
  613. break;
  614. case 'u':
  615. case 'U':
  616. if (next == 'u')
  617. unum = va_arg(ap, unsigned int);
  618. else
  619. unum = va_arg(ap, unsigned long long);
  620. {
  621. char buf[SDS_LLSTR_SIZE];
  622. l = sdsull2str(buf, unum);
  623. if (sdsavail(s) < l) {
  624. s = sdsMakeRoomFor(s, l);
  625. }
  626. memcpy(s + i, buf, l);
  627. sdsinclen(s, l);
  628. i += l;
  629. }
  630. break;
  631. default: /* Handle %% and generally %<unknown>. */
  632. s[i++] = next;
  633. sdsinclen(s, 1);
  634. break;
  635. }
  636. break;
  637. default:
  638. s[i++] = *f;
  639. sdsinclen(s, 1);
  640. break;
  641. }
  642. f++;
  643. }
  644. va_end(ap);
  645. /* Add null-term */
  646. s[i] = '\0';
  647. return s;
  648. }
  649. /* Remove the part of the string from left and from right composed just of
  650. * contiguous characters found in 'cset', that is a null terminted C string.
  651. *
  652. * After the call, the modified sds string is no longer valid and all the
  653. * references must be substituted with the new pointer returned by the call.
  654. *
  655. * Example:
  656. *
  657. * s = sdsnew("AA...AA.a.aa.aHelloWorld :::");
  658. * s = sdstrim(s,"Aa. :");
  659. * printf("%s\n", s);
  660. *
  661. * Output will be just "Hello World".
  662. */
  663. sds sdstrim(sds s, const char* cset)
  664. {
  665. char *start, *end, *sp, *ep;
  666. size_t len;
  667. sp = start = s;
  668. ep = end = s + sdslen(s) - 1;
  669. while (sp <= end && strchr(cset, *sp))
  670. sp++;
  671. while (ep > sp && strchr(cset, *ep))
  672. ep--;
  673. len = (sp > ep) ? 0 : ((ep - sp) + 1);
  674. if (s != sp)
  675. memmove(s, sp, len);
  676. s[len] = '\0';
  677. sdssetlen(s, len);
  678. return s;
  679. }
  680. /* Turn the string into a smaller (or equal) string containing only the
  681. * substring specified by the 'start' and 'end' indexes.
  682. *
  683. * start and end can be negative, where -1 means the last character of the
  684. * string, -2 the penultimate character, and so forth.
  685. *
  686. * The interval is inclusive, so the start and end characters will be part
  687. * of the resulting string.
  688. *
  689. * The string is modified in-place.
  690. *
  691. * Example:
  692. *
  693. * s = sdsnew("Hello World");
  694. * sdsrange(s,1,-1); => "ello World"
  695. */
  696. void sdsrange(sds s, int start, int end)
  697. {
  698. size_t newlen, len = sdslen(s);
  699. if (len == 0)
  700. return;
  701. if (start < 0) {
  702. start = len + start;
  703. if (start < 0)
  704. start = 0;
  705. }
  706. if (end < 0) {
  707. end = len + end;
  708. if (end < 0)
  709. end = 0;
  710. }
  711. newlen = (start > end) ? 0 : (end - start) + 1;
  712. if (newlen != 0) {
  713. if (start >= (signed) len) {
  714. newlen = 0;
  715. } else if (end >= (signed) len) {
  716. end = len - 1;
  717. newlen = (start > end) ? 0 : (end - start) + 1;
  718. }
  719. } else {
  720. start = 0;
  721. }
  722. if (start && newlen)
  723. memmove(s, s + start, newlen);
  724. s[newlen] = 0;
  725. sdssetlen(s, newlen);
  726. }
  727. /* Apply tolower() to every character of the sds string 's'. */
  728. void sdstolower(sds s)
  729. {
  730. int len = sdslen(s), j;
  731. for (j = 0; j < len; j++)
  732. s[j] = tolower(s[j]);
  733. }
  734. /* Apply toupper() to every character of the sds string 's'. */
  735. void sdstoupper(sds s)
  736. {
  737. int len = sdslen(s), j;
  738. for (j = 0; j < len; j++)
  739. s[j] = toupper(s[j]);
  740. }
  741. /* Compare two sds strings s1 and s2 with memcmp().
  742. *
  743. * Return value:
  744. *
  745. * positive if s1 > s2.
  746. * negative if s1 < s2.
  747. * 0 if s1 and s2 are exactly the same binary string.
  748. *
  749. * If two strings share exactly the same prefix, but one of the two has
  750. * additional characters, the longer string is considered to be greater than
  751. * the smaller one. */
  752. int sdscmp(const sds s1, const sds s2)
  753. {
  754. size_t l1, l2, minlen;
  755. int cmp;
  756. l1 = sdslen(s1);
  757. l2 = sdslen(s2);
  758. minlen = (l1 < l2) ? l1 : l2;
  759. cmp = memcmp(s1, s2, minlen);
  760. if (cmp == 0)
  761. return l1 - l2;
  762. return cmp;
  763. }
  764. /* Split 's' with separator in 'sep'. An array
  765. * of sds strings is returned. *count will be set
  766. * by reference to the number of tokens returned.
  767. *
  768. * On out of memory, zero length string, zero length
  769. * separator, NULL is returned.
  770. *
  771. * Note that 'sep' is able to split a string using
  772. * a multi-character separator. For example
  773. * sdssplit("foo_-_bar","_-_"); will return two
  774. * elements "foo" and "bar".
  775. *
  776. * This version of the function is binary-safe but
  777. * requires length arguments. sdssplit() is just the
  778. * same function but for zero-terminated strings.
  779. */
  780. sds* sdssplitlen(
  781. const char* s, int len, const char* sep, int seplen, int* count)
  782. {
  783. int elements = 0, slots = 5, start = 0, j;
  784. sds* tokens;
  785. if (seplen < 1 || len < 0)
  786. return NULL;
  787. tokens = s_malloc(sizeof(sds) * slots);
  788. if (tokens == NULL)
  789. return NULL;
  790. if (len == 0) {
  791. *count = 0;
  792. return tokens;
  793. }
  794. for (j = 0; j < (len - (seplen - 1)); j++) {
  795. /* make sure there is room for the next element and the final one */
  796. if (slots < elements + 2) {
  797. sds* newtokens;
  798. slots *= 2;
  799. newtokens = s_realloc(tokens, sizeof(sds) * slots);
  800. if (newtokens == NULL)
  801. goto cleanup;
  802. tokens = newtokens;
  803. }
  804. /* search the separator */
  805. if ((seplen == 1 && *(s + j) == sep[0]) ||
  806. (memcmp(s + j, sep, seplen) == 0)) {
  807. tokens[elements] = sdsnewlen(s + start, j - start);
  808. if (tokens[elements] == NULL)
  809. goto cleanup;
  810. elements++;
  811. start = j + seplen;
  812. j = j + seplen - 1; /* skip the separator */
  813. }
  814. }
  815. /* Add the final element. We are sure there is room in the tokens array. */
  816. tokens[elements] = sdsnewlen(s + start, len - start);
  817. if (tokens[elements] == NULL)
  818. goto cleanup;
  819. elements++;
  820. *count = elements;
  821. return tokens;
  822. cleanup: {
  823. int i;
  824. for (i = 0; i < elements; i++)
  825. sdsfree(tokens[i]);
  826. s_free(tokens);
  827. *count = 0;
  828. return NULL;
  829. }
  830. }
  831. /* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL.
  832. */
  833. void sdsfreesplitres(sds* tokens, int count)
  834. {
  835. if (!tokens)
  836. return;
  837. while (count--)
  838. sdsfree(tokens[count]);
  839. s_free(tokens);
  840. }
  841. /* Append to the sds string "s" an escaped string representation where
  842. * all the non-printable characters (tested with isprint()) are turned into
  843. * escapes in the form "\n\r\a...." or "\x<hex-number>".
  844. *
  845. * After the call, the modified sds string is no longer valid and all the
  846. * references must be substituted with the new pointer returned by the call. */
  847. sds sdscatrepr(sds s, const char* p, size_t len)
  848. {
  849. s = sdscatlen(s, "\"", 1);
  850. while (len--) {
  851. switch (*p) {
  852. case '\\':
  853. case '"':
  854. s = sdscatprintf(s, "\\%c", *p);
  855. break;
  856. case '\n':
  857. s = sdscatlen(s, "\\n", 2);
  858. break;
  859. case '\r':
  860. s = sdscatlen(s, "\\r", 2);
  861. break;
  862. case '\t':
  863. s = sdscatlen(s, "\\t", 2);
  864. break;
  865. case '\a':
  866. s = sdscatlen(s, "\\a", 2);
  867. break;
  868. case '\b':
  869. s = sdscatlen(s, "\\b", 2);
  870. break;
  871. default:
  872. if (isprint(*p))
  873. s = sdscatprintf(s, "%c", *p);
  874. else
  875. s = sdscatprintf(s, "\\x%02x", (unsigned char) *p);
  876. break;
  877. }
  878. p++;
  879. }
  880. return sdscatlen(s, "\"", 1);
  881. }
  882. /* Helper function for sdssplitargs() that returns non zero if 'c'
  883. * is a valid hex digit. */
  884. int is_hex_digit(char c)
  885. {
  886. return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  887. (c >= 'A' && c <= 'F');
  888. }
  889. /* Helper function for sdssplitargs() that converts a hex digit into an
  890. * integer from 0 to 15 */
  891. int hex_digit_to_int(char c)
  892. {
  893. switch (c) {
  894. case '0':
  895. return 0;
  896. case '1':
  897. return 1;
  898. case '2':
  899. return 2;
  900. case '3':
  901. return 3;
  902. case '4':
  903. return 4;
  904. case '5':
  905. return 5;
  906. case '6':
  907. return 6;
  908. case '7':
  909. return 7;
  910. case '8':
  911. return 8;
  912. case '9':
  913. return 9;
  914. case 'a':
  915. case 'A':
  916. return 10;
  917. case 'b':
  918. case 'B':
  919. return 11;
  920. case 'c':
  921. case 'C':
  922. return 12;
  923. case 'd':
  924. case 'D':
  925. return 13;
  926. case 'e':
  927. case 'E':
  928. return 14;
  929. case 'f':
  930. case 'F':
  931. return 15;
  932. default:
  933. return 0;
  934. }
  935. }
  936. /* Split a line into arguments, where every argument can be in the
  937. * following programming-language REPL-alike form:
  938. *
  939. * foo bar "newline are supported\n" and "\xff\x00otherstuff"
  940. *
  941. * The number of arguments is stored into *argc, and an array
  942. * of sds is returned.
  943. *
  944. * The caller should free the resulting array of sds strings with
  945. * sdsfreesplitres().
  946. *
  947. * Note that sdscatrepr() is able to convert back a string into
  948. * a quoted string in the same format sdssplitargs() is able to parse.
  949. *
  950. * The function returns the allocated tokens on success, even when the
  951. * input string is empty, or NULL if the input contains unbalanced
  952. * quotes or closed quotes followed by non space characters
  953. * as in: "foo"bar or "foo'
  954. */
  955. sds* sdssplitargs(const char* line, int* argc)
  956. {
  957. const char* p = line;
  958. char* current = NULL;
  959. char** vector = NULL;
  960. *argc = 0;
  961. while (1) {
  962. /* skip blanks */
  963. while (*p && isspace(*p))
  964. p++;
  965. if (*p) {
  966. /* get a token */
  967. int inq = 0; /* set to 1 if we are in "quotes" */
  968. int insq = 0; /* set to 1 if we are in 'single quotes' */
  969. int done = 0;
  970. if (current == NULL)
  971. current = sdsempty();
  972. while (!done) {
  973. if (inq) {
  974. if (*p == '\\' && *(p + 1) == 'x' &&
  975. is_hex_digit(*(p + 2)) && is_hex_digit(*(p + 3))) {
  976. unsigned char byte;
  977. byte = (hex_digit_to_int(*(p + 2)) * 16) +
  978. hex_digit_to_int(*(p + 3));
  979. current = sdscatlen(current, (char*) &byte, 1);
  980. p += 3;
  981. } else if (*p == '\\' && *(p + 1)) {
  982. char c;
  983. p++;
  984. switch (*p) {
  985. case 'n':
  986. c = '\n';
  987. break;
  988. case 'r':
  989. c = '\r';
  990. break;
  991. case 't':
  992. c = '\t';
  993. break;
  994. case 'b':
  995. c = '\b';
  996. break;
  997. case 'a':
  998. c = '\a';
  999. break;
  1000. default:
  1001. c = *p;
  1002. break;
  1003. }
  1004. current = sdscatlen(current, &c, 1);
  1005. } else if (*p == '"') {
  1006. /* closing quote must be followed by a space or
  1007. * nothing at all. */
  1008. if (*(p + 1) && !isspace(*(p + 1)))
  1009. goto err;
  1010. done = 1;
  1011. } else if (!*p) {
  1012. /* unterminated quotes */
  1013. goto err;
  1014. } else {
  1015. current = sdscatlen(current, p, 1);
  1016. }
  1017. } else if (insq) {
  1018. if (*p == '\\' && *(p + 1) == '\'') {
  1019. p++;
  1020. current = sdscatlen(current, "'", 1);
  1021. } else if (*p == '\'') {
  1022. /* closing quote must be followed by a space or
  1023. * nothing at all. */
  1024. if (*(p + 1) && !isspace(*(p + 1)))
  1025. goto err;
  1026. done = 1;
  1027. } else if (!*p) {
  1028. /* unterminated quotes */
  1029. goto err;
  1030. } else {
  1031. current = sdscatlen(current, p, 1);
  1032. }
  1033. } else {
  1034. switch (*p) {
  1035. case ' ':
  1036. case '\n':
  1037. case '\r':
  1038. case '\t':
  1039. case '\0':
  1040. done = 1;
  1041. break;
  1042. case '"':
  1043. inq = 1;
  1044. break;
  1045. case '\'':
  1046. insq = 1;
  1047. break;
  1048. default:
  1049. current = sdscatlen(current, p, 1);
  1050. break;
  1051. }
  1052. }
  1053. if (*p)
  1054. p++;
  1055. }
  1056. /* add the token to the vector */
  1057. vector = s_realloc(vector, ((*argc) + 1) * sizeof(char*));
  1058. vector[*argc] = current;
  1059. (*argc)++;
  1060. current = NULL;
  1061. } else {
  1062. /* Even on empty input string return something not NULL. */
  1063. if (vector == NULL)
  1064. vector = s_malloc(sizeof(void*));
  1065. return vector;
  1066. }
  1067. }
  1068. err:
  1069. while ((*argc)--)
  1070. sdsfree(vector[*argc]);
  1071. s_free(vector);
  1072. if (current)
  1073. sdsfree(current);
  1074. *argc = 0;
  1075. return NULL;
  1076. }
  1077. /* Modify the string substituting all the occurrences of the set of
  1078. * characters specified in the 'from' string to the corresponding character
  1079. * in the 'to' array.
  1080. *
  1081. * For instance: sdsmapchars(mystring, "ho", "01", 2)
  1082. * will have the effect of turning the string "hello" into "0ell1".
  1083. *
  1084. * The function returns the sds string pointer, that is always the same
  1085. * as the input pointer since no resize is needed. */
  1086. sds sdsmapchars(sds s, const char* from, const char* to, size_t setlen)
  1087. {
  1088. size_t j, i, l = sdslen(s);
  1089. for (j = 0; j < l; j++) {
  1090. for (i = 0; i < setlen; i++) {
  1091. if (s[j] == from[i]) {
  1092. s[j] = to[i];
  1093. break;
  1094. }
  1095. }
  1096. }
  1097. return s;
  1098. }
  1099. /* Join an array of C strings using the specified separator (also a C string).
  1100. * Returns the result as an sds string. */
  1101. sds sdsjoin(char** argv, int argc, char* sep)
  1102. {
  1103. sds join = sdsempty();
  1104. int j;
  1105. for (j = 0; j < argc; j++) {
  1106. join = sdscat(join, argv[j]);
  1107. if (j != argc - 1)
  1108. join = sdscat(join, sep);
  1109. }
  1110. return join;
  1111. }
  1112. /* Like sdsjoin, but joins an array of SDS strings. */
  1113. sds sdsjoinsds(sds* argv, int argc, const char* sep, size_t seplen)
  1114. {
  1115. sds join = sdsempty();
  1116. int j;
  1117. for (j = 0; j < argc; j++) {
  1118. join = sdscatsds(join, argv[j]);
  1119. if (j != argc - 1)
  1120. join = sdscatlen(join, sep, seplen);
  1121. }
  1122. return join;
  1123. }
  1124. #if defined(SDS_TEST_MAIN)
  1125. #include <stdio.h>
  1126. #include "testhelp.h"
  1127. #include "limits.h"
  1128. #define UNUSED(x) (void)(x)
  1129. int sdsTest(void)
  1130. {
  1131. {
  1132. sds x = sdsnew("foo"), y;
  1133. test_cond("Create a string and obtain the length",
  1134. sdslen(x) == 3 && memcmp(x, "foo\0", 4) == 0)
  1135. sdsfree(x);
  1136. x = sdsnewlen("foo", 2);
  1137. test_cond("Create a string with specified length",
  1138. sdslen(x) == 2 && memcmp(x, "fo\0", 3) == 0)
  1139. x = sdscat(x, "bar");
  1140. test_cond("Strings concatenation",
  1141. sdslen(x) == 5 && memcmp(x, "fobar\0", 6) == 0);
  1142. x = sdscpy(x, "a");
  1143. test_cond("sdscpy() against an originally longer string",
  1144. sdslen(x) == 1 && memcmp(x, "a\0", 2) == 0)
  1145. x = sdscpy(x, "xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk");
  1146. test_cond("sdscpy() against an originally shorter string",
  1147. sdslen(x) == 33 &&
  1148. memcmp(x, "xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0", 33) == 0)
  1149. sdsfree(x);
  1150. x = sdscatprintf(sdsempty(), "%d", 123);
  1151. test_cond("sdscatprintf() seems working in the base case",
  1152. sdslen(x) == 3 && memcmp(x, "123\0", 4) == 0)
  1153. sdsfree(x);
  1154. x = sdsnew("--");
  1155. x = sdscatfmt(x, "Hello %s World %I,%I--", "Hi!", LLONG_MIN, LLONG_MAX);
  1156. test_cond("sdscatfmt() seems working in the base case",
  1157. sdslen(x) == 60 &&
  1158. memcmp(x,
  1159. "--Hello Hi! World -9223372036854775808,"
  1160. "9223372036854775807--",
  1161. 60) == 0) printf("[%s]\n", x);
  1162. sdsfree(x);
  1163. x = sdsnew("--");
  1164. x = sdscatfmt(x, "%u,%U--", UINT_MAX, ULLONG_MAX);
  1165. test_cond("sdscatfmt() seems working with unsigned numbers",
  1166. sdslen(x) == 35 &&
  1167. memcmp(x, "--4294967295,18446744073709551615--", 35) == 0)
  1168. sdsfree(x);
  1169. x = sdsnew(" x ");
  1170. sdstrim(x, " x");
  1171. test_cond("sdstrim() works when all chars match", sdslen(x) == 0)
  1172. sdsfree(x);
  1173. x = sdsnew(" x ");
  1174. sdstrim(x, " ");
  1175. test_cond("sdstrim() works when a single char remains",
  1176. sdslen(x) == 1 && x[0] == 'x')
  1177. sdsfree(x);
  1178. x = sdsnew("xxciaoyyy");
  1179. sdstrim(x, "xy");
  1180. test_cond("sdstrim() correctly trims characters",
  1181. sdslen(x) == 4 && memcmp(x, "ciao\0", 5) == 0)
  1182. y = sdsdup(x);
  1183. sdsrange(y, 1, 1);
  1184. test_cond(
  1185. "sdsrange(...,1,1)", sdslen(y) == 1 && memcmp(y, "i\0", 2) == 0)
  1186. sdsfree(y);
  1187. y = sdsdup(x);
  1188. sdsrange(y, 1, -1);
  1189. test_cond(
  1190. "sdsrange(...,1,-1)", sdslen(y) == 3 && memcmp(y, "iao\0", 4) == 0)
  1191. sdsfree(y);
  1192. y = sdsdup(x);
  1193. sdsrange(y, -2, -1);
  1194. test_cond(
  1195. "sdsrange(...,-2,-1)", sdslen(y) == 2 && memcmp(y, "ao\0", 3) == 0)
  1196. sdsfree(y);
  1197. y = sdsdup(x);
  1198. sdsrange(y, 2, 1);
  1199. test_cond(
  1200. "sdsrange(...,2,1)", sdslen(y) == 0 && memcmp(y, "\0", 1) == 0)
  1201. sdsfree(y);
  1202. y = sdsdup(x);
  1203. sdsrange(y, 1, 100);
  1204. test_cond(
  1205. "sdsrange(...,1,100)", sdslen(y) == 3 && memcmp(y, "iao\0", 4) == 0)
  1206. sdsfree(y);
  1207. y = sdsdup(x);
  1208. sdsrange(y, 100, 100);
  1209. test_cond(
  1210. "sdsrange(...,100,100)", sdslen(y) == 0 && memcmp(y, "\0", 1) == 0)
  1211. sdsfree(y);
  1212. sdsfree(x);
  1213. x = sdsnew("foo");
  1214. y = sdsnew("foa");
  1215. test_cond("sdscmp(foo,foa)", sdscmp(x, y) > 0)
  1216. sdsfree(y);
  1217. sdsfree(x);
  1218. x = sdsnew("bar");
  1219. y = sdsnew("bar");
  1220. test_cond("sdscmp(bar,bar)", sdscmp(x, y) == 0)
  1221. sdsfree(y);
  1222. sdsfree(x);
  1223. x = sdsnew("aar");
  1224. y = sdsnew("bar");
  1225. test_cond("sdscmp(bar,bar)", sdscmp(x, y) < 0)
  1226. sdsfree(y);
  1227. sdsfree(x);
  1228. x = sdsnewlen("\a\n\0foo\r", 7);
  1229. y = sdscatrepr(sdsempty(), x, sdslen(x));
  1230. test_cond("sdscatrepr(...data...)",
  1231. memcmp(y, "\"\\a\\n\\x00foo\\r\"", 15) == 0)
  1232. {
  1233. unsigned int oldfree;
  1234. char* p;
  1235. int step = 10, j, i;
  1236. sdsfree(x);
  1237. sdsfree(y);
  1238. x = sdsnew("0");
  1239. test_cond("sdsnew() free/len buffers",
  1240. sdslen(x) == 1 && sdsavail(x) == 0);
  1241. /* Run the test a few times in order to hit the first two
  1242. * SDS header types. */
  1243. for (i = 0; i < 10; i++) {
  1244. int oldlen = sdslen(x);
  1245. x = sdsMakeRoomFor(x, step);
  1246. int type = x[-1] & SDS_TYPE_MASK;
  1247. test_cond("sdsMakeRoomFor() len", sdslen(x) == oldlen);
  1248. if (type != SDS_TYPE_5) {
  1249. test_cond("sdsMakeRoomFor() free", sdsavail(x) >= step);
  1250. oldfree = sdsavail(x);
  1251. }
  1252. p = x + oldlen;
  1253. for (j = 0; j < step; j++) {
  1254. p[j] = 'A' + j;
  1255. }
  1256. sdsIncrLen(x, step);
  1257. }
  1258. test_cond("sdsMakeRoomFor() content",
  1259. memcmp(
  1260. "0ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFG"
  1261. "HIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ",
  1262. x, 101) == 0);
  1263. test_cond("sdsMakeRoomFor() final length", sdslen(x) == 101);
  1264. sdsfree(x);
  1265. }
  1266. }
  1267. test_report() return 0;
  1268. }
  1269. #endif
  1270. #ifdef SDS_TEST_MAIN
  1271. int main(void) { return sdsTest(); }
  1272. #endif