1 /*
2 * Portions of this file Copyright 1999-2005 University of Chicago
3 * Portions of this file Copyright 1999-2005 The University of Southern California.
4 *
5 * This file or a portion of this file is licensed under the
6 * terms of the Globus Toolkit Public License, found at
7 * http://www.globus.org/toolkit/download/license.html.
8 * If you redistribute this file, with or without
9 * modifications, you must include this notice in the file.
10 */
11
12 #include "globus_i_wsrf_resource.h"
13 #include "xsd_any.h"
14
15 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
16 /**
17 * @file globus_wsrf_resource_property.c
18 * Resource Property Functions
19 * @author $author$
20 * @date $date$
21 * @version $version$
22 */
23 #endif /* GLOBUS_DONT_DOCUMENT_INTERNAL */
24
25 static
26 xsd_QName globus_l_resource_properties_any_qname = {
27 "any",
28 "any"
29 };
30
31 const xsd_QName * globus_resource_properties_any_qname =
32 &globus_l_resource_properties_any_qname;
33 static
34 globus_result_t
35 globus_l_resource_create_property(
36 globus_resource_t resource,
37 const xsd_QName * qname,
38 const globus_xsd_type_info_t type_info,
39 void * property,
40 globus_resource_property_callback_t callback,
41 void * callback_arg);
42
43 static
44 globus_result_t
45 globus_l_resource_get_any_property(
46 globus_resource_t resource,
47 const xsd_QName * qname,
48 void ** property,
49 globus_xsd_type_info_t * info);
50
51 globus_result_t
52 globus_l_resource_set_any_property(
53 globus_resource_t resource,
54 const xsd_QName * qname,
55 void * property);
56
57 /**
58 * Get the value of the named Resource Property.
59 * @ingroup resource_property
60 *
61 * @param resource
62 * Resource containing the property.
63 * @param qname
64 * Name of the Resource Property element.
65 * @param property
66 * Pointer to return the value of the property.
67 * @param type_info
68 * Pointer to return the type info for this property. This may be NULL.
69 *
70 * @retval GLOBUS_SUCCESS
71 * Resource Property found and its value returned in @a property.
72 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
73 * One of the parameters to this function was NULL.
74 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
75 * The resource does not contain a property with the specified name.
76 */
77 globus_result_t
78 globus_resource_get_property(
79 globus_resource_t resource,
80 const xsd_QName * qname,
81 void ** property,
82 globus_xsd_type_info_t * type_info)
83 493518 {
84 493518 globus_result_t result = GLOBUS_SUCCESS;
85 493518 globus_resource_property_t * prop = NULL;
86 GlobusFuncName(globus_resource_get_property);
87
88 493518 if (resource == NULL || qname == NULL || property == NULL)
89 {
90 3 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
91 }
92
93 493515 *property = NULL;
94
95 493515 prop = globus_hashtable_lookup(
96 &resource->resource_properties,
97 (void *) qname);
98
99 493515 if (prop != NULL)
100 {
101 493396 if (prop->callback != NULL)
102 {
103 3 prop->callback(prop->callback_arg, qname, property);
104
105 3 if (prop->property != NULL)
106 {
107 1 prop->type_info->destroy(prop->property);
108 }
109 3 prop->property = *property;
110 }
111 else
112 {
113 493393 *property = prop->property;
114 }
115 493396 if (type_info != NULL)
116 {
117 493380 (*type_info) = prop->type_info;
118 }
119 }
120 else
121 {
122 119 result = globus_l_resource_get_any_property(
123 resource,
124 qname,
125 property,
126 type_info);
127
128 if (result != GLOBUS_SUCCESS)
129 {
130 goto out;
131 }
132 }
133
134 493515 out:
135 493515 return result;
136 }
137 /* globus_resource_get_property() */
138
139 /**
140 * Set the value of the named Resource Property.
141 * @ingroup resource_property
142 *
143 * Changes the current value of the named Resource Property to be that of
144 * the @a property parameter. If the Resource Property already had a value
145 * set by a previous call to this function or
146 * #globus_resource_create_property(), the old value will be destroyed, using
147 * the functions included in the type info associated with the property.
148 *
149 * @param resource
150 * Resource containing the property.
151 * @param qname
152 * Name of the Resource Property element.
153 * @param property
154 * New value of the property.
155 *
156 * @retval GLOBUS_SUCCESS
157 * Resource Property found and its value returned in @a property.
158 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
159 * One of the parameters to this function was NULL.
160 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
161 * The resource does not contain a property with the specified name.
162 */
163 globus_result_t
164 globus_resource_set_property(
165 globus_resource_t resource,
166 const xsd_QName * qname,
167 void * property)
168 315 {
169 315 globus_result_t result = GLOBUS_SUCCESS;
170 315 globus_resource_property_t * prop = NULL;
171 GlobusFuncName(globus_resource_set_property);
172
173 315 if (resource == NULL || qname == NULL)
174 {
175 2 result = GLOBUS_RESOURCE_ERROR_NULL_PARAM();
176
177 2 goto out;
178 }
179
180 313 prop = globus_hashtable_lookup(
181 &resource->resource_properties,
182 (void*) qname);
183
184 313 if (prop != NULL)
185 {
186 300 if (prop->property != NULL && prop->type_info->destroy != NULL)
187 {
188 262 prop->type_info->destroy(prop->property);
189 }
190
191 300 prop->property = property;
192 }
193 else
194 {
195 13 result = globus_l_resource_set_any_property(
196 resource,
197 qname,
198 property);
199 }
200
201 315 out:
202 315 return result;
203 }
204 /* globus_resource_set_property() */
205
206 /**
207 * Create a new Resource Property.
208 * @ingroup resource_property
209 *
210 * Modifies the resource to contain a new Resource Property with the given
211 * element name and type information. The initial value of the property will
212 * be set to the @a property parameter's value.
213 *
214 * @param resource
215 * Resource with which to associated the new resource property.
216 * @param qname
217 * Name of the resource property element.
218 * @param type_info
219 * XSD type mapping for this resource property type. This mapping
220 * describes how to access the value contained in the @a property
221 * parameter.
222 * @param property
223 * Initial value of the property.
224 *
225 * @retval GLOBUS_SUCCESS
226 * Property successfully created.
227 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
228 * One of the parameters to this function was NULL.
229 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
230 * A Resource Property with the given QName already exists in this
231 * resource.
232 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
233 * Not enough memory to allocate the new Resource Property.
234 */
235 globus_result_t
236 globus_resource_create_property(
237 globus_resource_t resource,
238 const xsd_QName * qname,
239 const globus_xsd_type_info_t type_info,
240 void * property)
241 352 {
242 352 return globus_l_resource_create_property(
243 resource,
244 qname,
245 type_info,
246 property,
247 NULL,
248 NULL);
249 }
250 /* globus_resource_create_property() */
251
252 /**
253 * Create a new dynamic-valued Resource Property.
254 * @ingroup resource_property
255 *
256 * Modifies the resource to contain a new Resource Property with the given
257 * element name and type information. The value of the property is determined
258 * by calling the callback function. Subsequent calls to
259 * globus_resource_get_property() will delete the previous value generated by
260 * the callback.
261 *
262 * @param resource
263 * Resource with which to associated the new resource property.
264 * @param qname
265 * Name of the resource property element.
266 * @param type_info
267 * XSD type mapping for this resource property type. This mapping
268 * describes how to access the value contained in the @a property
269 * parameter.
270 * @param callback
271 * Callback when creating a dynamic-valued Resource Property.
272 * @param callback_arg
273 * User-specific callback argument for dynamic Resource Property
274 * value callbacks.
275 *
276 * @retval GLOBUS_SUCCESS
277 * Property successfully created.
278 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
279 * One of the parameters to this function was NULL.
280 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
281 * A Resource Property with the given QName already exists in this
282 * resource.
283 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
284 * Not enough memory to allocate the new Resource Property.
285 */
286 globus_result_t
287 globus_resource_create_property_callback(
288 globus_resource_t resource,
289 const xsd_QName * qname,
290 const globus_xsd_type_info_t type_info,
291 globus_resource_property_callback_t callback,
292 void * callback_arg)
293 31 {
294 GlobusFuncName(globus_resource_create_property_callback);
295
296 31 if (callback == NULL)
297 {
298 1 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
299 }
300
301 30 return globus_l_resource_create_property(
302 resource,
303 qname,
304 type_info,
305 NULL,
306 callback,
307 callback_arg);
308 }
309 /* globus_resource_create_property_callback() */
310
311 /**
312 * Remove the named resource property from a resource.
313 * @ingroup resource_property
314 *
315 * The property's current value and type info is returned in the @a property
316 * and @a type_info parameters respectively.
317 *
318 * @param resource
319 * Resource containing the property.
320 * @param qname
321 * Element name of the resource property.
322 * @param property
323 * Pointer to be set to point to the value of the resource property.
324 * @param type_info
325 * Pointer to be set to type information about the property value.
326 *
327 * @retval GLOBUS_SUCCESS
328 * Resource Property successfully deleted.
329 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
330 * One of the parameters to this function was NULL.
331 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
332 * The resource does not contain a property with the specified name.
333 */
334 globus_result_t
335 globus_resource_delete_property(
336 globus_resource_t resource,
337 const xsd_QName * qname,
338 void ** property,
339 globus_xsd_type_info_t * type_info)
340 6 {
341 6 globus_resource_property_t * prop = NULL;
342 GlobusFuncName(globus_resource_delete_property);
343
344 6 if (resource == NULL || qname == NULL || property == NULL ||
345 type_info == NULL)
346 {
347 4 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
348 }
349
350 2 if (resource->resource_properties != NULL)
351 {
352 2 prop = globus_hashtable_remove(
353 &resource->resource_properties,
354 (void*) qname);
355 }
356
357 2 if (prop == NULL)
358 {
359 1 return GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
360 }
361
362 1 *property = prop->property;
363 1 *type_info = prop->type_info;
364
365 1 globus_free(prop->name.Namespace);
366 1 globus_free(prop->name.local);
367 1 globus_free(prop);
368
369 1 return GLOBUS_SUCCESS;
370 }
371 /* globus_resource_delete_property() */
372
373 /**
374 * Destroy a named resource property.
375 * @ingroup resource_property
376 *
377 * The current value of the property is destroyed. Subsequent attempts to
378 * access the property will fail.
379 *
380 * and @a type_info parameters respectively.
381 *
382 * @param resource
383 * Resource containing the property.
384 * @param qname
385 * Element name of the resource property.
386 * @retval GLOBUS_SUCCESS
387 * The property was successfully destroyed
388 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
389 * One of the parameters to this function was NULL.
390 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
391 * The resource does not contain a property with the specified name.
392 */
393 globus_result_t
394 globus_resource_destroy_property(
395 globus_resource_t resource,
396 const xsd_QName * qname)
397 6 {
398 6 globus_resource_property_t * prop = NULL;
399 GlobusFuncName(globus_resource_destroy_property);
400
401 6 if (resource == NULL || qname == NULL)
402 {
403 2 return GLOBUS_RESOURCE_ERROR_NULL_PARAM();
404 }
405
406 4 if (resource->resource_properties != NULL)
407 {
408 4 prop = globus_hashtable_remove(
409 &resource->resource_properties,
410 (void *) qname);
411 }
412
413 4 if (prop == NULL)
414 {
415 1 return GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
416 }
417
418 3 if (prop->property != NULL)
419 {
420 1 prop->type_info->destroy(prop->property);
421 }
422
423 3 free(prop->name.Namespace);
424 3 free(prop->name.local);
425 3 free(prop);
426
427 3 return GLOBUS_SUCCESS;
428 }
429 /* globus_resource_destroy_property() */
430
431 #ifndef GLOBUS_DONT_DOCUMENT_INTERNAL
432 /**
433 * Internal implementation of Resource Property creation.
434 *
435 * Modifies the resource to contain a new Resource Property with the given
436 * element name and type information. The initial value of the property will
437 * be set to the @a property parameter's value.
438 *
439 * @param resource
440 * Resource with which to associated the new resource property.
441 * @param qname
442 * Name of the resource property element.
443 * @param type_info
444 * XSD type mapping for this resource property type. This mapping
445 * describes how to access the value contained in the @a property
446 * parameter.
447 * @param property
448 * Initial value of the property.
449 * @param callback
450 * Callback when creating a dynamic-valued Resource Property.
451 * @param callback_arg
452 * User-specific callback argument for dynamic Resource Property
453 * value callbacks.
454 *
455 * @retval GLOBUS_SUCCESS
456 * Property successfully created.
457 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
458 * One of the parameters to this function was NULL.
459 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_DUPLICATE_PROPERTY
460 * A Resource Property with the given QName already exists in this
461 * resource.
462 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_OUT_OF_MEMORY
463 * Not enough memory to allocate the new Resource Property.
464 */
465 static
466 globus_result_t
467 globus_l_resource_create_property(
468 globus_resource_t resource,
469 const xsd_QName * qname,
470 const globus_xsd_type_info_t type_info,
471 void * property,
472 globus_resource_property_callback_t callback,
473 void * callback_arg)
474 382 {
475 globus_resource_property_t * prop;
476 globus_result_t result;
477 int rc;
478 GlobusFuncName(globus_l_resource_create_property);
479
480 382 if (resource == NULL || qname == NULL || type_info == NULL)
481 {
482 6 result = GLOBUS_RESOURCE_ERROR_NULL_PARAM();
483
484 6 goto error;
485 }
486
487 /* If the globus_resource_properties_any_qname is used for the property
488 * name, it must be either an any or any_array and must not have a callback
489 */
490 376 if (xsd_QName_keyeq(
491 (void *) qname,
492 (void *) globus_resource_properties_any_qname) &&
493 ((type_info != &xsd_any_info && type_info != &xsd_any_array_info)
494 || (callback != NULL)))
495 {
496 0 result = GLOBUS_RESOURCE_ERROR_INVALID_ANY();
497
498 0 goto error;
499 }
500
501 376 prop = globus_hashtable_lookup(
502 &resource->resource_properties,
503 (void *) qname);
504
505 376 if (prop != NULL)
506 {
507 2 result = GLOBUS_RESOURCE_ERROR_DUPLICATE_PROPERTY(qname);
508
509 2 goto error;
510 }
511 374 prop = malloc(sizeof(struct globus_resource_property_s));
512
513 374 if (prop == NULL)
514 {
515 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
516
517 0 goto error;
518 }
519
520 374 result = xsd_QName_copy_contents(&prop->name, qname);
521 374 if(result != GLOBUS_SUCCESS)
522 {
523 374 goto free_prop_error;
524 }
525 374 prop->type_info = type_info;
526 374 prop->property = property;
527 374 prop->callback = callback;
528 374 prop->callback_arg = callback_arg;
529
530 374 rc = globus_hashtable_insert(
531 &resource->resource_properties,
532 &prop->name,
533 prop);
534
535 374 if (rc != GLOBUS_SUCCESS)
536 {
537 0 result = GLOBUS_RESOURCE_ERROR_OUT_OF_MEMORY();
538
539 0 goto free_qname_error;
540 }
541
542 374 if (xsd_QName_keyeq(
543 (void *) qname,
544 (void *) globus_resource_properties_any_qname)
545 && prop->property == NULL)
546 {
547 10 result = prop->type_info->initialize(&prop->property);
548
549 10 if (result != GLOBUS_SUCCESS)
550 {
551 374 goto remove_from_hashtable_error;
552 }
553 }
554
555 374 return GLOBUS_SUCCESS;
556
557 0 remove_from_hashtable_error:
558 0 globus_hashtable_remove(&resource->resource_properties, &prop->name);
559 0 free_qname_error:
560 0 xsd_QName_destroy_contents(&prop->name);
561 0 free_prop_error:
562 0 globus_libc_free(prop);
563 8 error:
564 8 return result;
565 }
566 /* globus_l_resource_create_property() */
567
568 /**
569 * Check to see if we can match the qname in the resource's any:any property
570 * if it is present.
571 *
572 * @param resource
573 * Resource containing the property.
574 * @param qname
575 * Name of the Resource Property element.
576 * @param property
577 * Pointer to return the value of the property.
578 * @param type_info
579 * Pointer to return the type info for this property. This may be NULL.
580 *
581 * @retval GLOBUS_SUCCESS
582 * Resource Property found and its value returned in @a property.
583 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
584 * One of the parameters to this function was NULL.
585 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
586 * The resource does not contain a property with the specified name.
587 */
588 static
589 globus_result_t
590 globus_l_resource_get_any_property(
591 globus_resource_t resource,
592 const xsd_QName * qname,
593 void ** property,
594 globus_xsd_type_info_t * info)
595 119 {
596 119 globus_result_t result = GLOBUS_SUCCESS;
597 globus_resource_property_t * prop;
598
599 119 prop = globus_hashtable_lookup(
600 &resource->resource_properties,
601 (void *) globus_resource_properties_any_qname);
602
603 119 if (prop == NULL)
604 {
605 17 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
606
607 17 goto out;
608 }
609
610 102 if (prop->type_info == &xsd_any_info)
611 {
612 56 xsd_any * any = prop->property;
613
614 56 if (any->element != NULL &&
615 !xsd_QName_keyeq((void *) any->element, (void *) qname))
616 {
617 12 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
618
619 12 goto out;
620 }
621 44 *property = any;
622 }
623 46 else if (prop->type_info == &xsd_any_array_info)
624 {
625 46 xsd_any_array * any_array = prop->property;
626 int i;
627
628 64 for (i = 0; i < any_array->length; i++)
629 {
630 48 if (any_array->elements[i].element == NULL)
631 {
632 6 *property = &any_array->elements[i];
633 6 break;
634 }
635 42 else if (xsd_QName_keyeq(
636 any_array->elements[i].element,
637 (void *) qname))
638 {
639 24 *property = &any_array->elements[i];
640 24 break;
641 }
642 }
643 46 if (i == any_array->length)
644 {
645 16 xsd_any * any = xsd_any_array_push(any_array);
646 16 any->any_info = &xsd_any_array_info;
647 16 *property = any;
648 }
649 }
650 90 if (info != NULL)
651 {
652 90 *info = &xsd_any_info;
653 }
654 119 out:
655 119 return result;
656 }
657 /* globus_l_resource_get_any_property() */
658
659 /**
660 * Set the value of a named resource property stored within the special
661 * "any:any" resource property.
662 *
663 * Changes the current value of the named Resource Property to be that of
664 * the @a property parameter. If the Resource Property already had a value
665 * set by a previous call to this function or
666 * #globus_resource_create_property(), the old value will be destroyed, using
667 * the functions included in the type info associated with the property. If
668 * the @a property parameter is NULL and this is in the any resource property,
669 * it will be removed.
670 *
671 * @param resource
672 * Resource containing the property.
673 * @param qname
674 * Name of the Resource Property element.
675 * @param property
676 * New value of the property.
677 *
678 * @retval GLOBUS_SUCCESS
679 * Resource Property found and its value returned in @a property.
680 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_NULL_PARAM
681 * One of the parameters to this function was NULL.
682 * @retval GLOBUS_WSRF_RESOURCE_ERROR_TYPE_UNKNOWN_PROPERTY
683 * The resource does not contain a property with the specified name.
684 */
685 globus_result_t
686 globus_l_resource_set_any_property(
687 globus_resource_t resource,
688 const xsd_QName * qname,
689 void * property)
690 13 {
691 13 globus_result_t result = GLOBUS_SUCCESS;
692 13 globus_resource_property_t * prop = NULL;
693 xsd_any * any;
694 xsd_any_array * any_array;
695 int i;
696 GlobusFuncName(globus_l_resource_set_any_property);
697
698 13 prop = globus_hashtable_lookup(
699 &resource->resource_properties,
700 (void*) globus_resource_properties_any_qname);
701
702 13 if (prop == NULL)
703 {
704 1 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
705
706 1 goto out;
707 }
708
709 12 if (prop->type_info == &xsd_any_info)
710 {
711 /* Single any element */
712 8 any = prop->property;
713
714 8 if (any->element == NULL ||
715 xsd_QName_keyeq(any->element, (void *) qname))
716 {
717 /* The element name matches, so we'll destroy the old value */
718 8 if (any->value != NULL)
719 {
720 8 any->any_info->destroy(any->value);
721 8 any->value = NULL;
722 }
723 /*
724 * Insert the new prop value if we have one; otherwise, we remove
725 * the binding of the QName to this any.
726 */
727 8 if (property != NULL)
728 {
729 0 any->value = property;
730 }
731 else
732 {
733 8 any->value = NULL;
734 8 if (any->element != NULL)
735 {
736 8 xsd_QName_destroy(any->element);
737 8 any->element = NULL;
738 }
739 8 any->any_info = NULL;
740 }
741 }
742 else
743 {
744 /* element name doesn't match */
745 0 result = GLOBUS_RESOURCE_ERROR_UNKNOWN_PROPERTY(qname);
746
747 0 goto out;
748 }
749 }
750 else
751 {
752 4 assert(prop->type_info == &xsd_any_array_info);
753 4 any_array = prop->property;
754
755 /* The value is an array of anys. We'll look for the one which
756 * matches our qname, and replace its contents with the new value.
757 * if property is null, we'll remove it from the array altogether
758 */
759 4 for (i = 0; i < any_array->length; i++)
760 {
761 4 any = &any_array->elements[i];
762
763 4 if (any->element != NULL &&
764 xsd_QName_keyeq(any->element, (void *) qname))
765 {
766 /* found a match */
767 4 if (any->value != NULL)
768 {
769 /* old value -- gone! */
770 4 any->any_info->destroy(any->value);
771 4 any->value = NULL;
772 }
773 4 if (property != NULL)
774 {
775 /* replace with new value */
776 0 any->value = property;
777 }
778 else
779 {
780 /* delete binding for this QName */
781 4 xsd_QName_destroy(any->element);
782 4 any->element = NULL;
783
784 4 if (i + 1 < any_array->length)
785 {
786 /* pop this array element out of the array */
787 4 memmove(
788 &any_array->elements[i],
789 &any_array->elements[i+1],
790 sizeof(any_array->elements[i]) *
791 (any_array->length - (i + 1)));
792 }
793 /* And clear value at the tail of this array */
794 4 memset(&any_array->elements[any_array->length-1],
795 0,
796 sizeof(any_array->elements[i]));
797 4 any_array->length--;
798 }
799 break; /* only one match will be possible */
800 }
801 }
802 }
803 13 out:
804 13 return result;
805 }