aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/src/mstr.c
diff options
context:
space:
mode:
authorMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
committerMitja Felicijan <mitja.felicijan@gmail.com>2026-01-21 22:52:54 +0100
commitdcacc00e3750300617ba6e16eb346713f91a783a (patch)
tree38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/src/mstr.c
parent58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff)
downloadcrep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz
Remove testing data
Diffstat (limited to 'examples/redis-unstable/src/mstr.c')
-rw-r--r--examples/redis-unstable/src/mstr.c528
1 files changed, 0 insertions, 528 deletions
diff --git a/examples/redis-unstable/src/mstr.c b/examples/redis-unstable/src/mstr.c
deleted file mode 100644
index 97f7145..0000000
--- a/examples/redis-unstable/src/mstr.c
+++ /dev/null
@@ -1,528 +0,0 @@
1/*
2 * Copyright Redis Ltd. 2024 - present
3 *
4 * Licensed under your choice of (a) the Redis Source Available License 2.0
5 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
6 * GNU Affero General Public License v3 (AGPLv3).
7 */
8
9#include <string.h>
10#include <assert.h>
11#include "sdsalloc.h"
12#include "mstr.h"
13#include "stdio.h"
14
15#define NULL_SIZE 1
16
17static inline char mstrReqType(size_t string_size);
18static inline int mstrHdrSize(char type);
19static inline int mstrSumMetaLen(mstrKind *k, mstrFlags flags);
20static inline size_t mstrAllocLen(const mstr s, struct mstrKind *kind);
21
22/*** mstr API ***/
23
24/* Create mstr without any metadata attached, based on string 'initStr'.
25 * - If initStr equals NULL, then only allocation will be made.
26 * - string of mstr is always null-terminated.
27 */
28mstr mstrNew(const char *initStr, size_t lenStr, int trymalloc, size_t *usable) {
29 unsigned char *pInfo; /* pointer to mstr info field */
30 void *sh;
31 mstr s;
32 char type = mstrReqType(lenStr);
33 int mstrHdr = mstrHdrSize(type);
34
35 assert(lenStr + mstrHdr + 1 > lenStr); /* Catch size_t overflow */
36
37 size_t len = mstrHdr + lenStr + NULL_SIZE;
38 sh = trymalloc? s_trymalloc_usable(len, usable) : s_malloc_usable(len, usable);
39
40 if (sh == NULL) return NULL;
41
42 s = (char*)sh + mstrHdr;
43 pInfo = ((unsigned char*)s) - 1;
44
45 switch(type) {
46 case MSTR_TYPE_5: {
47 *pInfo = CREATE_MSTR_INFO(lenStr, 0 /*ismeta*/, type);
48 break;
49 }
50 case MSTR_TYPE_8: {
51 MSTR_HDR_VAR(8,s);
52 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 0 /*ismeta*/, type);
53 sh->len = lenStr;
54 break;
55 }
56 case MSTR_TYPE_16: {
57 MSTR_HDR_VAR(16,s);
58 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 0 /*ismeta*/, type);
59 sh->len = lenStr;
60 break;
61 }
62 case MSTR_TYPE_64: {
63 MSTR_HDR_VAR(64,s);
64 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 0 /*ismeta*/, type);
65 sh->len = lenStr;
66 break;
67 }
68 }
69
70 if (initStr && lenStr)
71 memcpy(s, initStr, lenStr);
72
73 s[lenStr] = '\0';
74 return s;
75}
76
77/* Creates mstr with given string. Reserve space for metadata.
78 *
79 * Note: mstrNew(s,l,u) and mstrNewWithMeta(s,l,0,u) are not the same. The first allocates
80 * just string. The second allocates a string with flags (yet without any metadata
81 * structures allocated).
82 */
83mstr mstrNewWithMeta(struct mstrKind *kind, const char *initStr, size_t lenStr, mstrFlags metaFlags, int trymalloc, size_t *usable) {
84 unsigned char *pInfo; /* pointer to mstr info field */
85 char *allocMstr;
86 mstr mstrPtr;
87 char type = mstrReqType(lenStr);
88 int mstrHdr = mstrHdrSize(type);
89 int sumMetaLen = mstrSumMetaLen(kind, metaFlags);
90
91
92 /* mstrSumMetaLen() + sizeof(mstrFlags) + sizeof(mstrhdrX) + lenStr */
93
94 size_t allocLen = sumMetaLen + sizeof(mstrFlags) + mstrHdr + lenStr + NULL_SIZE;
95 allocMstr = trymalloc? s_trymalloc_usable(allocLen, usable) : s_malloc_usable(allocLen, usable);
96
97 if (allocMstr == NULL) return NULL;
98
99 /* metadata is located at the beginning of the allocation, then meta-flags and lastly the string */
100 mstrFlags *pMetaFlags = (mstrFlags *) (allocMstr + sumMetaLen) ;
101 mstrPtr = ((char*) pMetaFlags) + sizeof(mstrFlags) + mstrHdr;
102 pInfo = ((unsigned char*)mstrPtr) - 1;
103
104 switch(type) {
105 case MSTR_TYPE_5: {
106 *pInfo = CREATE_MSTR_INFO(lenStr, 1 /*ismeta*/, type);
107 break;
108 }
109 case MSTR_TYPE_8: {
110 MSTR_HDR_VAR(8, mstrPtr);
111 sh->len = lenStr;
112 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 1 /*ismeta*/, type);
113 break;
114 }
115 case MSTR_TYPE_16: {
116 MSTR_HDR_VAR(16, mstrPtr);
117 sh->len = lenStr;
118 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 1 /*ismeta*/, type);
119 break;
120 }
121 case MSTR_TYPE_64: {
122 MSTR_HDR_VAR(64, mstrPtr);
123 sh->len = lenStr;
124 *pInfo = CREATE_MSTR_INFO(0 /*unused*/, 1 /*ismeta*/, type);
125 break;
126 }
127 }
128 *pMetaFlags = metaFlags;
129 if (initStr != NULL) memcpy(mstrPtr, initStr, lenStr);
130 mstrPtr[lenStr] = '\0';
131
132 return mstrPtr;
133}
134
135/* Create copy of mstr. Flags can be modified. For each metadata flag, if
136 * same flag is set on both, then copy its metadata. */
137mstr mstrNewCopy(struct mstrKind *kind, mstr src, mstrFlags newFlags, size_t *usable) {
138 mstr dst;
139
140 /* if no flags are set, then just copy the string */
141 if (newFlags == 0) return mstrNew(src, mstrlen(src), 0, usable);
142
143 dst = mstrNewWithMeta(kind, src, mstrlen(src), newFlags, 0, usable);
144 memcpy(dst, src, mstrlen(src) + 1);
145
146 /* if metadata is attached to src, then selectively copy metadata */
147 if (mstrIsMetaAttached(src)) {
148 mstrFlags *pFlags1 = mstrFlagsRef(src),
149 *pFlags2 = mstrFlagsRef(dst);
150
151 mstrFlags flags1Shift = *pFlags1,
152 flags2Shift = *pFlags2;
153
154 unsigned char *at1 = ((unsigned char *) pFlags1),
155 *at2 = ((unsigned char *) pFlags2);
156
157 /* if the flag is set on both, then copy the metadata */
158 for (int i = 0; flags1Shift != 0; ++i) {
159 int isFlag1Set = flags1Shift & 0x1;
160 int isFlag2Set = flags2Shift & 0x1;
161
162 if (isFlag1Set) at1 -= kind->metaSize[i];
163 if (isFlag2Set) at2 -= kind->metaSize[i];
164
165 if (isFlag1Set && isFlag2Set)
166 memcpy(at2, at1, kind->metaSize[i]);
167 flags1Shift >>= 1;
168 flags2Shift >>= 1;
169 }
170 }
171 return dst;
172}
173
174/* Free mstring. Note, mstrKind is required to eval sizeof metadata and find start
175 * of allocation but if mstrIsMetaAttached(s) is false, you can pass NULL as well.
176 */
177void mstrFree(struct mstrKind *kind, mstr s, size_t *usable) {
178 size_t oldsize = 0;
179 if (s != NULL)
180 s_free_usable(mstrGetAllocPtr(kind, s), &oldsize);
181 if (usable != NULL) *usable = oldsize;
182}
183
184/* return ref to metadata flags. Useful to modify directly flags which doesn't
185 * include metadata payload */
186mstrFlags *mstrFlagsRef(mstr s) {
187 switch(s[-1]&MSTR_TYPE_MASK) {
188 case MSTR_TYPE_5:
189 return ((mstrFlags *) (s - sizeof(struct mstrhdr5))) - 1;
190 case MSTR_TYPE_8:
191 return ((mstrFlags *) (s - sizeof(struct mstrhdr8))) - 1;
192 case MSTR_TYPE_16:
193 return ((mstrFlags *) (s - sizeof(struct mstrhdr16))) - 1;
194 default: /* MSTR_TYPE_64: */
195 return ((mstrFlags *) (s - sizeof(struct mstrhdr64))) - 1;
196 }
197}
198
199/* Return a reference to corresponding metadata of the specified metadata flag
200 * index (flagIdx). If the metadata doesn't exist, it still returns a reference
201 * to the starting location where it would have been written among other metadatas.
202 * To verify if `flagIdx` of some metadata is attached, use `mstrGetFlag(s, flagIdx)`.
203 */
204void *mstrMetaRef(mstr s, struct mstrKind *kind, int flagIdx) {
205 int metaOffset = 0;
206 /* start iterating from flags backward */
207 mstrFlags *pFlags = mstrFlagsRef(s);
208 mstrFlags tmp = *pFlags;
209
210 for (int i = 0 ; i <= flagIdx ; ++i) {
211 if (tmp & 0x1) metaOffset += kind->metaSize[i];
212 tmp >>= 1;
213 }
214 return ((char *)pFlags) - metaOffset;
215}
216
217/* mstr layout: [meta-data#N]...[meta-data#0][mstrFlags][mstrhdr][string][null] */
218void *mstrGetAllocPtr(struct mstrKind *kind, mstr str) {
219 if (!mstrIsMetaAttached(str))
220 return (char*)str - mstrHdrSize(str[-1]);
221
222 int totalMetaLen = mstrSumMetaLen(kind, *mstrFlagsRef(str));
223 return (char*)str - mstrHdrSize(str[-1]) - sizeof(mstrFlags) - totalMetaLen;
224}
225
226/* Prints in the following fashion:
227 * [0x7f8bd8816017] my_mstr: foo (strLen=3, mstrLen=11, isMeta=1, metaFlags=0x1)
228 * [0x7f8bd8816010] >> meta[0]: 0x78 0x56 0x34 0x12 (metaLen=4)
229 */
230void mstrPrint(mstr s, struct mstrKind *kind, int verbose) {
231 mstrFlags mflags, tmp;
232 int isMeta = mstrIsMetaAttached(s);
233
234 tmp = mflags = (isMeta) ? *mstrFlagsRef(s) : 0;
235
236 if (!isMeta) {
237 printf("[%p] %s: %s (strLen=%zu, mstrLen=%zu, isMeta=0)\n",
238 (void *)s, kind->name, s, mstrlen(s), mstrAllocLen(s, kind));
239 return;
240 }
241
242 printf("[%p] %s: %s (strLen=%zu, mstrLen=%zu, isMeta=1, metaFlags=0x%x)\n",
243 (void *)s, kind->name, s, mstrlen(s), mstrAllocLen(s, kind), mflags);
244
245 if (verbose) {
246 for (unsigned int i = 0 ; i < NUM_MSTR_FLAGS ; ++i) {
247 if (tmp & 0x1) {
248 int mSize = kind->metaSize[i];
249 void *mRef = mstrMetaRef(s, kind, i);
250 printf("[%p] >> meta[%d]:", mRef, i);
251 for (int j = 0 ; j < mSize ; ++j) {
252 printf(" 0x%02x", ((unsigned char *) mRef)[j]);
253 }
254 printf(" (metaLen=%d)\n", mSize);
255 }
256 tmp >>= 1;
257 }
258 }
259}
260
261/* return length of the string (ignoring metadata attached) */
262size_t mstrlen(const mstr s) {
263 unsigned char info = s[-1];
264 switch(info & MSTR_TYPE_MASK) {
265 case MSTR_TYPE_5:
266 return MSTR_TYPE_5_LEN(info);
267 case MSTR_TYPE_8:
268 return MSTR_HDR(8,s)->len;
269 case MSTR_TYPE_16:
270 return MSTR_HDR(16,s)->len;
271 default: /* MSTR_TYPE_64: */
272 return MSTR_HDR(64,s)->len;
273 }
274}
275
276/*** mstr internals ***/
277
278static inline int mstrSumMetaLen(mstrKind *k, mstrFlags flags) {
279 int total = 0;
280 int i = 0 ;
281 while (flags) {
282 total += (flags & 0x1) ? k->metaSize[i] : 0;
283 flags >>= 1;
284 ++i;
285 }
286 return total;
287}
288
289/* mstrSumMetaLen() + sizeof(mstrFlags) + sizeof(mstrhdrX) + strlen + '\0' */
290static inline size_t mstrAllocLen(const mstr s, struct mstrKind *kind) {
291 int hdrlen;
292 mstrFlags *pMetaFlags;
293 size_t strlen = 0;
294
295 int isMeta = mstrIsMetaAttached(s);
296 unsigned char info = s[-1];
297
298 switch(info & MSTR_TYPE_MASK) {
299 case MSTR_TYPE_5:
300 strlen = MSTR_TYPE_5_LEN(info);
301 hdrlen = sizeof(struct mstrhdr5);
302 pMetaFlags = ((mstrFlags *) MSTR_HDR(5, s)) - 1;
303 break;
304 case MSTR_TYPE_8:
305 strlen = MSTR_HDR(8,s)->len;
306 hdrlen = sizeof(struct mstrhdr8);
307 pMetaFlags = ((mstrFlags *) MSTR_HDR(8, s)) - 1;
308 break;
309 case MSTR_TYPE_16:
310 strlen = MSTR_HDR(16,s)->len;
311 hdrlen = sizeof(struct mstrhdr16);
312 pMetaFlags = ((mstrFlags *) MSTR_HDR(16, s)) - 1;
313 break;
314 default: /* MSTR_TYPE_64: */
315 strlen = MSTR_HDR(64,s)->len;
316 hdrlen = sizeof(struct mstrhdr64);
317 pMetaFlags = ((mstrFlags *) MSTR_HDR(64, s)) - 1;
318 break;
319 }
320 return hdrlen + strlen + NULL_SIZE + ((isMeta) ? (mstrSumMetaLen(kind, *pMetaFlags) + sizeof(mstrFlags)) : 0);
321}
322
323/* returns pointer to the beginning of malloc() of mstr */
324void *mstrGetStartAlloc(mstr s, struct mstrKind *kind) {
325 int hdrlen;
326 mstrFlags *pMetaFlags;
327
328 int isMeta = mstrIsMetaAttached(s);
329
330 switch(s[-1]&MSTR_TYPE_MASK) {
331 case MSTR_TYPE_5:
332 hdrlen = sizeof(struct mstrhdr5);
333 pMetaFlags = ((mstrFlags *) MSTR_HDR(5, s)) - 1;
334 break;
335 case MSTR_TYPE_8:
336 hdrlen = sizeof(struct mstrhdr8);
337 pMetaFlags = ((mstrFlags *) MSTR_HDR(8, s)) - 1;
338 break;
339 case MSTR_TYPE_16:
340 hdrlen = sizeof(struct mstrhdr16);
341 pMetaFlags = ((mstrFlags *) MSTR_HDR(16, s)) - 1;
342 break;
343 default: /* MSTR_TYPE_64: */
344 hdrlen = sizeof(struct mstrhdr64);
345 pMetaFlags = ((mstrFlags *) MSTR_HDR(64, s)) - 1;
346 break;
347 }
348 return (char *) s - hdrlen - ((isMeta) ? (mstrSumMetaLen(kind, *pMetaFlags) + sizeof(mstrFlags)) : 0);
349}
350
351static inline int mstrHdrSize(char type) {
352 switch(type&MSTR_TYPE_MASK) {
353 case MSTR_TYPE_5:
354 return sizeof(struct mstrhdr5);
355 case MSTR_TYPE_8:
356 return sizeof(struct mstrhdr8);
357 case MSTR_TYPE_16:
358 return sizeof(struct mstrhdr16);
359 case MSTR_TYPE_64:
360 return sizeof(struct mstrhdr64);
361 }
362 return 0;
363}
364
365static inline char mstrReqType(size_t string_size) {
366 if (string_size < 1<<5)
367 return MSTR_TYPE_5;
368 if (string_size < 1<<8)
369 return MSTR_TYPE_8;
370 if (string_size < 1<<16)
371 return MSTR_TYPE_16;
372 return MSTR_TYPE_64;
373}
374
375#ifdef REDIS_TEST
376#include <stdlib.h>
377#include <assert.h>
378#include "testhelp.h"
379#include "limits.h"
380
381#ifndef UNUSED
382#define UNUSED(x) (void)(x)
383#endif
384
385/* Challenge mstr with metadata interesting enough that can include the case of hfield and hkey and more */
386#define B(idx) (1<<(idx))
387
388#define META_IDX_MYMSTR_TTL4 0
389#define META_IDX_MYMSTR_TTL8 1
390#define META_IDX_MYMSTR_TYPE_ENC_LRU 2 // 4Bbit type, 4bit encoding, 24bits lru
391#define META_IDX_MYMSTR_VALUE_PTR 3
392#define META_IDX_MYMSTR_FLAG_NO_META 4
393
394#define TEST_CONTEXT(context) printf("\nContext: %s \n", context);
395
396int mstrTest(int argc, char **argv, int flags) {
397 UNUSED(argc);
398 UNUSED(argv);
399 UNUSED(flags);
400
401 struct mstrKind kind_mymstr = {
402 .name = "my_mstr",
403 .metaSize[META_IDX_MYMSTR_TTL4] = 4,
404 .metaSize[META_IDX_MYMSTR_TTL8] = 8,
405 .metaSize[META_IDX_MYMSTR_TYPE_ENC_LRU] = 4,
406 .metaSize[META_IDX_MYMSTR_VALUE_PTR] = 8,
407 .metaSize[META_IDX_MYMSTR_FLAG_NO_META] = 0,
408 };
409
410 TEST_CONTEXT("Create simple short mstr")
411 {
412 char *str = "foo";
413 mstr s = mstrNew(str, strlen(str), 0, NULL);
414 size_t expStrLen = strlen(str);
415
416 test_cond("Verify str length and alloc length",
417 mstrAllocLen(s, NULL) == (1 + expStrLen + 1) && /* mstrhdr5 + str + null */
418 mstrlen(s) == expStrLen && /* expected strlen(str) */
419 memcmp(s, str, expStrLen + 1) == 0);
420 mstrFree(&kind_mymstr, s, NULL);
421 }
422
423 TEST_CONTEXT("Create simple 40 bytes mstr")
424 {
425 char *str = "0123456789012345678901234567890123456789"; // 40 bytes
426 mstr s = mstrNew(str, strlen(str), 0, NULL);
427
428 test_cond("Verify str length and alloc length",
429 mstrAllocLen(s, NULL) == (3 + 40 + 1) && /* mstrhdr8 + str + null */
430 mstrlen(s) == 40 &&
431 memcmp(s,str,40) == 0);
432 mstrFree(&kind_mymstr, s, NULL);
433 }
434
435 TEST_CONTEXT("Create mstr with random characters")
436 {
437 long unsigned int i;
438 char str[66000];
439 for (i = 0 ; i < sizeof(str) ; ++i) str[i] = rand() % 256;
440
441 size_t len[] = { 31, 32, 33, 255, 256, 257, 65535, 65536, 65537, 66000};
442 for (i = 0 ; i < sizeof(len) / sizeof(len[0]) ; ++i) {
443 char title[100];
444 mstr s = mstrNew(str, len[i], 0, NULL);
445 size_t mstrhdrSize = (len[i] < 1<<5) ? sizeof(struct mstrhdr5) :
446 (len[i] < 1<<8) ? sizeof(struct mstrhdr8) :
447 (len[i] < 1<<16) ? sizeof(struct mstrhdr16) :
448 sizeof(struct mstrhdr64);
449
450 snprintf(title, sizeof(title), "Verify string of length %zu", len[i]);
451 test_cond(title,
452 mstrAllocLen(s, NULL) == (mstrhdrSize + len[i] + 1) && /* mstrhdrX + str + null */
453 mstrlen(s) == len[i] &&
454 memcmp(s,str,len[i]) == 0);
455 mstrFree(&kind_mymstr, s, NULL);
456 }
457 }
458
459 TEST_CONTEXT("Create short mstr with TTL4")
460 {
461 uint32_t *ttl;
462 mstr s = mstrNewWithMeta(&kind_mymstr,
463 "foo",
464 strlen("foo"),
465 B(META_IDX_MYMSTR_TTL4), /* allocate with TTL4 metadata */
466 0,
467 NULL);
468
469 ttl = mstrMetaRef(s, &kind_mymstr, META_IDX_MYMSTR_TTL4);
470 *ttl = 0x12345678;
471
472 test_cond("Verify memory-allocation and string lengths",
473 mstrAllocLen(s, &kind_mymstr) == (1 + 3 + 2 + 1 + 4) && /* mstrhdr5 + str + null + mstrFlags + TLL */
474 mstrlen(s) == 3);
475
476 unsigned char expMem[] = {0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x1c, 'f', 'o', 'o', '\0' };
477 uint32_t value = 0x12345678;
478 memcpy(expMem, &value, sizeof(uint32_t));
479 test_cond("Verify string and TTL4 payload", memcmp(
480 mstrMetaRef(s, &kind_mymstr, 0) , expMem, sizeof(expMem)) == 0);
481
482 test_cond("Verify mstrIsMetaAttached() function works", mstrIsMetaAttached(s) != 0);
483
484 mstrFree(&kind_mymstr, s, NULL);
485 }
486
487 TEST_CONTEXT("Create short mstr with TTL4 and value ptr ")
488 {
489 mstr s = mstrNewWithMeta(&kind_mymstr, "foo", strlen("foo"),
490 B(META_IDX_MYMSTR_TTL4) | B(META_IDX_MYMSTR_VALUE_PTR), 0, NULL);
491 *((uint32_t *) (mstrMetaRef(s, &kind_mymstr,
492 META_IDX_MYMSTR_TTL4))) = 0x12345678;
493
494 test_cond("Verify length and alloc length",
495 mstrAllocLen(s, &kind_mymstr) == (1 + 3 + 1 + 2 + 4 + 8) && /* mstrhdr5 + str + null + mstrFlags + TLL + PTR */
496 mstrlen(s) == 3);
497 mstrFree(&kind_mymstr, s, NULL);
498 }
499
500 TEST_CONTEXT("Copy mstr and add it TTL4")
501 {
502 mstr s1 = mstrNew("foo", strlen("foo"), 0, NULL);
503 mstr s2 = mstrNewCopy(&kind_mymstr, s1, B(META_IDX_MYMSTR_TTL4), NULL);
504 *((uint32_t *) (mstrMetaRef(s2, &kind_mymstr, META_IDX_MYMSTR_TTL4))) = 0x12345678;
505
506 test_cond("Verify new mstr includes TTL4",
507 mstrAllocLen(s2, &kind_mymstr) == (1 + 3 + 1 + 2 + 4) && /* mstrhdr5 + str + null + mstrFlags + TTL4 */
508 mstrlen(s2) == 3 && /* 'foo' = 3bytes */
509 memcmp(s2, "foo\0", 4) == 0);
510
511 mstr s3 = mstrNewCopy(&kind_mymstr, s2, B(META_IDX_MYMSTR_TTL4), NULL);
512 unsigned char expMem[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x1, 0x0, 0x1c, 'f', 'o', 'o', '\0' };
513 uint32_t value = 0x12345678;
514 memcpy(expMem, &value, sizeof(uint32_t));
515
516 char *ppp = mstrGetStartAlloc(s3, &kind_mymstr);
517 test_cond("Verify string and TTL4 payload",
518 memcmp(ppp, expMem, sizeof(expMem)) == 0);
519
520 mstrPrint(s3, &kind_mymstr, 1);
521 mstrFree(&kind_mymstr, s1, NULL);
522 mstrFree(&kind_mymstr, s2, NULL);
523 mstrFree(&kind_mymstr, s3, NULL);
524 }
525
526 return 0;
527}
528#endif