1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * Copyright by The HDF Group.                                               *
3  * Copyright by the Board of Trustees of the University of Illinois.         *
4  * All rights reserved.                                                      *
5  *                                                                           *
6  * This file is part of HDF5.  The full HDF5 copyright notice, including     *
7  * terms governing use, modification, and redistribution, is contained in    *
8  * the files COPYING and Copyright.html.  COPYING can be found at the root   *
9  * of the source code distribution tree; Copyright.html can be found at the  *
10  * root level of an installed copy of the electronic HDF5 document set and   *
11  * is linked from the top-level documents page.  It can also be found at     *
12  * http://hdfgroup.org/HDF5/doc/Copyright.html.  If you do not have          *
13  * access to either file, you may request a copy from help@hdfgroup.org.     *
14  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /*
17  * Reference counted string algorithms.
18  *
19  * These are used for various internal strings which get copied multiple times.
20  *
21  */
22 
23 
24 #include "H5Eprivate.h"		/* Error handling		  	*/
25 #include "H5FLprivate.h"	/* Free lists                           */
26 #include "H5RSprivate.h"        /* Reference-counted strings            */
27 
28 /* Private typedefs & structs */
29 struct H5RS_str_t {
30     char *s;            /* String to be reference counted */
31     unsigned wrapped;   /* Indicates that the string to be ref-counted is not copied */
32     unsigned n;         /* Reference count of number of pointers sharing string */
33 };
34 
35 /* Declare a free list to manage the H5RS_str_t struct */
36 H5FL_DEFINE_STATIC(H5RS_str_t);
37 
38 /* Declare the PQ free list for the wrapped strings */
39 H5FL_BLK_DEFINE(str_buf);
40 
41 
42 /*--------------------------------------------------------------------------
43  NAME
44     H5RS_xstrdup
45  PURPOSE
46     Duplicate the string being reference counted
47  USAGE
48     char *H5RS_xstrdup(s)
49         const char *s;          IN: String to duplicate
50 
51  RETURNS
52     Returns a pointer to a new string on success, NULL on failure.
53  DESCRIPTION
54     Duplicate a string buffer being reference counted.  Use this instead of
55     [H5MM_][x]strdup, in order to use the free-list memory routines.
56  GLOBAL VARIABLES
57  COMMENTS, BUGS, ASSUMPTIONS
58  EXAMPLES
59  REVISION LOG
60 --------------------------------------------------------------------------*/
61 static char *
H5RS_xstrdup(const char * s)62 H5RS_xstrdup(const char *s)
63 {
64     char *ret_value;   /* Return value */
65 
66     FUNC_ENTER_NOAPI_NOINIT_NOERR
67 
68     if(s) {
69         size_t len = HDstrlen(s) + 1;
70 
71         ret_value = (char *)H5FL_BLK_MALLOC(str_buf, len);
72         HDassert(ret_value);
73         HDstrncpy(ret_value, s, len);
74     } /* end if */
75     else
76         ret_value = NULL;
77 
78     FUNC_LEAVE_NOAPI(ret_value)
79 } /* end H5RS_xstrdup() */
80 
81 
82 /*--------------------------------------------------------------------------
83  NAME
84     H5RS_create
85  PURPOSE
86     Create a reference counted string
87  USAGE
88     H5RS_str_t *H5RS_create(s)
89         const char *s;          IN: String to initialize ref-counted string with
90 
91  RETURNS
92     Returns a pointer to a new ref-counted string on success, NULL on failure.
93  DESCRIPTION
94     Create a reference counted string.  The string passed in is copied into an
95     internal buffer.
96  GLOBAL VARIABLES
97  COMMENTS, BUGS, ASSUMPTIONS
98  EXAMPLES
99  REVISION LOG
100 --------------------------------------------------------------------------*/
101 H5RS_str_t *
H5RS_create(const char * s)102 H5RS_create(const char *s)
103 {
104     H5RS_str_t *ret_value;   /* Return value */
105 
106     FUNC_ENTER_NOAPI(NULL)
107 
108     /* Allocate ref-counted string structure */
109     if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
110         HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
111 
112     /* Set the internal fields */
113     ret_value->s = H5RS_xstrdup(s);
114     ret_value->wrapped = 0;
115     ret_value->n = 1;
116 
117 done:
118     FUNC_LEAVE_NOAPI(ret_value)
119 } /* end H5RS_create() */
120 
121 
122 /*--------------------------------------------------------------------------
123  NAME
124     H5RS_wrap
125  PURPOSE
126     "Wrap" a reference counted string around an existing string
127  USAGE
128     H5RS_str_t *H5RS_wrap(s)
129         const char *s;          IN: String to wrap ref-counted string around
130 
131  RETURNS
132     Returns a pointer to a new ref-counted string on success, NULL on failure.
133  DESCRIPTION
134     Wrap a reference counted string around an existing string, which is not
135     duplicated, unless its reference count gets incremented.
136  GLOBAL VARIABLES
137  COMMENTS, BUGS, ASSUMPTIONS
138  EXAMPLES
139  REVISION LOG
140 --------------------------------------------------------------------------*/
141 H5RS_str_t *
H5RS_wrap(const char * s)142 H5RS_wrap(const char *s)
143 {
144     H5RS_str_t *ret_value;   /* Return value */
145 
146     FUNC_ENTER_NOAPI(NULL)
147 
148     /* Allocate ref-counted string structure */
149     if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
150         HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
151 
152     /* Set the internal fields */
153     ret_value->s = (char *)s;      /* (Cast away const OK - QAK) */
154     ret_value->wrapped = 1;
155     ret_value->n = 1;
156 
157 done:
158     FUNC_LEAVE_NOAPI(ret_value)
159 } /* end H5RS_wrap() */
160 
161 
162 /*--------------------------------------------------------------------------
163  NAME
164     H5RS_own
165  PURPOSE
166     Transfer ownership of a regular string to a reference counted string
167  USAGE
168     H5RS_str_t *H5RS_own(s)
169         const char *s;          IN: String to transfer ownership of
170 
171  RETURNS
172     Returns a pointer to a new ref-counted string on success, NULL on failure.
173  DESCRIPTION
174     Transfer ownership of a dynamically allocated string to a reference counted
175     string.  The routine which passed in the string should not attempt to free
176     it, the reference counting string routines will do that when the reference
177     count drops to zero.
178  GLOBAL VARIABLES
179  COMMENTS, BUGS, ASSUMPTIONS
180  EXAMPLES
181  REVISION LOG
182 --------------------------------------------------------------------------*/
183 H5RS_str_t *
H5RS_own(char * s)184 H5RS_own(char *s)
185 {
186     H5RS_str_t *ret_value;   /* Return value */
187 
188     FUNC_ENTER_NOAPI(NULL)
189 
190     /* Allocate ref-counted string structure */
191     if(NULL == (ret_value = H5FL_MALLOC(H5RS_str_t)))
192         HGOTO_ERROR(H5E_RS, H5E_NOSPACE, NULL, "memory allocation failed")
193 
194     /* Set the internal fields */
195     ret_value->s = s;
196     ret_value->wrapped = 0;
197     ret_value->n = 1;
198 
199 done:
200     FUNC_LEAVE_NOAPI(ret_value)
201 } /* end H5RS_own() */
202 
203 
204 /*--------------------------------------------------------------------------
205  NAME
206     H5RS_decr
207  PURPOSE
208     Decrement the reference count for a ref-counted string
209  USAGE
210     herr_t H5RS_decr(rs)
211         H5RS_str_t *rs;     IN/OUT: Ref-counted string to decrement count of
212 
213  RETURNS
214     Non-negative on success/Negative on failure
215  DESCRIPTION
216     Decrement the reference count for a reference counted string.  If the
217     reference count drops to zero, the reference counted string is deleted.
218  GLOBAL VARIABLES
219  COMMENTS, BUGS, ASSUMPTIONS
220  EXAMPLES
221  REVISION LOG
222 --------------------------------------------------------------------------*/
223 herr_t
H5RS_decr(H5RS_str_t * rs)224 H5RS_decr(H5RS_str_t *rs)
225 {
226     FUNC_ENTER_NOAPI_NOINIT_NOERR
227 
228     /* Sanity check */
229     HDassert(rs);
230     HDassert(rs->n > 0);
231 
232     /* Decrement reference count for string */
233     if((--rs->n) == 0) {
234         if(!rs->wrapped)
235             rs->s = (char *)H5FL_BLK_FREE(str_buf, rs->s);
236         rs = H5FL_FREE(H5RS_str_t, rs);
237     } /* end if */
238 
239     FUNC_LEAVE_NOAPI(SUCCEED)
240 } /* end H5RS_decr() */
241 
242 
243 /*--------------------------------------------------------------------------
244  NAME
245     H5RS_incr
246  PURPOSE
247     Increment the reference count for a ref-counted string
248  USAGE
249     herr_t H5RS_incr(rs)
250         H5RS_str_t *rs;     IN/OUT: Ref-counted string to increment count of
251 
252  RETURNS
253     Non-negative on success/Negative on failure
254  DESCRIPTION
255     Increment the reference count for a reference counted string.
256  GLOBAL VARIABLES
257  COMMENTS, BUGS, ASSUMPTIONS
258  EXAMPLES
259  REVISION LOG
260 --------------------------------------------------------------------------*/
261 herr_t
H5RS_incr(H5RS_str_t * rs)262 H5RS_incr(H5RS_str_t *rs)
263 {
264     FUNC_ENTER_NOAPI_NOINIT_NOERR
265 
266     /* Sanity check */
267     HDassert(rs);
268     HDassert(rs->n > 0);
269 
270     /* If the ref-counted string started life as a wrapper around an existing
271      * string, duplicate the string now, so that the wrapped string can go out
272      * scope appropriately.
273      */
274     if(rs->wrapped) {
275         rs->s = H5RS_xstrdup(rs->s);
276         rs->wrapped = 0;
277     } /* end if */
278 
279     /* Increment reference count for string */
280     rs->n++;
281 
282     FUNC_LEAVE_NOAPI(SUCCEED)
283 } /* end H5RS_incr() */
284 
285 
286 /*--------------------------------------------------------------------------
287  NAME
288     H5RS_dup
289  PURPOSE
290     "Duplicate" a ref-counted string
291  USAGE
292     H5RS_str_t H5RS_dup(rs)
293         H5RS_str_t *rs;     IN/OUT: Ref-counted string to "duplicate"
294 
295  RETURNS
296     Returns a pointer to ref-counted string on success, NULL on failure.
297  DESCRIPTION
298     Increment the reference count for the reference counted string and return
299     a pointer to it.
300  GLOBAL VARIABLES
301  COMMENTS, BUGS, ASSUMPTIONS
302  EXAMPLES
303  REVISION LOG
304 --------------------------------------------------------------------------*/
305 H5RS_str_t *
H5RS_dup(H5RS_str_t * ret_value)306 H5RS_dup(H5RS_str_t *ret_value)
307 {
308     FUNC_ENTER_NOAPI_NOINIT_NOERR
309 
310     /* Check for valid reference counted string */
311     if(ret_value != NULL)
312         /* Increment reference count for string */
313         ret_value->n++;
314 
315     FUNC_LEAVE_NOAPI(ret_value)
316 } /* end H5RS_dup() */
317 
318 
319 /*--------------------------------------------------------------------------
320  NAME
321     H5RS_dup_str
322  PURPOSE
323     "Duplicate" a regular string into a ref-counted string
324  USAGE
325     H5RS_str_t H5RS_dup_str(s)
326         const char *s;     IN: Regular string to duplicate
327 
328  RETURNS
329     Returns a pointer to ref-counted string on success, NULL on failure.
330  DESCRIPTION
331     Duplicate a regular string into a ref-counted string.
332  GLOBAL VARIABLES
333  COMMENTS, BUGS, ASSUMPTIONS
334  EXAMPLES
335  REVISION LOG
336 --------------------------------------------------------------------------*/
337 H5RS_str_t *
H5RS_dup_str(const char * s)338 H5RS_dup_str(const char *s)
339 {
340     char *new_str;              /* Duplicate of string */
341     size_t path_len;            /* Length of the path */
342     H5RS_str_t *ret_value;
343 
344     FUNC_ENTER_NOAPI(NULL)
345 
346     /* Sanity check */
347     HDassert(s);
348 
349     /* Get the length of the string */
350     path_len = HDstrlen(s);
351 
352     /* Allocate space for the string */
353     if(NULL == (new_str = (char *)H5FL_BLK_MALLOC(str_buf, path_len + 1)))
354         HGOTO_ERROR(H5E_RESOURCE, H5E_NOSPACE, NULL, "memory allocation failed")
355 
356     /* Copy name for full path */
357     HDstrncpy(new_str, s, (path_len + 1));
358 
359     /* Create reference counted string for path */
360     ret_value = H5RS_own(new_str);
361 
362 done:
363     FUNC_LEAVE_NOAPI(ret_value)
364 } /* end H5RS_dup_str() */
365 
366 
367 /*--------------------------------------------------------------------------
368  NAME
369     H5RS_cmp
370  PURPOSE
371     Compare two ref-counted strings
372  USAGE
373     int H5RS_cmp(rs1,rs2)
374         const H5RS_str_t *rs1;  IN: First Ref-counted string to compare
375         const H5RS_str_t *rs2;  IN: Second Ref-counted string to compare
376 
377  RETURNS
378     Returns positive, negative or 0 for comparison of two r-strings [same as
379     strcmp()]
380  DESCRIPTION
381     Compare two ref-counted strings and return a value indicating their sort
382     order [same as strcmp()]
383  GLOBAL VARIABLES
384  COMMENTS, BUGS, ASSUMPTIONS
385  EXAMPLES
386  REVISION LOG
387 --------------------------------------------------------------------------*/
388 int
H5RS_cmp(const H5RS_str_t * rs1,const H5RS_str_t * rs2)389 H5RS_cmp(const H5RS_str_t *rs1, const H5RS_str_t *rs2)
390 {
391     /* Can't return invalid value from this function */
392     FUNC_ENTER_NOAPI_NOINIT_NOERR
393 
394     /* Sanity check */
395     HDassert(rs1);
396     HDassert(rs1->s);
397     HDassert(rs2);
398     HDassert(rs2->s);
399 
400     FUNC_LEAVE_NOAPI(HDstrcmp(rs1->s, rs2->s))
401 } /* end H5RS_cmp() */
402 
403 
404 /*--------------------------------------------------------------------------
405  NAME
406     H5RS_len
407  PURPOSE
408     Compute the length of a ref-counted string
409  USAGE
410     ssize_t H5RS_cmp(rs)
411         const H5RS_str_t *rs;  IN: Ref-counted string to compute length of
412 
413  RETURNS
414     Returns non-negative value on success, negative value on failure
415  DESCRIPTION
416     Compute the length of a ref-counted string.  [same as strlen()]
417  GLOBAL VARIABLES
418  COMMENTS, BUGS, ASSUMPTIONS
419  EXAMPLES
420  REVISION LOG
421 --------------------------------------------------------------------------*/
422 ssize_t
H5RS_len(const H5RS_str_t * rs)423 H5RS_len(const H5RS_str_t *rs)
424 {
425     FUNC_ENTER_NOAPI_NOINIT_NOERR
426 
427     /* Sanity check */
428     HDassert(rs);
429     HDassert(rs->s);
430 
431     FUNC_LEAVE_NOAPI((ssize_t)HDstrlen(rs->s))
432 } /* end H5RS_len() */
433 
434 
435 /*--------------------------------------------------------------------------
436  NAME
437     H5RS_get_str
438  PURPOSE
439     Get a pointer to the internal string contained in a ref-counted string
440  USAGE
441     char *H5RS_get_str(rs)
442         const H5RS_str_t *rs;   IN: Ref-counted string to get internal string from
443 
444  RETURNS
445     Returns a pointer to the internal string being ref-counted on success,
446         NULL on failure.
447  DESCRIPTION
448     Gets a pointer to the internal string being reference counted.  This
449     pointer is volatile and might be invalid is further calls to the H5RS
450     API are made.
451  GLOBAL VARIABLES
452  COMMENTS, BUGS, ASSUMPTIONS
453  EXAMPLES
454  REVISION LOG
455 --------------------------------------------------------------------------*/
456 char *
H5RS_get_str(const H5RS_str_t * rs)457 H5RS_get_str(const H5RS_str_t *rs)
458 {
459     FUNC_ENTER_NOAPI_NOINIT_NOERR
460 
461     /* Sanity check */
462     HDassert(rs);
463     HDassert(rs->s);
464 
465     FUNC_LEAVE_NOAPI(rs->s)
466 } /* end H5RS_get_str() */
467 
468 
469 /*--------------------------------------------------------------------------
470  NAME
471     H5RS_get_count
472  PURPOSE
473     Get the reference count for a ref-counted string
474  USAGE
475     unsigned H5RS_get_count(rs)
476         const H5RS_str_t *rs;   IN: Ref-counted string to get internal count from
477 
478  RETURNS
479     Returns the number of references to the internal string being ref-counted on success,
480         0 on failure.
481  DESCRIPTION
482     Gets the count of references to the reference counted string.
483  GLOBAL VARIABLES
484  COMMENTS, BUGS, ASSUMPTIONS
485  EXAMPLES
486  REVISION LOG
487 --------------------------------------------------------------------------*/
488 unsigned
H5RS_get_count(const H5RS_str_t * rs)489 H5RS_get_count(const H5RS_str_t *rs)
490 {
491     FUNC_ENTER_NOAPI_NOINIT_NOERR
492 
493     /* Sanity check */
494     HDassert(rs);
495     HDassert(rs->n > 0);
496 
497     FUNC_LEAVE_NOAPI(rs->n)
498 } /* end H5RS_get_count() */
499 
500