Bug Summary

File:tests/suite/ecore/src/lib/eina_stringshare.c
Location:line 665, column 57
Description:Dereference of null pointer loaded from variable 'str'

Annotated Source Code

1/* EINA - EFL data type library
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
3 * Carsten Haitzler,
4 * Jorge Luis Zapata Muga,
5 * Cedric Bail,
6 * Gustavo Sverzut Barbieri
7 * Tom Hacohen
8 * Brett Nash
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library;
22 * if not, see <http://www.gnu.org/licenses/>.
23 */
24
25/**
26 * @page tutorial_stringshare_page Stringshare Tutorial
27 *
28 * to be written...
29 *
30 */
31
32#ifdef HAVE_CONFIG_H1
33# include "config.h"
34#endif
35
36#define _GNU_SOURCE
37
38#ifdef HAVE_ALLOCA_H1
39# include <alloca.h>
40#elif defined __GNUC__4
41# define alloca __builtin_alloca
42#elif defined _AIX
43# define alloca __alloca
44#elif defined _MSC_VER
45# include <malloc.h>
46# define alloca _alloca
47#else
48# include <stddef.h>
49# ifdef __cplusplus
50extern "C"
51# endif
52void *alloca (size_t)__builtin_alloca (size_t);
53#endif
54
55#include <stdlib.h>
56#include <stdio.h>
57#include <string.h>
58
59#ifdef EFL_HAVE_POSIX_THREADS1
60# include <pthread.h>
61#endif
62
63#ifdef HAVE_EVIL
64# include <Evil.h>
65#endif
66
67#include "eina_config.h"
68#include "eina_private.h"
69#include "eina_hash.h"
70#include "eina_rbtree.h"
71#include "eina_error.h"
72#include "eina_log.h"
73#include "eina_stringshare.h"
74
75/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
76#include "eina_safety_checks.h"
77#include "eina_share_common.h"
78
79/* The actual share */
80static Eina_Share *stringshare_share;
81static const char EINA_MAGIC_STRINGSHARE_NODE_STR[] = "Eina Stringshare Node";
82
83#ifdef EFL_HAVE_THREADS1
84extern Eina_Bool _share_common_threads_activated;
85
86# ifdef EFL_HAVE_POSIX_THREADS1
87static pthread_mutex_t _mutex_small = PTHREAD_MUTEX_INITIALIZER{ { 0, 0, 0, 0, 0, 0, { 0, 0 } } };
88# define STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
if(_share_common_threads_activated) \
89 pthread_mutex_lock(&_mutex_small)
90# define STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
if(_share_common_threads_activated) \
91 pthread_mutex_unlock(&_mutex_small)
92# else /* EFL_HAVE_WIN32_THREADS */
93static HANDLE _mutex_small = NULL((void*)0);
94# define STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
if(_share_common_threads_activated) \
95 WaitForSingleObject(_mutex_small, INFINITE)
96# define STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
if(_share_common_threads_activated) \
97 ReleaseMutex(_mutex_small)
98
99# endif /* EFL_HAVE_WIN32_THREADS */
100#else /* EFL_HAVE_THREADS */
101# define STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
do {} while (0)
102# define STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
do {} while (0)
103#endif
104
105/* Stringshare optimizations */
106static const unsigned char _eina_stringshare_single[512] = {
107 0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,
108 16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,
109 31,0,32,0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,
110 46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,0,
111 61,0,62,0,63,0,64,0,65,0,66,0,67,0,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,
112 76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,
113 91,0,92,0,93,0,94,0,95,0,96,0,97,0,98,0,99,0,100,0,101,0,102,0,103,0,104,0,
114 105,0,
115 106,0,107,0,108,0,109,0,110,0,111,0,112,0,113,0,114,0,115,0,116,0,117,0,118,
116 0,119,0,120,0,
117 121,0,122,0,123,0,124,0,125,0,126,0,127,0,128,0,129,0,130,0,131,0,132,0,133,
118 0,134,0,135,0,
119 136,0,137,0,138,0,139,0,140,0,141,0,142,0,143,0,144,0,145,0,146,0,147,0,148,
120 0,149,0,150,0,
121 151,0,152,0,153,0,154,0,155,0,156,0,157,0,158,0,159,0,160,0,161,0,162,0,163,
122 0,164,0,165,0,
123 166,0,167,0,168,0,169,0,170,0,171,0,172,0,173,0,174,0,175,0,176,0,177,0,178,
124 0,179,0,180,0,
125 181,0,182,0,183,0,184,0,185,0,186,0,187,0,188,0,189,0,190,0,191,0,192,0,193,
126 0,194,0,195,0,
127 196,0,197,0,198,0,199,0,200,0,201,0,202,0,203,0,204,0,205,0,206,0,207,0,208,
128 0,209,0,210,0,
129 211,0,212,0,213,0,214,0,215,0,216,0,217,0,218,0,219,0,220,0,221,0,222,0,223,
130 0,224,0,225,0,
131 226,0,227,0,228,0,229,0,230,0,231,0,232,0,233,0,234,0,235,0,236,0,237,0,238,
132 0,239,0,240,0,
133 241,0,242,0,243,0,244,0,245,0,246,0,247,0,248,0,249,0,250,0,251,0,252,0,253,
134 0,254,0,255,0
135};
136
137typedef struct _Eina_Stringshare_Small Eina_Stringshare_Small;
138typedef struct _Eina_Stringshare_Small_Bucket Eina_Stringshare_Small_Bucket;
139
140struct _Eina_Stringshare_Small_Bucket
141{
142 /* separate arrays for faster lookups */
143 const char **strings;
144 unsigned char *lengths;
145 unsigned short *references;
146 int count;
147 int size;
148};
149
150struct _Eina_Stringshare_Small
151{
152 Eina_Stringshare_Small_Bucket *buckets[256];
153};
154
155#define EINA_STRINGSHARE_SMALL_BUCKET_STEP8 8
156static Eina_Stringshare_Small _eina_small_share;
157
158static inline int
159_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket,
160 int i,
161 const char *pstr,
162 unsigned char plength)
163{
164 /* pstr and plength are from second char and on, since the first is
165 * always the same.
166 *
167 * First string being always the same, size being between 2 and 3
168 * characters (there is a check for special case length==1 and then
169 * small stringshare is applied to strings < 4), we just need to
170 * compare 2 characters of both strings.
171 */
172 const unsigned char cur_plength = bucket->lengths[i] - 1;
173 const char *cur_pstr;
174
175 if (cur_plength > plength)
176 return 1;
177 else if (cur_plength < plength)
178 return -1;
179
180 cur_pstr = bucket->strings[i] + 1;
181
182 if (cur_pstr[0] > pstr[0])
183 return 1;
184 else if (cur_pstr[0] < pstr[0])
185 return -1;
186
187 if (plength == 1)
188 return 0;
189
190 if (cur_pstr[1] > pstr[1])
191 return 1;
192 else if (cur_pstr[1] < pstr[1])
193 return -1;
194
195 return 0;
196}
197
198static const char *
199_eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket *bucket,
200 const char *str,
201 unsigned char length,
202 int *idx)
203{
204 const char *pstr = str + 1; /* skip first letter, it's always the same */
205 unsigned char plength = length - 1;
206 int i, low, high;
207
208 if (bucket->count == 0)
209 {
210 *idx = 0;
211 return NULL((void*)0);
212 }
213
214 low = 0;
215 high = bucket->count;
216
217 while (low < high)
218 {
219 int r;
220
221 i = (low + high - 1) / 2;
222
223 r = _eina_stringshare_small_cmp(bucket, i, pstr, plength);
224 if (r > 0)
225 high = i;
226 else if (r < 0)
227 low = i + 1;
228 else
229 {
230 *idx = i;
231 return bucket->strings[i];
232 }
233 }
234
235 *idx = low;
236 return NULL((void*)0);
237}
238
239static Eina_Bool
240_eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket *bucket,
241 int size)
242{
243 void *tmp;
244
245 tmp = realloc((void *)bucket->strings, size * sizeof(bucket->strings[0]));
246 if (!tmp)
247 {
248 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
249 return 0;
250 }
251
252 bucket->strings = tmp;
253
254 tmp = realloc(bucket->lengths, size * sizeof(bucket->lengths[0]));
255 if (!tmp)
256 {
257 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
258 return 0;
259 }
260
261 bucket->lengths = tmp;
262
263 tmp = realloc(bucket->references, size * sizeof(bucket->references[0]));
264 if (!tmp)
265 {
266 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
267 return 0;
268 }
269
270 bucket->references = tmp;
271
272 bucket->size = size;
273 return 1;
274}
275
276static const char *
277_eina_stringshare_small_bucket_insert_at(
278 Eina_Stringshare_Small_Bucket **p_bucket,
279 const char *str,
280 unsigned char length,
281 int idx)
282{
283 Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
284 int todo, off;
285 char *snew;
286
287 if (!bucket)
288 {
289 *p_bucket = bucket = calloc(1, sizeof(*bucket));
290 if (!bucket)
291 {
292 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
293 return NULL((void*)0);
294 }
295 }
296
297 if (bucket->count + 1 >= bucket->size)
298 {
299 int size = bucket->size + EINA_STRINGSHARE_SMALL_BUCKET_STEP8;
300 if (!_eina_stringshare_small_bucket_resize(bucket, size))
301 return NULL((void*)0);
302 }
303
304 snew = malloc(length + 1);
305 if (!snew)
306 {
307 eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
308 return NULL((void*)0);
309 }
310
311 memcpy(snew, str, length);
312 snew[length] = '\0';
313
314 off = idx + 1;
315 todo = bucket->count - idx;
316 if (todo > 0)
317 {
318 memmove((void *)(bucket->strings + off), bucket->strings + idx,
319 todo * sizeof(bucket->strings[0]));
320 memmove(bucket->lengths + off, bucket->lengths + idx,
321 todo * sizeof(bucket->lengths[0]));
322 memmove(bucket->references + off, bucket->references + idx,
323 todo * sizeof(bucket->references[0]));
324 }
325
326 bucket->strings[idx] = snew;
327 bucket->lengths[idx] = length;
328 bucket->references[idx] = 1;
329 bucket->count++;
330
331 return snew;
332}
333
334static void
335_eina_stringshare_small_bucket_remove_at(
336 Eina_Stringshare_Small_Bucket **p_bucket,
337 int idx)
338{
339 Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
340 int todo, off;
341
342 if (bucket->references[idx] > 1)
343 {
344 bucket->references[idx]--;
345 return;
346 }
347
348 free((char *)bucket->strings[idx]);
349
350 if (bucket->count == 1)
351 {
352 free((void *)bucket->strings);
353 free(bucket->lengths);
354 free(bucket->references);
355 free(bucket);
356 *p_bucket = NULL((void*)0);
357 return;
358 }
359
360 bucket->count--;
361 if (idx == bucket->count)
362 goto end;
363
364 off = idx + 1;
365 todo = bucket->count - idx;
366
367 memmove((void *)(bucket->strings + idx), bucket->strings + off,
368 todo * sizeof(bucket->strings[0]));
369 memmove(bucket->lengths + idx, bucket->lengths + off,
370 todo * sizeof(bucket->lengths[0]));
371 memmove(bucket->references + idx, bucket->references + off,
372 todo * sizeof(bucket->references[0]));
373
374end:
375 if (bucket->count + EINA_STRINGSHARE_SMALL_BUCKET_STEP8 < bucket->size)
376 {
377 int size = bucket->size - EINA_STRINGSHARE_SMALL_BUCKET_STEP8;
378 _eina_stringshare_small_bucket_resize(bucket, size);
379 }
380}
381
382static const char *
383_eina_stringshare_small_add(const char *str, unsigned char length)
384{
385 Eina_Stringshare_Small_Bucket **bucket;
386 int i;
387
388 bucket = _eina_small_share.buckets + (unsigned char)str[0];
389 if (!*bucket)
390 i = 0;
391 else
392 {
393 const char *ret;
394 ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
395 if (ret)
396 {
397 (*bucket)->references[i]++;
398 return ret;
399 }
400 }
401
402 return _eina_stringshare_small_bucket_insert_at(bucket, str, length, i);
403}
404
405static void
406_eina_stringshare_small_del(const char *str, unsigned char length)
407{
408 Eina_Stringshare_Small_Bucket **bucket;
409 const char *ret;
410 int i;
411
412 bucket = _eina_small_share.buckets + (unsigned char)str[0];
413 if (!*bucket)
414 goto error;
415
416 ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
417 if (!ret)
418 goto error;
419
420 _eina_stringshare_small_bucket_remove_at(bucket, i);
421 return;
422
423error:
424 CRITICAL("EEEK trying to del non-shared stringshare \"%s\"", str)eina_log_print(_eina_share_common_log_dom, EINA_LOG_LEVEL_CRITICAL
, "ecore/src/lib/eina_stringshare.c", __FUNCTION__, 424, "EEEK trying to del non-shared stringshare \"%s\""
, str)
;
425}
426
427static void
428_eina_stringshare_small_init(void)
429{
430 memset(&_eina_small_share, 0, sizeof(_eina_small_share));
431}
432
433static void
434_eina_stringshare_small_shutdown(void)
435{
436 Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
437
438 p_bucket = _eina_small_share.buckets;
439 p_bucket_end = p_bucket + 256;
440
441 for (; p_bucket < p_bucket_end; p_bucket++)
442 {
443 Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
444 char **s, **s_end;
445
446 if (!bucket)
447 continue;
448
449 s = (char **)bucket->strings;
450 s_end = s + bucket->count;
451 for (; s < s_end; s++)
452 free(*s);
453
454 free((void *)bucket->strings);
455 free(bucket->lengths);
456 free(bucket->references);
457 free(bucket);
458 *p_bucket = NULL((void*)0);
459 }
460}
461
462static void
463_eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket *bucket,
464 struct dumpinfo *di)
465{
466 const char **s = bucket->strings;
467 unsigned char *l = bucket->lengths;
468 unsigned short *r = bucket->references;
469 int i;
470
471 di->used += sizeof(*bucket);
472 di->used += bucket->count * sizeof(*s);
473 di->used += bucket->count * sizeof(*l);
474 di->used += bucket->count * sizeof(*r);
475 di->unique += bucket->count;
476
477 for (i = 0; i < bucket->count; i++, s++, l++, r++)
478 {
479 int dups;
480#ifdef _WIN32
481 printf("DDD: %5hu %5hu '%s'\n", *l, *r, *s);
482#else
483 printf("DDD: %5hhu %5hu '%s'\n", *l, *r, *s);
484#endif
485
486 dups = (*r - 1);
487
488 di->used += *l;
489 di->saved += *l * dups;
490 di->dups += dups;
491 }
492}
493
494static void
495_eina_stringshare_small_dump(struct dumpinfo *di)
496{
497 Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
498
499 p_bucket = _eina_small_share.buckets;
500 p_bucket_end = p_bucket + 256;
501
502 for (; p_bucket < p_bucket_end; p_bucket++)
503 {
504 Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
505
506 if (!bucket)
507 continue;
508
509 _eina_stringshare_small_bucket_dump(bucket, di);
510 }
511}
512
513
514/*============================================================================*
515* Global *
516*============================================================================*/
517
518/**
519 * @internal
520 * @brief Initialize the share_common module.
521 *
522 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
523 *
524 * This function sets up the share_common module of Eina. It is called by
525 * eina_init().
526 *
527 * @see eina_init()
528 */
529Eina_Bool
530eina_stringshare_init(void)
531{
532 Eina_Bool ret;
533 ret = eina_share_common_init(&stringshare_share,
534 EINA_MAGIC_STRINGSHARE_NODE0x98761254,
535 EINA_MAGIC_STRINGSHARE_NODE_STR);
536 if (ret)
537 _eina_stringshare_small_init();
538
539 return ret;
540}
541
542/**
543 * @internal
544 * @brief Shut down the share_common module.
545 *
546 * @return #EINA_TRUE on success, #EINA_FALSE on failure.
547 *
548 * This function shuts down the share_common module set up by
549 * eina_share_common_init(). It is called by eina_shutdown().
550 *
551 * @see eina_shutdown()
552 */
553Eina_Bool
554eina_stringshare_shutdown(void)
555{
556 Eina_Bool ret;
557 _eina_stringshare_small_shutdown();
558 ret = eina_share_common_shutdown(&stringshare_share);
559 return ret;
560}
561
562/*============================================================================*
563* API *
564*============================================================================*/
565
566/**
567 * @addtogroup Eina_Stringshare_Group Stringshare
568 *
569 * These functions allow you to store one copy of a string, and use it
570 * throughout your program.
571 *
572 * This is a method to reduce the number of duplicated strings kept in
573 * memory. It's pretty common for the same strings to be dynamically
574 * allocated repeatedly between applications and libraries, especially in
575 * circumstances where you could have multiple copies of a structure that
576 * allocates the string. So rather than duplicating and freeing these
577 * strings, you request a read-only pointer to an existing string and
578 * only incur the overhead of a hash lookup.
579 *
580 * It sounds like micro-optimizing, but profiling has shown this can have
581 * a significant impact as you scale the number of copies up. It improves
582 * string creation/destruction speed, reduces memory use and decreases
583 * memory fragmentation, so a win all-around.
584 *
585 * For more information, you can look at the @ref tutorial_stringshare_page.
586 *
587 * @{
588 */
589
590/**
591 * @brief Note that the given string has lost an instance.
592 *
593 * @param str string The given string.
594 *
595 * This function decreases the reference counter associated to @p str
596 * if it exists. If that counter reaches 0, the memory associated to
597 * @p str is freed. If @p str is NULL, the function returns
598 * immediately.
599 *
600 * Note that if the given pointer is not shared or NULL, bad things
601 * will happen, likely a segmentation fault.
602 */
603EAPI__attribute__ ((visibility("default"))) void
604eina_stringshare_del(const char *str)
605{
606 int slen;
607 DBG("str=%p (%s)", str, str ? str : "")eina_log_print(_eina_share_common_log_dom, EINA_LOG_LEVEL_DBG
, "ecore/src/lib/eina_stringshare.c", __FUNCTION__, 607, "str=%p (%s)"
, str, str ? str : "")
;
608 if (!str)
609 return;
610
611 /* special cases */
612 if (str[0] == '\0')
613 slen = 0;
614 else if (str[1] == '\0')
615 slen = 1;
616 else if (str[2] == '\0')
617 slen = 2;
618 else if (str[3] == '\0')
619 slen = 3;
620 else
621 slen = 4; /* handled later */
622
623 if (slen < 2)
624 return;
625 else if (slen < 4)
626 {
627 eina_share_common_population_del(stringshare_share, slen);
628 STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
;
629 _eina_stringshare_small_del(str, slen);
630 STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
;
631 return;
632 }
633
634 eina_share_common_del(stringshare_share, str);
635}
636
637/**
638 * @brief Retrieve an instance of a string for use in a program.
639 *
640 * @param str The string to retrieve an instance of.
641 * @param slen The string size (<= strlen(str)).
642 * @return A pointer to an instance of the string on success.
643 * @c NULL on failure.
644 *
645 * This function retrieves an instance of @p str. If @p str is
646 * @c NULL, then @c NULL is returned. If @p str is already stored, it
647 * is just returned and its reference counter is increased. Otherwise
648 * it is added to the strings to be searched and a duplicated string
649 * of @p str is returned.
650 *
651 * This function does not check string size, but uses the
652 * exact given size. This can be used to share_common part of a larger
653 * buffer or substring.
654 *
655 * @see eina_share_common_add()
656 */
657EAPI__attribute__ ((visibility("default"))) const char *
658eina_stringshare_add_length(const char *str, unsigned int slen)
659{
660 DBG("str=%p (%.*s), slen=%u", str, slen, str ? str : "", slen)eina_log_print(_eina_share_common_log_dom, EINA_LOG_LEVEL_DBG
, "ecore/src/lib/eina_stringshare.c", __FUNCTION__, 660, "str=%p (%.*s), slen=%u"
, str, slen, str ? str : "", slen)
;
1
Within the expansion of the macro 'DBG':
a
Assuming pointer value is null
661
662 if (slen <= 0)
2
Taking false branch
663 return "";
664 else if (slen == 1)
3
Taking true branch
665 return (const char *)_eina_stringshare_single + ((*str) << 1);
4
Dereference of null pointer loaded from variable 'str'
666 else if (slen < 4)
667 {
668 const char *s;
669
670 STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
;
671 s = _eina_stringshare_small_add(str, slen);
672 STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
;
673 return s;
674 }
675
676 return eina_share_common_add_length(stringshare_share, str, slen *
677 sizeof(char), sizeof(char));
678}
679
680/**
681 * @brief Retrieve an instance of a string for use in a program.
682 *
683 * @param str The NULL terminated string to retrieve an instance of.
684 * @return A pointer to an instance of the string on success.
685 * @c NULL on failure.
686 *
687 * This function retrieves an instance of @p str. If @p str is
688 * @c NULL, then @c NULL is returned. If @p str is already stored, it
689 * is just returned and its reference counter is increased. Otherwise
690 * it is added to the strings to be searched and a duplicated string
691 * of @p str is returned.
692 *
693 * The string @p str must be NULL terminated ('@\0') and its full
694 * length will be used. To use part of the string or non-null
695 * terminated, use eina_stringshare_add_length() instead.
696 *
697 * @see eina_stringshare_add_length()
698 */
699EAPI__attribute__ ((visibility("default"))) const char *
700eina_stringshare_add(const char *str)
701{
702 int slen;
703 if (!str)
704 return NULL((void*)0);
705
706 if (str[0] == '\0')
707 slen = 0;
708 else if (str[1] == '\0')
709 slen = 1;
710 else if (str[2] == '\0')
711 slen = 2;
712 else if (str[3] == '\0')
713 slen = 3;
714 else
715 slen = 3 + (int)strlen(str + 3);
716
717 return eina_stringshare_add_length(str, slen);
718}
719
720/**
721 * @brief Retrieve an instance of a string for use in a program
722 * from a format string.
723 *
724 * @param fmt The NULL terminated format string to retrieve an instance of.
725 * @return A pointer to an instance of the string on success.
726 * @c NULL on failure.
727 *
728 * This function retrieves an instance of @p fmt. If @p fmt is
729 * @c NULL, then @c NULL is returned. If @p fmt is already stored, it
730 * is just returned and its reference counter is increased. Otherwise
731 * it is added to the strings to be searched and a duplicated string
732 * is returned.
733 *
734 * The format string @p fmt must be NULL terminated ('@\0') and its full
735 * length will be used. To use part of the format string or non-null
736 * terminated, use eina_stringshare_nprintf() instead.
737 *
738 * @see eina_stringshare_nprintf()
739 */
740EAPI__attribute__ ((visibility("default"))) const char *
741eina_stringshare_printf(const char *fmt, ...)
742{
743 va_list args;
744 char *tmp;
745 const char *ret;
746 int len;
747
748 if (!fmt)
749 return NULL((void*)0);
750
751 va_start(args, fmt)__builtin_va_start(args, fmt);
752 len = vasprintf(&tmp, fmt, args);
753 va_end(args)__builtin_va_end(args);
754
755 if (len < 1)
756 return NULL((void*)0);
757
758 ret = eina_stringshare_add_length(tmp, len);
759 free(tmp);
760
761 return ret;
762}
763
764/**
765 * @brief Retrieve an instance of a string for use in a program
766 * from a format string.
767 *
768 * @param fmt The NULL terminated format string to retrieve an instance of.
769 * @param args The va_args for @p fmt
770 * @return A pointer to an instance of the string on success.
771 * @c NULL on failure.
772 *
773 * This function retrieves an instance of @p fmt with @p args. If @p fmt is
774 * @c NULL, then @c NULL is returned. If @p fmt with @p args is already stored, it
775 * is just returned and its reference counter is increased. Otherwise
776 * it is added to the strings to be searched and a duplicated string
777 * is returned.
778 *
779 * The format string @p fmt must be NULL terminated ('@\0') and its full
780 * length will be used. To use part of the format string or non-null
781 * terminated, use eina_stringshare_nprintf() instead.
782 *
783 * @see eina_stringshare_nprintf()
784 */
785EAPI__attribute__ ((visibility("default"))) const char *
786eina_stringshare_vprintf(const char *fmt, va_list args)
787{
788 char *tmp;
789 const char *ret;
790 int len;
791
792 if (!fmt)
793 return NULL((void*)0);
794
795 len = vasprintf(&tmp, fmt, args);
796
797 if (len < 1)
798 return NULL((void*)0);
799
800 ret = eina_stringshare_add_length(tmp, len);
801 free(tmp);
802
803 return ret;
804}
805
806/**
807 * @brief Retrieve an instance of a string for use in a program
808 * from a format string with size limitation.
809 * @param len The length of the format string to use
810 * @param fmt The format string to retrieve an instance of.
811 * @return A pointer to an instance of the string on success.
812 * @c NULL on failure.
813 *
814 * This function retrieves an instance of @p fmt limited by @p len. If @p fmt is
815 * @c NULL or @p len is < 1, then @c NULL is returned. If the resulting string
816 * is already stored, it is returned and its reference counter is increased. Otherwise
817 * it is added to the strings to be searched and a duplicated string
818 * is returned.
819 *
820 * @p len length of the format string will be used. To use the
821 * entire format string, use eina_stringshare_printf() instead.
822 *
823 * @see eina_stringshare_printf()
824 */
825EAPI__attribute__ ((visibility("default"))) const char *
826eina_stringshare_nprintf(unsigned int len, const char *fmt, ...)
827{
828 va_list args;
829 char *tmp;
830 int size;
831
832 if (!fmt)
833 return NULL((void*)0);
834
835 if (len < 1)
836 return NULL((void*)0);
837
838 tmp = alloca(sizeof(char) * len + 1)__builtin_alloca (sizeof(char) * len + 1);
839
840 va_start(args, fmt)__builtin_va_start(args, fmt);
841 size = vsnprintf(tmp, len, fmt, args);
842 va_end(args)__builtin_va_end(args);
843
844 if (size < 1)
845 return NULL((void*)0);
846
847 return eina_stringshare_add_length(tmp, len);
848}
849
850/**
851 * Increment references of the given shared string.
852 *
853 * @param str The shared string.
854 * @return A pointer to an instance of the string on success.
855 * @c NULL on failure.
856 *
857 * This is similar to eina_share_common_add(), but it's faster since it will
858 * avoid lookups if possible, but on the down side it requires the parameter
859 * to be shared before, in other words, it must be the return of a previous
860 * eina_share_common_add().
861 *
862 * There is no unref since this is the work of eina_share_common_del().
863 */
864EAPI__attribute__ ((visibility("default"))) const char *
865eina_stringshare_ref(const char *str)
866{
867 int slen;
868 DBG("str=%p (%s)", str, str ? str : "")eina_log_print(_eina_share_common_log_dom, EINA_LOG_LEVEL_DBG
, "ecore/src/lib/eina_stringshare.c", __FUNCTION__, 868, "str=%p (%s)"
, str, str ? str : "")
;
869
870 if (!str)
871 return eina_share_common_ref(stringshare_share, str);
872
873 /* special cases */
874 if (str[0] == '\0')
875 slen = 0;
876 else if (str[1] == '\0')
877 slen = 1;
878 else if (str[2] == '\0')
879 slen = 2;
880 else if (str[3] == '\0')
881 slen = 3;
882 else
883 slen = 3 + (int)strlen(str + 3);
884
885 if (slen < 2)
886 {
887 eina_share_common_population_add(stringshare_share, slen);
888
889 return str;
890 }
891 else if (slen < 4)
892 {
893 const char *s;
894 eina_share_common_population_add(stringshare_share, slen);
895
896 STRINGSHARE_LOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_lock(&_mutex_small
)
;
897 s = _eina_stringshare_small_add(str, slen);
898 STRINGSHARE_UNLOCK_SMALL()if(_share_common_threads_activated) pthread_mutex_unlock(&
_mutex_small)
;
899
900 return s;
901 }
902
903 return eina_share_common_ref(stringshare_share, str);
904}
905
906/**
907 * @brief Note that the given string @b must be shared.
908 *
909 * @param str the shared string to know the length. It is safe to
910 * give NULL, in that case -1 is returned.
911 *
912 * This function is a cheap way to known the length of a shared
913 * string. Note that if the given pointer is not shared, bad
914 * things will happen, likely a segmentation fault. If in doubt, try
915 * strlen().
916 */
917EAPI__attribute__ ((visibility("default"))) int
918eina_stringshare_strlen(const char *str)
919{
920 int len;
921 /* special cases */
922 if (str[0] == '\0')
923 return 0;
924
925 if (str[1] == '\0')
926 return 1;
927
928 if (str[2] == '\0')
929 return 2;
930
931 if (str[3] == '\0')
932 return 3;
933
934 len = eina_share_common_length(stringshare_share, (const char *)str);
935 len = (len > 0) ? len / (int)sizeof(char) : -1;
936 return len;
937}
938
939/**
940 * @brief Dump the contents of the share_common.
941 *
942 * This function dumps all strings in the share_common to stdout with a
943 * DDD: prefix per line and a memory usage summary.
944 */
945EAPI__attribute__ ((visibility("default"))) void
946eina_stringshare_dump(void)
947{
948 eina_share_common_dump(stringshare_share,
949 _eina_stringshare_small_dump,
950 sizeof(_eina_stringshare_single));
951}
952
953/**
954 * @}
955 */
956