Annotation of embedaddon/php/ext/spl/spl_array.c, revision 1.1.1.4
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 6: +----------------------------------------------------------------------+
7: | This source file is subject to version 3.01 of the PHP license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.php.net/license/3_01.txt |
11: | If you did not receive a copy of the PHP license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@php.net so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Marcus Boerger <helly@php.net> |
16: +----------------------------------------------------------------------+
17: */
18:
1.1.1.2 misho 19: /* $Id$ */
1.1 misho 20:
21: #ifdef HAVE_CONFIG_H
22: # include "config.h"
23: #endif
24:
25: #include "php.h"
26: #include "php_ini.h"
27: #include "ext/standard/info.h"
28: #include "ext/standard/php_var.h"
29: #include "ext/standard/php_smart_str.h"
30: #include "zend_interfaces.h"
31: #include "zend_exceptions.h"
32:
33: #include "php_spl.h"
34: #include "spl_functions.h"
35: #include "spl_engine.h"
36: #include "spl_iterators.h"
37: #include "spl_array.h"
38: #include "spl_exceptions.h"
39:
40: zend_object_handlers spl_handler_ArrayObject;
41: PHPAPI zend_class_entry *spl_ce_ArrayObject;
42:
43: zend_object_handlers spl_handler_ArrayIterator;
44: PHPAPI zend_class_entry *spl_ce_ArrayIterator;
45: PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
46:
47: #define SPL_ARRAY_STD_PROP_LIST 0x00000001
48: #define SPL_ARRAY_ARRAY_AS_PROPS 0x00000002
49: #define SPL_ARRAY_CHILD_ARRAYS_ONLY 0x00000004
50: #define SPL_ARRAY_OVERLOADED_REWIND 0x00010000
51: #define SPL_ARRAY_OVERLOADED_VALID 0x00020000
52: #define SPL_ARRAY_OVERLOADED_KEY 0x00040000
53: #define SPL_ARRAY_OVERLOADED_CURRENT 0x00080000
54: #define SPL_ARRAY_OVERLOADED_NEXT 0x00100000
55: #define SPL_ARRAY_IS_REF 0x01000000
56: #define SPL_ARRAY_IS_SELF 0x02000000
57: #define SPL_ARRAY_USE_OTHER 0x04000000
58: #define SPL_ARRAY_INT_MASK 0xFFFF0000
59: #define SPL_ARRAY_CLONE_MASK 0x0300FFFF
60:
1.1.1.3 misho 61: #define SPL_ARRAY_METHOD_NO_ARG 0
62: #define SPL_ARRAY_METHOD_USE_ARG 1
63: #define SPL_ARRAY_METHOD_MAY_USER_ARG 2
64:
1.1 misho 65: typedef struct _spl_array_object {
1.1.1.2 misho 66: zend_object std;
67: zval *array;
68: zval *retval;
69: HashPosition pos;
70: ulong pos_h;
71: int ar_flags;
72: int is_self;
73: zend_function *fptr_offset_get;
74: zend_function *fptr_offset_set;
75: zend_function *fptr_offset_has;
76: zend_function *fptr_offset_del;
77: zend_function *fptr_count;
78: zend_class_entry* ce_get_iterator;
1.1 misho 79: HashTable *debug_info;
80: unsigned char nApplyCount;
81: } spl_array_object;
82:
83: static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int check_std_props TSRMLS_DC) { /* {{{ */
84: if ((intern->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
1.1.1.2 misho 85: if (!intern->std.properties) {
86: rebuild_object_properties(&intern->std);
87: }
1.1 misho 88: return intern->std.properties;
89: } else if ((intern->ar_flags & SPL_ARRAY_USE_OTHER) && (check_std_props == 0 || (intern->ar_flags & SPL_ARRAY_STD_PROP_LIST) == 0) && Z_TYPE_P(intern->array) == IS_OBJECT) {
90: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(intern->array TSRMLS_CC);
91: return spl_array_get_hash_table(other, check_std_props TSRMLS_CC);
92: } else if ((intern->ar_flags & ((check_std_props ? SPL_ARRAY_STD_PROP_LIST : 0) | SPL_ARRAY_IS_SELF)) != 0) {
1.1.1.2 misho 93: if (!intern->std.properties) {
94: rebuild_object_properties(&intern->std);
95: }
1.1 misho 96: return intern->std.properties;
97: } else {
98: return HASH_OF(intern->array);
99: }
100: } /* }}} */
101:
102: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC);
103:
104: static void spl_array_update_pos(spl_array_object* intern) /* {{{ */
105: {
106: Bucket *pos = intern->pos;
107: if (pos != NULL) {
108: intern->pos_h = pos->h;
109: }
110: } /* }}} */
111:
112: static void spl_array_set_pos(spl_array_object* intern, HashPosition pos) /* {{{ */
113: {
114: intern->pos = pos;
115: spl_array_update_pos(intern);
116: } /* }}} */
117:
118: SPL_API int spl_hash_verify_pos_ex(spl_array_object * intern, HashTable * ht TSRMLS_DC) /* {{{ */
119: {
120: Bucket *p;
121:
122: /* IS_CONSISTENT(ht);*/
123:
124: /* HASH_PROTECT_RECURSION(ht);*/
125: p = ht->arBuckets[intern->pos_h & ht->nTableMask];
126: while (p != NULL) {
127: if (p == intern->pos) {
128: return SUCCESS;
129: }
130: p = p->pNext;
131: }
132: /* HASH_UNPROTECT_RECURSION(ht); */
133: spl_array_rewind(intern TSRMLS_CC);
134: return FAILURE;
135:
136: } /* }}} */
137:
138: SPL_API int spl_hash_verify_pos(spl_array_object * intern TSRMLS_DC) /* {{{ */
139: {
140: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
141: return spl_hash_verify_pos_ex(intern, ht TSRMLS_CC);
142: }
143: /* }}} */
144:
145: /* {{{ spl_array_object_free_storage */
146: static void spl_array_object_free_storage(void *object TSRMLS_DC)
147: {
148: spl_array_object *intern = (spl_array_object *)object;
149:
150: zend_object_std_dtor(&intern->std TSRMLS_CC);
151:
152: zval_ptr_dtor(&intern->array);
153: zval_ptr_dtor(&intern->retval);
154:
155: if (intern->debug_info != NULL) {
156: zend_hash_destroy(intern->debug_info);
157: efree(intern->debug_info);
158: }
159:
160: efree(object);
161: }
162: /* }}} */
163:
164: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC);
165:
166: /* {{{ spl_array_object_new_ex */
167: static zend_object_value spl_array_object_new_ex(zend_class_entry *class_type, spl_array_object **obj, zval *orig, int clone_orig TSRMLS_DC)
168: {
1.1.1.4 ! misho 169: zend_object_value retval = {0};
1.1 misho 170: spl_array_object *intern;
171: zval *tmp;
172: zend_class_entry * parent = class_type;
173: int inherited = 0;
174:
175: intern = emalloc(sizeof(spl_array_object));
176: memset(intern, 0, sizeof(spl_array_object));
177: *obj = intern;
178: ALLOC_INIT_ZVAL(intern->retval);
179:
180: zend_object_std_init(&intern->std, class_type TSRMLS_CC);
1.1.1.2 misho 181: object_properties_init(&intern->std, class_type);
1.1 misho 182:
183: intern->ar_flags = 0;
184: intern->debug_info = NULL;
185: intern->ce_get_iterator = spl_ce_ArrayIterator;
186: if (orig) {
187: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(orig TSRMLS_CC);
188:
189: intern->ar_flags &= ~ SPL_ARRAY_CLONE_MASK;
190: intern->ar_flags |= (other->ar_flags & SPL_ARRAY_CLONE_MASK);
191: intern->ce_get_iterator = other->ce_get_iterator;
192: if (clone_orig) {
193: intern->array = other->array;
194: if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayObject) {
195: MAKE_STD_ZVAL(intern->array);
196: array_init(intern->array);
197: zend_hash_copy(HASH_OF(intern->array), HASH_OF(other->array), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
198: }
199: if (Z_OBJ_HT_P(orig) == &spl_handler_ArrayIterator) {
200: Z_ADDREF_P(other->array);
201: }
202: } else {
203: intern->array = orig;
204: Z_ADDREF_P(intern->array);
205: intern->ar_flags |= SPL_ARRAY_IS_REF | SPL_ARRAY_USE_OTHER;
206: }
207: } else {
208: MAKE_STD_ZVAL(intern->array);
209: array_init(intern->array);
210: intern->ar_flags &= ~SPL_ARRAY_IS_REF;
211: }
212:
213: retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) spl_array_object_free_storage, NULL TSRMLS_CC);
214: while (parent) {
215: if (parent == spl_ce_ArrayIterator || parent == spl_ce_RecursiveArrayIterator) {
216: retval.handlers = &spl_handler_ArrayIterator;
217: class_type->get_iterator = spl_array_get_iterator;
218: break;
219: } else if (parent == spl_ce_ArrayObject) {
220: retval.handlers = &spl_handler_ArrayObject;
221: break;
222: }
223: parent = parent->parent;
224: inherited = 1;
225: }
226: if (!parent) { /* this must never happen */
227: php_error_docref(NULL TSRMLS_CC, E_COMPILE_ERROR, "Internal compiler error, Class is not child of ArrayObject or ArrayIterator");
228: }
229: if (inherited) {
230: zend_hash_find(&class_type->function_table, "offsetget", sizeof("offsetget"), (void **) &intern->fptr_offset_get);
231: if (intern->fptr_offset_get->common.scope == parent) {
232: intern->fptr_offset_get = NULL;
233: }
234: zend_hash_find(&class_type->function_table, "offsetset", sizeof("offsetset"), (void **) &intern->fptr_offset_set);
235: if (intern->fptr_offset_set->common.scope == parent) {
236: intern->fptr_offset_set = NULL;
237: }
238: zend_hash_find(&class_type->function_table, "offsetexists", sizeof("offsetexists"), (void **) &intern->fptr_offset_has);
239: if (intern->fptr_offset_has->common.scope == parent) {
240: intern->fptr_offset_has = NULL;
241: }
242: zend_hash_find(&class_type->function_table, "offsetunset", sizeof("offsetunset"), (void **) &intern->fptr_offset_del);
243: if (intern->fptr_offset_del->common.scope == parent) {
244: intern->fptr_offset_del = NULL;
245: }
246: zend_hash_find(&class_type->function_table, "count", sizeof("count"), (void **) &intern->fptr_count);
247: if (intern->fptr_count->common.scope == parent) {
248: intern->fptr_count = NULL;
249: }
250: }
251: /* Cache iterator functions if ArrayIterator or derived. Check current's */
252: /* cache since only current is always required */
253: if (retval.handlers == &spl_handler_ArrayIterator) {
254: if (!class_type->iterator_funcs.zf_current) {
255: zend_hash_find(&class_type->function_table, "rewind", sizeof("rewind"), (void **) &class_type->iterator_funcs.zf_rewind);
256: zend_hash_find(&class_type->function_table, "valid", sizeof("valid"), (void **) &class_type->iterator_funcs.zf_valid);
257: zend_hash_find(&class_type->function_table, "key", sizeof("key"), (void **) &class_type->iterator_funcs.zf_key);
258: zend_hash_find(&class_type->function_table, "current", sizeof("current"), (void **) &class_type->iterator_funcs.zf_current);
259: zend_hash_find(&class_type->function_table, "next", sizeof("next"), (void **) &class_type->iterator_funcs.zf_next);
260: }
261: if (inherited) {
262: if (class_type->iterator_funcs.zf_rewind->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_REWIND;
263: if (class_type->iterator_funcs.zf_valid->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_VALID;
264: if (class_type->iterator_funcs.zf_key->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_KEY;
265: if (class_type->iterator_funcs.zf_current->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_CURRENT;
266: if (class_type->iterator_funcs.zf_next->common.scope != parent) intern->ar_flags |= SPL_ARRAY_OVERLOADED_NEXT;
267: }
268: }
269:
270: spl_array_rewind(intern TSRMLS_CC);
271: return retval;
272: }
273: /* }}} */
274:
275: /* {{{ spl_array_object_new */
276: static zend_object_value spl_array_object_new(zend_class_entry *class_type TSRMLS_DC)
277: {
278: spl_array_object *tmp;
279: return spl_array_object_new_ex(class_type, &tmp, NULL, 0 TSRMLS_CC);
280: }
281: /* }}} */
282:
283: /* {{{ spl_array_object_clone */
284: static zend_object_value spl_array_object_clone(zval *zobject TSRMLS_DC)
285: {
286: zend_object_value new_obj_val;
287: zend_object *old_object;
288: zend_object *new_object;
289: zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
290: spl_array_object *intern;
291:
292: old_object = zend_objects_get_address(zobject TSRMLS_CC);
293: new_obj_val = spl_array_object_new_ex(old_object->ce, &intern, zobject, 1 TSRMLS_CC);
294: new_object = &intern->std;
295:
296: zend_objects_clone_members(new_object, new_obj_val, old_object, handle TSRMLS_CC);
297:
298: return new_obj_val;
299: }
300: /* }}} */
301:
302: static zval **spl_array_get_dimension_ptr_ptr(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
303: {
304: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
305: zval **retval;
306: long index;
307: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
308:
309: if (!offset) {
310: return &EG(uninitialized_zval_ptr);
311: }
312:
313: if ((type == BP_VAR_W || type == BP_VAR_RW) && (ht->nApplyCount > 0)) {
314: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
1.1.1.3 misho 315: return &EG(error_zval_ptr);;
1.1 misho 316: }
317:
318: switch(Z_TYPE_P(offset)) {
1.1.1.3 misho 319: case IS_NULL:
320: Z_STRVAL_P(offset) = "";
321: Z_STRLEN_P(offset) = 0;
1.1 misho 322: case IS_STRING:
323: if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &retval) == FAILURE) {
1.1.1.3 misho 324: switch (type) {
325: case BP_VAR_R:
326: zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(offset));
327: case BP_VAR_UNSET:
328: case BP_VAR_IS:
329: retval = &EG(uninitialized_zval_ptr);
330: break;
331: case BP_VAR_RW:
332: zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
333: case BP_VAR_W: {
334: zval *value;
335: ALLOC_INIT_ZVAL(value);
336: zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), (void **)&retval);
1.1.1.2 misho 337: }
1.1 misho 338: }
339: }
1.1.1.3 misho 340: return retval;
1.1 misho 341: case IS_RESOURCE:
1.1.1.3 misho 342: zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(offset), Z_LVAL_P(offset));
343: case IS_DOUBLE:
1.1 misho 344: case IS_BOOL:
345: case IS_LONG:
346: if (offset->type == IS_DOUBLE) {
347: index = (long)Z_DVAL_P(offset);
348: } else {
349: index = Z_LVAL_P(offset);
350: }
351: if (zend_hash_index_find(ht, index, (void **) &retval) == FAILURE) {
1.1.1.3 misho 352: switch (type) {
353: case BP_VAR_R:
354: zend_error(E_NOTICE, "Undefined offset: %ld", index);
355: case BP_VAR_UNSET:
356: case BP_VAR_IS:
357: retval = &EG(uninitialized_zval_ptr);
358: break;
359: case BP_VAR_RW:
360: zend_error(E_NOTICE, "Undefined offset: %ld", index);
361: case BP_VAR_W: {
362: zval *value;
363: ALLOC_INIT_ZVAL(value);
364: zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), (void **)&retval);
365: }
1.1 misho 366: }
367: }
1.1.1.3 misho 368: return retval;
1.1 misho 369: default:
370: zend_error(E_WARNING, "Illegal offset type");
1.1.1.3 misho 371: return (type == BP_VAR_W || type == BP_VAR_RW) ?
372: &EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
1.1 misho 373: }
374: } /* }}} */
375:
376: static zval *spl_array_read_dimension_ex(int check_inherited, zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
377: {
378: zval **ret;
379:
380: if (check_inherited) {
381: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
382: if (intern->fptr_offset_get) {
383: zval *rv;
1.1.1.3 misho 384: if (!offset) {
385: ALLOC_INIT_ZVAL(offset);
386: } else {
387: SEPARATE_ARG_IF_REF(offset);
388: }
1.1 misho 389: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_get, "offsetGet", &rv, offset);
390: zval_ptr_dtor(&offset);
391: if (rv) {
392: zval_ptr_dtor(&intern->retval);
393: MAKE_STD_ZVAL(intern->retval);
394: ZVAL_ZVAL(intern->retval, rv, 1, 1);
395: return intern->retval;
396: }
397: return EG(uninitialized_zval_ptr);
398: }
399: }
400: ret = spl_array_get_dimension_ptr_ptr(check_inherited, object, offset, type TSRMLS_CC);
401:
402: /* When in a write context,
403: * ZE has to be fooled into thinking this is in a reference set
404: * by separating (if necessary) and returning as an is_ref=1 zval (even if refcount == 1) */
1.1.1.3 misho 405: if ((type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) && !Z_ISREF_PP(ret)) {
1.1 misho 406: if (Z_REFCOUNT_PP(ret) > 1) {
407: zval *newval;
408:
409: /* Separate */
410: MAKE_STD_ZVAL(newval);
411: *newval = **ret;
412: zval_copy_ctor(newval);
413: Z_SET_REFCOUNT_P(newval, 1);
414:
415: /* Replace */
416: Z_DELREF_PP(ret);
417: *ret = newval;
418: }
419:
420: Z_SET_ISREF_PP(ret);
421: }
422:
423: return *ret;
424: } /* }}} */
425:
426: static zval *spl_array_read_dimension(zval *object, zval *offset, int type TSRMLS_DC) /* {{{ */
427: {
428: return spl_array_read_dimension_ex(1, object, offset, type TSRMLS_CC);
429: } /* }}} */
430:
431: static void spl_array_write_dimension_ex(int check_inherited, zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
432: {
433: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
434: long index;
435: HashTable *ht;
436:
437: if (check_inherited && intern->fptr_offset_set) {
438: if (!offset) {
439: ALLOC_INIT_ZVAL(offset);
440: } else {
441: SEPARATE_ARG_IF_REF(offset);
442: }
443: zend_call_method_with_2_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_set, "offsetSet", NULL, offset, value);
444: zval_ptr_dtor(&offset);
445: return;
446: }
447:
448: if (!offset) {
449: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
450: if (ht->nApplyCount > 0) {
451: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
452: return;
453: }
454: Z_ADDREF_P(value);
455: zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
456: return;
457: }
458: switch(Z_TYPE_P(offset)) {
459: case IS_STRING:
460: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
461: if (ht->nApplyCount > 0) {
462: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
463: return;
464: }
465: Z_ADDREF_P(value);
466: zend_symtable_update(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void**)&value, sizeof(void*), NULL);
467: return;
468: case IS_DOUBLE:
469: case IS_RESOURCE:
470: case IS_BOOL:
471: case IS_LONG:
472: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
473: if (ht->nApplyCount > 0) {
474: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
475: return;
476: }
477: if (offset->type == IS_DOUBLE) {
478: index = (long)Z_DVAL_P(offset);
479: } else {
480: index = Z_LVAL_P(offset);
481: }
482: Z_ADDREF_P(value);
483: zend_hash_index_update(ht, index, (void**)&value, sizeof(void*), NULL);
484: return;
485: case IS_NULL:
486: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
487: if (ht->nApplyCount > 0) {
488: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
489: return;
490: }
491: Z_ADDREF_P(value);
492: zend_hash_next_index_insert(ht, (void**)&value, sizeof(void*), NULL);
493: return;
494: default:
495: zend_error(E_WARNING, "Illegal offset type");
496: return;
497: }
498: } /* }}} */
499:
500: static void spl_array_write_dimension(zval *object, zval *offset, zval *value TSRMLS_DC) /* {{{ */
501: {
502: spl_array_write_dimension_ex(1, object, offset, value TSRMLS_CC);
503: } /* }}} */
504:
505: static void spl_array_unset_dimension_ex(int check_inherited, zval *object, zval *offset TSRMLS_DC) /* {{{ */
506: {
507: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
508: long index;
509: HashTable *ht;
510:
511: if (check_inherited && intern->fptr_offset_del) {
512: SEPARATE_ARG_IF_REF(offset);
513: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_del, "offsetUnset", NULL, offset);
514: zval_ptr_dtor(&offset);
515: return;
516: }
517:
518: switch(Z_TYPE_P(offset)) {
519: case IS_STRING:
520: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
521: if (ht->nApplyCount > 0) {
522: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
523: return;
524: }
525: if (ht == &EG(symbol_table)) {
526: if (zend_delete_global_variable(Z_STRVAL_P(offset), Z_STRLEN_P(offset) TSRMLS_CC)) {
1.1.1.3 misho 527: zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
1.1 misho 528: }
529: } else {
530: if (zend_symtable_del(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1) == FAILURE) {
1.1.1.3 misho 531: zend_error(E_NOTICE,"Undefined index: %s", Z_STRVAL_P(offset));
1.1.1.2 misho 532: } else {
533: spl_array_object *obj = intern;
534:
535: while (1) {
536: if ((obj->ar_flags & SPL_ARRAY_IS_SELF) != 0) {
537: break;
538: } else if (Z_TYPE_P(obj->array) == IS_OBJECT) {
539: if ((obj->ar_flags & SPL_ARRAY_USE_OTHER) == 0) {
540: obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
541: break;
542: } else {
543: obj = (spl_array_object*)zend_object_store_get_object(obj->array TSRMLS_CC);
544: }
545: } else {
546: obj = NULL;
547: break;
548: }
549: }
550: if (obj) {
551: zend_property_info *property_info = zend_get_property_info(obj->std.ce, offset, 1 TSRMLS_CC);
552:
553: if (property_info &&
554: (property_info->flags & ZEND_ACC_STATIC) == 0 &&
555: property_info->offset >= 0) {
556: obj->std.properties_table[property_info->offset] = NULL;
557: }
558: }
559: }
1.1 misho 560: }
561: break;
562: case IS_DOUBLE:
563: case IS_RESOURCE:
564: case IS_BOOL:
565: case IS_LONG:
566: if (offset->type == IS_DOUBLE) {
567: index = (long)Z_DVAL_P(offset);
568: } else {
569: index = Z_LVAL_P(offset);
570: }
571: ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
572: if (ht->nApplyCount > 0) {
573: zend_error(E_WARNING, "Modification of ArrayObject during sorting is prohibited");
574: return;
575: }
576: if (zend_hash_index_del(ht, index) == FAILURE) {
1.1.1.3 misho 577: zend_error(E_NOTICE,"Undefined offset: %ld", Z_LVAL_P(offset));
1.1 misho 578: }
579: break;
580: default:
581: zend_error(E_WARNING, "Illegal offset type");
582: return;
583: }
584: spl_hash_verify_pos(intern TSRMLS_CC); /* call rewind on FAILURE */
585: } /* }}} */
586:
587: static void spl_array_unset_dimension(zval *object, zval *offset TSRMLS_DC) /* {{{ */
588: {
589: spl_array_unset_dimension_ex(1, object, offset TSRMLS_CC);
590: } /* }}} */
591:
592: static int spl_array_has_dimension_ex(int check_inherited, zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
593: {
594: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
595: long index;
596: zval *rv, **tmp;
597:
598: if (check_inherited && intern->fptr_offset_has) {
599: SEPARATE_ARG_IF_REF(offset);
600: zend_call_method_with_1_params(&object, Z_OBJCE_P(object), &intern->fptr_offset_has, "offsetExists", &rv, offset);
601: zval_ptr_dtor(&offset);
602: if (rv && zend_is_true(rv)) {
603: zval_ptr_dtor(&rv);
604: return 1;
605: }
606: if (rv) {
607: zval_ptr_dtor(&rv);
608: }
609: return 0;
610: }
611:
612: switch(Z_TYPE_P(offset)) {
1.1.1.2 misho 613: case IS_STRING:
614: {
615: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
616: if (zend_symtable_find(ht, Z_STRVAL_P(offset), Z_STRLEN_P(offset)+1, (void **) &tmp) != FAILURE) {
617: switch (check_empty) {
618: case 0:
619: return Z_TYPE_PP(tmp) != IS_NULL;
620: case 2:
621: return 1;
622: default:
623: return zend_is_true(*tmp);
624: }
1.1 misho 625: }
626: }
627: return 0;
1.1.1.2 misho 628: case IS_DOUBLE:
629: case IS_RESOURCE:
630: case IS_BOOL:
631: case IS_LONG:
632: {
633: HashTable *ht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
634: if (offset->type == IS_DOUBLE) {
635: index = (long)Z_DVAL_P(offset);
636: } else {
637: index = Z_LVAL_P(offset);
1.1 misho 638: }
1.1.1.2 misho 639: if (zend_hash_index_find(ht, index, (void **)&tmp) != FAILURE) {
640: switch (check_empty) {
641: case 0:
642: return Z_TYPE_PP(tmp) != IS_NULL;
643: case 2:
644: return 1;
645: default:
646: return zend_is_true(*tmp);
647: }
648: }
649: return 0;
1.1 misho 650: }
1.1.1.2 misho 651: default:
652: zend_error(E_WARNING, "Illegal offset type");
1.1 misho 653: }
654: return 0;
655: } /* }}} */
656:
657: static int spl_array_has_dimension(zval *object, zval *offset, int check_empty TSRMLS_DC) /* {{{ */
658: {
659: return spl_array_has_dimension_ex(1, object, offset, check_empty TSRMLS_CC);
660: } /* }}} */
661:
1.1.1.3 misho 662: /* {{{ spl_array_object_verify_pos_ex */
663: static inline int spl_array_object_verify_pos_ex(spl_array_object *object, HashTable *ht, const char *msg_prefix TSRMLS_DC)
664: {
665: if (!ht) {
666: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and is no longer an array", msg_prefix);
667: return FAILURE;
668: }
669:
670: if (object->pos && (object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, ht TSRMLS_CC) == FAILURE) {
671: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%sArray was modified outside object and internal position is no longer valid", msg_prefix);
672: return FAILURE;
673: }
674:
675: return SUCCESS;
676: } /* }}} */
677:
678: /* {{{ spl_array_object_verify_pos */
679: static inline int spl_array_object_verify_pos(spl_array_object *object, HashTable *ht TSRMLS_DC)
680: {
681: return spl_array_object_verify_pos_ex(object, ht, "" TSRMLS_CC);
682: } /* }}} */
683:
1.1 misho 684: /* {{{ proto bool ArrayObject::offsetExists(mixed $index)
685: proto bool ArrayIterator::offsetExists(mixed $index)
686: Returns whether the requested $index exists. */
687: SPL_METHOD(Array, offsetExists)
688: {
689: zval *index;
690: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
691: return;
692: }
1.1.1.2 misho 693: RETURN_BOOL(spl_array_has_dimension_ex(0, getThis(), index, 2 TSRMLS_CC));
1.1 misho 694: } /* }}} */
695:
696: /* {{{ proto mixed ArrayObject::offsetGet(mixed $index)
697: proto mixed ArrayIterator::offsetGet(mixed $index)
698: Returns the value at the specified $index. */
699: SPL_METHOD(Array, offsetGet)
700: {
701: zval *index, *value;
702: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
703: return;
704: }
705: value = spl_array_read_dimension_ex(0, getThis(), index, BP_VAR_R TSRMLS_CC);
706: RETURN_ZVAL(value, 1, 0);
707: } /* }}} */
708:
709: /* {{{ proto void ArrayObject::offsetSet(mixed $index, mixed $newval)
710: proto void ArrayIterator::offsetSet(mixed $index, mixed $newval)
711: Sets the value at the specified $index to $newval. */
712: SPL_METHOD(Array, offsetSet)
713: {
714: zval *index, *value;
715: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &index, &value) == FAILURE) {
716: return;
717: }
718: spl_array_write_dimension_ex(0, getThis(), index, value TSRMLS_CC);
719: } /* }}} */
720:
721: void spl_array_iterator_append(zval *object, zval *append_value TSRMLS_DC) /* {{{ */
722: {
723: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
724: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
725:
726: if (!aht) {
727: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
728: return;
729: }
730:
731: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
732: php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "Cannot append properties to objects, use %s::offsetSet() instead", Z_OBJCE_P(object)->name);
733: return;
734: }
735:
736: spl_array_write_dimension(object, NULL, append_value TSRMLS_CC);
737: if (!intern->pos) {
738: spl_array_set_pos(intern, aht->pListTail);
739: }
740: } /* }}} */
741:
742: /* {{{ proto void ArrayObject::append(mixed $newval)
743: proto void ArrayIterator::append(mixed $newval)
744: Appends the value (cannot be called for objects). */
745: SPL_METHOD(Array, append)
746: {
747: zval *value;
748:
749: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
750: return;
751: }
752: spl_array_iterator_append(getThis(), value TSRMLS_CC);
753: } /* }}} */
754:
755: /* {{{ proto void ArrayObject::offsetUnset(mixed $index)
756: proto void ArrayIterator::offsetUnset(mixed $index)
757: Unsets the value at the specified $index. */
758: SPL_METHOD(Array, offsetUnset)
759: {
760: zval *index;
761: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &index) == FAILURE) {
762: return;
763: }
764: spl_array_unset_dimension_ex(0, getThis(), index TSRMLS_CC);
765: } /* }}} */
766:
767: /* {{{ proto array ArrayObject::getArrayCopy()
768: proto array ArrayIterator::getArrayCopy()
769: Return a copy of the contained array */
770: SPL_METHOD(Array, getArrayCopy)
771: {
772: zval *object = getThis(), *tmp;
773: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
774:
775: array_init(return_value);
776: zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
777: } /* }}} */
778:
779: static HashTable *spl_array_get_properties(zval *object TSRMLS_DC) /* {{{ */
780: {
781: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
782: HashTable *result;
783:
784: if (intern->nApplyCount > 1) {
785: php_error_docref(NULL TSRMLS_CC, E_ERROR, "Nesting level too deep - recursive dependency?");
786: }
787:
788: intern->nApplyCount++;
789: result = spl_array_get_hash_table(intern, 1 TSRMLS_CC);
790: intern->nApplyCount--;
791: return result;
792: } /* }}} */
793:
794: static HashTable* spl_array_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
795: {
796: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(obj TSRMLS_CC);
797: zval *tmp, *storage;
798: int name_len;
799: char *zname;
800: zend_class_entry *base;
801:
802: *is_temp = 0;
803:
1.1.1.2 misho 804: if (!intern->std.properties) {
805: rebuild_object_properties(&intern->std);
806: }
807:
1.1 misho 808: if (HASH_OF(intern->array) == intern->std.properties) {
809: return intern->std.properties;
810: } else {
811: if (intern->debug_info == NULL) {
812: ALLOC_HASHTABLE(intern->debug_info);
813: ZEND_INIT_SYMTABLE_EX(intern->debug_info, zend_hash_num_elements(intern->std.properties) + 1, 0);
814: }
815:
816: if (intern->debug_info->nApplyCount == 0) {
817: zend_hash_clean(intern->debug_info);
818: zend_hash_copy(intern->debug_info, intern->std.properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
819:
820: storage = intern->array;
821: zval_add_ref(&storage);
822:
823: base = (Z_OBJ_HT_P(obj) == &spl_handler_ArrayIterator) ? spl_ce_ArrayIterator : spl_ce_ArrayObject;
824: zname = spl_gen_private_prop_name(base, "storage", sizeof("storage")-1, &name_len TSRMLS_CC);
825: zend_symtable_update(intern->debug_info, zname, name_len+1, &storage, sizeof(zval *), NULL);
826: efree(zname);
827: }
828:
829: return intern->debug_info;
830: }
831: }
832: /* }}} */
833:
1.1.1.2 misho 834: static zval *spl_array_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 835: {
836: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
837:
838: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 misho 839: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 840: return spl_array_read_dimension(object, member, type TSRMLS_CC);
841: }
1.1.1.2 misho 842: return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
1.1 misho 843: } /* }}} */
844:
1.1.1.2 misho 845: static void spl_array_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 846: {
847: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
848:
849: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 misho 850: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 851: spl_array_write_dimension(object, member, value TSRMLS_CC);
852: return;
853: }
1.1.1.2 misho 854: std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
1.1 misho 855: } /* }}} */
856:
1.1.1.2 misho 857: static zval **spl_array_get_property_ptr_ptr(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 858: {
859: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
860:
861: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 misho 862: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 863: return spl_array_get_dimension_ptr_ptr(1, object, member, BP_VAR_RW TSRMLS_CC);
864: }
1.1.1.2 misho 865: return std_object_handlers.get_property_ptr_ptr(object, member, key TSRMLS_CC);
1.1 misho 866: } /* }}} */
867:
1.1.1.2 misho 868: static int spl_array_has_property(zval *object, zval *member, int has_set_exists, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 869: {
870: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
871:
872: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 misho 873: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 874: return spl_array_has_dimension(object, member, has_set_exists TSRMLS_CC);
875: }
1.1.1.2 misho 876: return std_object_handlers.has_property(object, member, has_set_exists, key TSRMLS_CC);
1.1 misho 877: } /* }}} */
878:
1.1.1.2 misho 879: static void spl_array_unset_property(zval *object, zval *member, const zend_literal *key TSRMLS_DC) /* {{{ */
1.1 misho 880: {
881: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
882:
883: if ((intern->ar_flags & SPL_ARRAY_ARRAY_AS_PROPS) != 0
1.1.1.2 misho 884: && !std_object_handlers.has_property(object, member, 2, key TSRMLS_CC)) {
1.1 misho 885: spl_array_unset_dimension(object, member TSRMLS_CC);
886: spl_array_rewind(intern TSRMLS_CC); /* because deletion might invalidate position */
887: return;
888: }
1.1.1.2 misho 889: std_object_handlers.unset_property(object, member, key TSRMLS_CC);
890: } /* }}} */
891:
892: static int spl_array_compare_objects(zval *o1, zval *o2 TSRMLS_DC) /* {{{ */
893: {
894: HashTable *ht1,
895: *ht2;
896: spl_array_object *intern1,
897: *intern2;
898: int result = 0;
899: zval temp_zv;
900:
901: intern1 = (spl_array_object*)zend_object_store_get_object(o1 TSRMLS_CC);
902: intern2 = (spl_array_object*)zend_object_store_get_object(o2 TSRMLS_CC);
903: ht1 = spl_array_get_hash_table(intern1, 0 TSRMLS_CC);
904: ht2 = spl_array_get_hash_table(intern2, 0 TSRMLS_CC);
905:
906: zend_compare_symbol_tables(&temp_zv, ht1, ht2 TSRMLS_CC);
907: result = (int)Z_LVAL(temp_zv);
908: /* if we just compared std.properties, don't do it again */
909: if (result == 0 &&
910: !(ht1 == intern1->std.properties && ht2 == intern2->std.properties)) {
911: result = std_object_handlers.compare_objects(o1, o2 TSRMLS_CC);
912: }
913: return result;
1.1 misho 914: } /* }}} */
915:
916: static int spl_array_skip_protected(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
917: {
918: char *string_key;
919: uint string_length;
920: ulong num_key;
921:
922: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
923: do {
924: if (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 0, &intern->pos) == HASH_KEY_IS_STRING) {
925: if (!string_length || string_key[0]) {
926: return SUCCESS;
927: }
928: } else {
929: return SUCCESS;
930: }
931: if (zend_hash_has_more_elements_ex(aht, &intern->pos) != SUCCESS) {
932: return FAILURE;
933: }
934: zend_hash_move_forward_ex(aht, &intern->pos);
935: spl_array_update_pos(intern);
936: } while (1);
937: }
938: return FAILURE;
939: } /* }}} */
940:
941: static int spl_array_next_no_verify(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
942: {
943: zend_hash_move_forward_ex(aht, &intern->pos);
944: spl_array_update_pos(intern);
945: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
946: return spl_array_skip_protected(intern, aht TSRMLS_CC);
947: } else {
948: return zend_hash_has_more_elements_ex(aht, &intern->pos);
949: }
950: } /* }}} */
951:
952: static int spl_array_next_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
953: {
954: if ((intern->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(intern, aht TSRMLS_CC) == FAILURE) {
955: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and internal position is no longer valid");
956: return FAILURE;
957: }
958:
959: return spl_array_next_no_verify(intern, aht TSRMLS_CC);
960: } /* }}} */
961:
962: static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
963: {
964: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
965:
966: return spl_array_next_ex(intern, aht TSRMLS_CC);
967:
968: } /* }}} */
969:
970: /* define an overloaded iterator structure */
971: typedef struct {
972: zend_user_iterator intern;
973: spl_array_object *object;
974: } spl_array_it;
975:
976: static void spl_array_it_dtor(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
977: {
978: spl_array_it *iterator = (spl_array_it *)iter;
979:
980: zend_user_it_invalidate_current(iter TSRMLS_CC);
981: zval_ptr_dtor((zval**)&iterator->intern.it.data);
982:
983: efree(iterator);
984: }
985: /* }}} */
986:
987: static int spl_array_it_valid(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
988: {
989: spl_array_it *iterator = (spl_array_it *)iter;
990: spl_array_object *object = iterator->object;
991: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
992:
993: if (object->ar_flags & SPL_ARRAY_OVERLOADED_VALID) {
994: return zend_user_it_valid(iter TSRMLS_CC);
995: } else {
1.1.1.3 misho 996: if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::valid(): " TSRMLS_CC) == FAILURE) {
1.1 misho 997: return FAILURE;
998: }
1.1.1.3 misho 999:
1000: return zend_hash_has_more_elements_ex(aht, &object->pos);
1.1 misho 1001: }
1002: }
1003: /* }}} */
1004:
1005: static void spl_array_it_get_current_data(zend_object_iterator *iter, zval ***data TSRMLS_DC) /* {{{ */
1006: {
1007: spl_array_it *iterator = (spl_array_it *)iter;
1008: spl_array_object *object = iterator->object;
1009: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
1010:
1011: if (object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT) {
1012: zend_user_it_get_current_data(iter, data TSRMLS_CC);
1013: } else {
1014: if (zend_hash_get_current_data_ex(aht, (void**)data, &object->pos) == FAILURE) {
1015: *data = NULL;
1016: }
1017: }
1018: }
1019: /* }}} */
1020:
1021: static int spl_array_it_get_current_key(zend_object_iterator *iter, char **str_key, uint *str_key_len, ulong *int_key TSRMLS_DC) /* {{{ */
1022: {
1023: spl_array_it *iterator = (spl_array_it *)iter;
1024: spl_array_object *object = iterator->object;
1025: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
1026:
1027: if (object->ar_flags & SPL_ARRAY_OVERLOADED_KEY) {
1028: return zend_user_it_get_current_key(iter, str_key, str_key_len, int_key TSRMLS_CC);
1029: } else {
1.1.1.3 misho 1030: if (spl_array_object_verify_pos_ex(object, aht, "ArrayIterator::current(): " TSRMLS_CC) == FAILURE) {
1.1 misho 1031: return HASH_KEY_NON_EXISTANT;
1032: }
1033:
1034: return zend_hash_get_current_key_ex(aht, str_key, str_key_len, int_key, 1, &object->pos);
1035: }
1036: }
1037: /* }}} */
1038:
1039: static void spl_array_it_move_forward(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1040: {
1041: spl_array_it *iterator = (spl_array_it *)iter;
1042: spl_array_object *object = iterator->object;
1043: HashTable *aht = spl_array_get_hash_table(object, 0 TSRMLS_CC);
1044:
1045: if (object->ar_flags & SPL_ARRAY_OVERLOADED_NEXT) {
1046: zend_user_it_move_forward(iter TSRMLS_CC);
1047: } else {
1048: zend_user_it_invalidate_current(iter TSRMLS_CC);
1049: if (!aht) {
1050: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::current(): Array was modified outside object and is no longer an array");
1051: return;
1052: }
1053:
1054: if ((object->ar_flags & SPL_ARRAY_IS_REF) && spl_hash_verify_pos_ex(object, aht TSRMLS_CC) == FAILURE) {
1055: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::next(): Array was modified outside object and internal position is no longer valid");
1056: } else {
1057: spl_array_next_no_verify(object, aht TSRMLS_CC);
1058: }
1059: }
1060: }
1061: /* }}} */
1062:
1063: static void spl_array_rewind_ex(spl_array_object *intern, HashTable *aht TSRMLS_DC) /* {{{ */
1064: {
1065:
1066: zend_hash_internal_pointer_reset_ex(aht, &intern->pos);
1067: spl_array_update_pos(intern);
1068: spl_array_skip_protected(intern, aht TSRMLS_CC);
1069:
1070: } /* }}} */
1071:
1072: static void spl_array_rewind(spl_array_object *intern TSRMLS_DC) /* {{{ */
1073: {
1074: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1075:
1076: if (!aht) {
1077: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "ArrayIterator::rewind(): Array was modified outside object and is no longer an array");
1078: return;
1079: }
1080:
1081: spl_array_rewind_ex(intern, aht TSRMLS_CC);
1082: }
1083: /* }}} */
1084:
1085: static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
1086: {
1087: spl_array_it *iterator = (spl_array_it *)iter;
1088: spl_array_object *object = iterator->object;
1089:
1090: if (object->ar_flags & SPL_ARRAY_OVERLOADED_REWIND) {
1091: zend_user_it_rewind(iter TSRMLS_CC);
1092: } else {
1093: zend_user_it_invalidate_current(iter TSRMLS_CC);
1094: spl_array_rewind(object TSRMLS_CC);
1095: }
1096: }
1097: /* }}} */
1098:
1099: /* {{{ spl_array_set_array */
1100: static void spl_array_set_array(zval *object, spl_array_object *intern, zval **array, long ar_flags, int just_array TSRMLS_DC) {
1101:
1102: if (Z_TYPE_PP(array) == IS_ARRAY) {
1103: SEPARATE_ZVAL_IF_NOT_REF(array);
1104: }
1105:
1106: if (Z_TYPE_PP(array) == IS_OBJECT && (Z_OBJ_HT_PP(array) == &spl_handler_ArrayObject || Z_OBJ_HT_PP(array) == &spl_handler_ArrayIterator)) {
1107: zval_ptr_dtor(&intern->array);
1108: if (just_array) {
1109: spl_array_object *other = (spl_array_object*)zend_object_store_get_object(*array TSRMLS_CC);
1110: ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
1111: }
1112: ar_flags |= SPL_ARRAY_USE_OTHER;
1113: intern->array = *array;
1114: } else {
1115: if (Z_TYPE_PP(array) != IS_OBJECT && Z_TYPE_PP(array) != IS_ARRAY) {
1116: zend_throw_exception(spl_ce_InvalidArgumentException, "Passed variable is not an array or object, using empty array instead", 0 TSRMLS_CC);
1117: return;
1118: }
1119: zval_ptr_dtor(&intern->array);
1120: intern->array = *array;
1121: }
1122: if (object == *array) {
1123: intern->ar_flags |= SPL_ARRAY_IS_SELF;
1124: intern->ar_flags &= ~SPL_ARRAY_USE_OTHER;
1125: } else {
1126: intern->ar_flags &= ~SPL_ARRAY_IS_SELF;
1127: }
1128: intern->ar_flags |= ar_flags;
1129: Z_ADDREF_P(intern->array);
1130: if (Z_TYPE_PP(array) == IS_OBJECT) {
1131: zend_object_get_properties_t handler = Z_OBJ_HANDLER_PP(array, get_properties);
1132: if ((handler != std_object_handlers.get_properties && handler != spl_array_get_properties)
1133: || !spl_array_get_hash_table(intern, 0 TSRMLS_CC)) {
1134: zend_throw_exception_ex(spl_ce_InvalidArgumentException, 0 TSRMLS_CC, "Overloaded object of type %s is not compatible with %s", Z_OBJCE_PP(array)->name, intern->std.ce->name);
1135: }
1136: }
1137:
1138: spl_array_rewind(intern TSRMLS_CC);
1139: }
1140: /* }}} */
1141:
1142: /* iterator handler table */
1143: zend_object_iterator_funcs spl_array_it_funcs = {
1144: spl_array_it_dtor,
1145: spl_array_it_valid,
1146: spl_array_it_get_current_data,
1147: spl_array_it_get_current_key,
1148: spl_array_it_move_forward,
1149: spl_array_it_rewind
1150: };
1151:
1152: zend_object_iterator *spl_array_get_iterator(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC) /* {{{ */
1153: {
1154: spl_array_it *iterator;
1155: spl_array_object *array_object = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1156:
1157: if (by_ref && (array_object->ar_flags & SPL_ARRAY_OVERLOADED_CURRENT)) {
1158: zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
1159: }
1160:
1161: iterator = emalloc(sizeof(spl_array_it));
1162:
1163: Z_ADDREF_P(object);
1164: iterator->intern.it.data = (void*)object;
1165: iterator->intern.it.funcs = &spl_array_it_funcs;
1166: iterator->intern.ce = ce;
1167: iterator->intern.value = NULL;
1168: iterator->object = array_object;
1169:
1170: return (zend_object_iterator*)iterator;
1171: }
1172: /* }}} */
1173:
1174: /* {{{ proto void ArrayObject::__construct(array|object ar = array() [, int flags = 0 [, string iterator_class = "ArrayIterator"]])
1175: proto void ArrayIterator::__construct(array|object ar = array() [, int flags = 0])
1176: Constructs a new array iterator from a path. */
1177: SPL_METHOD(Array, __construct)
1178: {
1179: zval *object = getThis();
1180: spl_array_object *intern;
1181: zval **array;
1182: long ar_flags = 0;
1183: zend_class_entry *ce_get_iterator = spl_ce_Iterator;
1184: zend_error_handling error_handling;
1185:
1186: if (ZEND_NUM_ARGS() == 0) {
1187: return; /* nothing to do */
1188: }
1189:
1190: zend_replace_error_handling(EH_THROW, spl_ce_InvalidArgumentException, &error_handling TSRMLS_CC);
1191:
1192: intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1193:
1194: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|lC", &array, &ar_flags, &ce_get_iterator) == FAILURE) {
1195: zend_restore_error_handling(&error_handling TSRMLS_CC);
1196: return;
1197: }
1198:
1199: if (ZEND_NUM_ARGS() > 2) {
1200: intern->ce_get_iterator = ce_get_iterator;
1201: }
1202:
1203: ar_flags &= ~SPL_ARRAY_INT_MASK;
1204:
1205: spl_array_set_array(object, intern, array, ar_flags, ZEND_NUM_ARGS() == 1 TSRMLS_CC);
1206:
1207: zend_restore_error_handling(&error_handling TSRMLS_CC);
1208:
1209: }
1210: /* }}} */
1211:
1212: /* {{{ proto void ArrayObject::setIteratorClass(string iterator_class)
1213: Set the class used in getIterator. */
1214: SPL_METHOD(Array, setIteratorClass)
1215: {
1216: zval *object = getThis();
1217: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1218: zend_class_entry * ce_get_iterator = spl_ce_Iterator;
1219:
1220: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "C", &ce_get_iterator) == FAILURE) {
1221: return;
1222: }
1223:
1224: intern->ce_get_iterator = ce_get_iterator;
1225: }
1226: /* }}} */
1227:
1228: /* {{{ proto string ArrayObject::getIteratorClass()
1229: Get the class used in getIterator. */
1230: SPL_METHOD(Array, getIteratorClass)
1231: {
1232: zval *object = getThis();
1233: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1234:
1235: if (zend_parse_parameters_none() == FAILURE) {
1236: return;
1237: }
1238:
1239: RETURN_STRING(intern->ce_get_iterator->name, 1);
1240: }
1241: /* }}} */
1242:
1243: /* {{{ proto int ArrayObject::getFlags()
1244: Get flags */
1245: SPL_METHOD(Array, getFlags)
1246: {
1247: zval *object = getThis();
1248: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1249:
1250: if (zend_parse_parameters_none() == FAILURE) {
1251: return;
1252: }
1253:
1254: RETURN_LONG(intern->ar_flags & ~SPL_ARRAY_INT_MASK);
1255: }
1256: /* }}} */
1257:
1258: /* {{{ proto void ArrayObject::setFlags(int flags)
1259: Set flags */
1260: SPL_METHOD(Array, setFlags)
1261: {
1262: zval *object = getThis();
1263: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1264: long ar_flags = 0;
1265:
1266: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ar_flags) == FAILURE) {
1267: return;
1268: }
1269:
1270: intern->ar_flags = (intern->ar_flags & SPL_ARRAY_INT_MASK) | (ar_flags & ~SPL_ARRAY_INT_MASK);
1271: }
1272: /* }}} */
1273:
1274: /* {{{ proto Array|Object ArrayObject::exchangeArray(Array|Object ar = array())
1275: Replace the referenced array or object with a new one and return the old one (right now copy - to be changed) */
1276: SPL_METHOD(Array, exchangeArray)
1277: {
1278: zval *object = getThis(), *tmp, **array;
1279: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1280:
1281: array_init(return_value);
1282: zend_hash_copy(HASH_OF(return_value), spl_array_get_hash_table(intern, 0 TSRMLS_CC), (copy_ctor_func_t) zval_add_ref, &tmp, sizeof(zval*));
1283:
1284: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &array) == FAILURE) {
1285: return;
1286: }
1287:
1288: spl_array_set_array(object, intern, array, 0L, 1 TSRMLS_CC);
1289:
1290: }
1291: /* }}} */
1292:
1293: /* {{{ proto ArrayIterator ArrayObject::getIterator()
1294: Create a new iterator from a ArrayObject instance */
1295: SPL_METHOD(Array, getIterator)
1296: {
1297: zval *object = getThis();
1298: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1299: spl_array_object *iterator;
1300: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1301:
1302: if (zend_parse_parameters_none() == FAILURE) {
1303: return;
1304: }
1305:
1306: if (!aht) {
1307: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1308: return;
1309: }
1310:
1311: return_value->type = IS_OBJECT;
1312: return_value->value.obj = spl_array_object_new_ex(intern->ce_get_iterator, &iterator, object, 0 TSRMLS_CC);
1313: Z_SET_REFCOUNT_P(return_value, 1);
1314: Z_SET_ISREF_P(return_value);
1315: }
1316: /* }}} */
1317:
1318: /* {{{ proto void ArrayIterator::rewind()
1319: Rewind array back to the start */
1320: SPL_METHOD(Array, rewind)
1321: {
1322: zval *object = getThis();
1323: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1324:
1325: if (zend_parse_parameters_none() == FAILURE) {
1326: return;
1327: }
1328:
1329: spl_array_rewind(intern TSRMLS_CC);
1330: }
1331: /* }}} */
1332:
1333: /* {{{ proto void ArrayIterator::seek(int $position)
1334: Seek to position. */
1335: SPL_METHOD(Array, seek)
1336: {
1337: long opos, position;
1338: zval *object = getThis();
1339: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1340: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1341: int result;
1342:
1343: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &position) == FAILURE) {
1344: return;
1345: }
1346:
1347: if (!aht) {
1348: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1349: return;
1350: }
1351:
1352: opos = position;
1353:
1354: if (position >= 0) { /* negative values are not supported */
1355: spl_array_rewind(intern TSRMLS_CC);
1356: result = SUCCESS;
1357:
1358: while (position-- > 0 && (result = spl_array_next(intern TSRMLS_CC)) == SUCCESS);
1359:
1360: if (result == SUCCESS && zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS) {
1361: return; /* ok */
1362: }
1363: }
1364: zend_throw_exception_ex(spl_ce_OutOfBoundsException, 0 TSRMLS_CC, "Seek position %ld is out of range", opos);
1365: } /* }}} */
1366:
1367: int static spl_array_object_count_elements_helper(spl_array_object *intern, long *count TSRMLS_DC) /* {{{ */
1368: {
1369: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1370: HashPosition pos;
1371:
1372: if (!aht) {
1373: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1374: *count = 0;
1375: return FAILURE;
1376: }
1377:
1378: if (Z_TYPE_P(intern->array) == IS_OBJECT) {
1379: /* We need to store the 'pos' since we'll modify it in the functions
1380: * we're going to call and which do not support 'pos' as parameter. */
1381: pos = intern->pos;
1382: *count = 0;
1383: spl_array_rewind(intern TSRMLS_CC);
1384: while(intern->pos && spl_array_next(intern TSRMLS_CC) == SUCCESS) {
1385: (*count)++;
1386: }
1387: spl_array_set_pos(intern, pos);
1388: return SUCCESS;
1389: } else {
1390: *count = zend_hash_num_elements(aht);
1391: return SUCCESS;
1392: }
1393: } /* }}} */
1394:
1395: int spl_array_object_count_elements(zval *object, long *count TSRMLS_DC) /* {{{ */
1396: {
1397: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1398:
1399: if (intern->fptr_count) {
1400: zval *rv;
1401: zend_call_method_with_0_params(&object, intern->std.ce, &intern->fptr_count, "count", &rv);
1402: if (rv) {
1403: zval_ptr_dtor(&intern->retval);
1404: MAKE_STD_ZVAL(intern->retval);
1405: ZVAL_ZVAL(intern->retval, rv, 1, 1);
1406: convert_to_long(intern->retval);
1407: *count = (long) Z_LVAL_P(intern->retval);
1408: return SUCCESS;
1409: }
1410: *count = 0;
1411: return FAILURE;
1412: }
1413: return spl_array_object_count_elements_helper(intern, count TSRMLS_CC);
1414: } /* }}} */
1415:
1416: /* {{{ proto int ArrayObject::count()
1417: proto int ArrayIterator::count()
1418: Return the number of elements in the Iterator. */
1419: SPL_METHOD(Array, count)
1420: {
1421: long count;
1422: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1423:
1424: if (zend_parse_parameters_none() == FAILURE) {
1425: return;
1426: }
1427:
1428: spl_array_object_count_elements_helper(intern, &count TSRMLS_CC);
1429:
1430: RETURN_LONG(count);
1431: } /* }}} */
1432:
1433: static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fname_len, int use_arg) /* {{{ */
1434: {
1435: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1436: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1.1.1.3 misho 1437: zval *tmp, *arg = NULL;
1.1 misho 1438: zval *retval_ptr = NULL;
1439:
1440: MAKE_STD_ZVAL(tmp);
1441: Z_TYPE_P(tmp) = IS_ARRAY;
1442: Z_ARRVAL_P(tmp) = aht;
1443:
1.1.1.3 misho 1444: if (!use_arg) {
1445: aht->nApplyCount++;
1446: zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 1, tmp, NULL TSRMLS_CC);
1447: aht->nApplyCount--;
1448: } else if (use_arg == SPL_ARRAY_METHOD_MAY_USER_ARG) {
1449: if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "|z", &arg) == FAILURE) {
1.1 misho 1450: Z_TYPE_P(tmp) = IS_NULL;
1451: zval_ptr_dtor(&tmp);
1.1.1.3 misho 1452: zend_throw_exception(spl_ce_BadMethodCallException, "Function expects one argument at most", 0 TSRMLS_CC);
1.1 misho 1453: return;
1454: }
1455: aht->nApplyCount++;
1.1.1.3 misho 1456: zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, arg? 2 : 1, tmp, arg TSRMLS_CC);
1.1 misho 1457: aht->nApplyCount--;
1458: } else {
1.1.1.3 misho 1459: if (ZEND_NUM_ARGS() != 1 || zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1460: Z_TYPE_P(tmp) = IS_NULL;
1461: zval_ptr_dtor(&tmp);
1462: zend_throw_exception(spl_ce_BadMethodCallException, "Function expects exactly one argument", 0 TSRMLS_CC);
1463: return;
1464: }
1.1 misho 1465: aht->nApplyCount++;
1.1.1.3 misho 1466: zend_call_method(NULL, NULL, NULL, fname, fname_len, &retval_ptr, 2, tmp, arg TSRMLS_CC);
1.1 misho 1467: aht->nApplyCount--;
1468: }
1469: Z_TYPE_P(tmp) = IS_NULL; /* we want to destroy the zval, not the hashtable */
1470: zval_ptr_dtor(&tmp);
1471: if (retval_ptr) {
1472: COPY_PZVAL_TO_ZVAL(*return_value, retval_ptr);
1473: }
1474: } /* }}} */
1475:
1476: #define SPL_ARRAY_METHOD(cname, fname, use_arg) \
1477: SPL_METHOD(cname, fname) \
1478: { \
1479: spl_array_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, #fname, sizeof(#fname)-1, use_arg); \
1480: }
1481:
1.1.1.3 misho 1482: /* {{{ proto int ArrayObject::asort([int $sort_flags = SORT_REGULAR ])
1483: proto int ArrayIterator::asort([int $sort_flags = SORT_REGULAR ])
1.1 misho 1484: Sort the entries by values. */
1.1.1.3 misho 1485: SPL_ARRAY_METHOD(Array, asort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
1.1 misho 1486:
1.1.1.3 misho 1487: /* {{{ proto int ArrayObject::ksort([int $sort_flags = SORT_REGULAR ])
1488: proto int ArrayIterator::ksort([int $sort_flags = SORT_REGULAR ])
1.1 misho 1489: Sort the entries by key. */
1.1.1.3 misho 1490: SPL_ARRAY_METHOD(Array, ksort, SPL_ARRAY_METHOD_MAY_USER_ARG) /* }}} */
1.1 misho 1491:
1492: /* {{{ proto int ArrayObject::uasort(callback cmp_function)
1493: proto int ArrayIterator::uasort(callback cmp_function)
1494: Sort the entries by values user defined function. */
1.1.1.3 misho 1495: SPL_ARRAY_METHOD(Array, uasort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
1.1 misho 1496:
1497: /* {{{ proto int ArrayObject::uksort(callback cmp_function)
1498: proto int ArrayIterator::uksort(callback cmp_function)
1499: Sort the entries by key using user defined function. */
1.1.1.3 misho 1500: SPL_ARRAY_METHOD(Array, uksort, SPL_ARRAY_METHOD_USE_ARG) /* }}} */
1.1 misho 1501:
1502: /* {{{ proto int ArrayObject::natsort()
1503: proto int ArrayIterator::natsort()
1504: Sort the entries by values using "natural order" algorithm. */
1.1.1.3 misho 1505: SPL_ARRAY_METHOD(Array, natsort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
1.1 misho 1506:
1507: /* {{{ proto int ArrayObject::natcasesort()
1508: proto int ArrayIterator::natcasesort()
1509: Sort the entries by key using case insensitive "natural order" algorithm. */
1.1.1.3 misho 1510: SPL_ARRAY_METHOD(Array, natcasesort, SPL_ARRAY_METHOD_NO_ARG) /* }}} */
1.1 misho 1511:
1512: /* {{{ proto mixed|NULL ArrayIterator::current()
1513: Return current array entry */
1514: SPL_METHOD(Array, current)
1515: {
1516: zval *object = getThis();
1517: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1518: zval **entry;
1519: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1520:
1521: if (zend_parse_parameters_none() == FAILURE) {
1522: return;
1523: }
1524:
1.1.1.3 misho 1525: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1526: return;
1527: }
1528:
1529: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1530: return;
1531: }
1532: RETVAL_ZVAL(*entry, 1, 0);
1533: }
1534: /* }}} */
1535:
1536: /* {{{ proto mixed|NULL ArrayIterator::key()
1537: Return current array key */
1538: SPL_METHOD(Array, key)
1539: {
1540: if (zend_parse_parameters_none() == FAILURE) {
1541: return;
1542: }
1543:
1544: spl_array_iterator_key(getThis(), return_value TSRMLS_CC);
1545: } /* }}} */
1546:
1547: void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ */
1548: {
1549: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1550: char *string_key;
1551: uint string_length;
1552: ulong num_key;
1553: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1554:
1.1.1.3 misho 1555: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1556: return;
1557: }
1558:
1559: switch (zend_hash_get_current_key_ex(aht, &string_key, &string_length, &num_key, 1, &intern->pos)) {
1560: case HASH_KEY_IS_STRING:
1561: RETVAL_STRINGL(string_key, string_length - 1, 0);
1562: break;
1563: case HASH_KEY_IS_LONG:
1564: RETVAL_LONG(num_key);
1565: break;
1566: case HASH_KEY_NON_EXISTANT:
1567: return;
1568: }
1569: }
1570: /* }}} */
1571:
1572: /* {{{ proto void ArrayIterator::next()
1573: Move to next entry */
1574: SPL_METHOD(Array, next)
1575: {
1576: zval *object = getThis();
1577: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1578: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1579:
1580: if (zend_parse_parameters_none() == FAILURE) {
1581: return;
1582: }
1.1.1.3 misho 1583:
1584: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1585: return;
1586: }
1587:
1.1.1.3 misho 1588: spl_array_next_no_verify(intern, aht TSRMLS_CC);
1.1 misho 1589: }
1590: /* }}} */
1591:
1592: /* {{{ proto bool ArrayIterator::valid()
1593: Check whether array contains more entries */
1594: SPL_METHOD(Array, valid)
1595: {
1596: zval *object = getThis();
1597: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1598: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1599:
1600: if (zend_parse_parameters_none() == FAILURE) {
1601: return;
1602: }
1603:
1.1.1.3 misho 1604: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1605: RETURN_FALSE;
1606: } else {
1607: RETURN_BOOL(zend_hash_has_more_elements_ex(aht, &intern->pos) == SUCCESS);
1608: }
1609: }
1610: /* }}} */
1611:
1612: /* {{{ proto bool RecursiveArrayIterator::hasChildren()
1613: Check whether current element has children (e.g. is an array) */
1614: SPL_METHOD(Array, hasChildren)
1615: {
1616: zval *object = getThis(), **entry;
1617: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1618: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1619:
1620: if (zend_parse_parameters_none() == FAILURE) {
1621: return;
1622: }
1623:
1.1.1.3 misho 1624: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1625: RETURN_FALSE;
1626: }
1627:
1628: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1629: RETURN_FALSE;
1630: }
1631:
1632: RETURN_BOOL(Z_TYPE_PP(entry) == IS_ARRAY || (Z_TYPE_PP(entry) == IS_OBJECT && (intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) == 0));
1633: }
1634: /* }}} */
1635:
1636: /* {{{ proto object RecursiveArrayIterator::getChildren()
1637: Create a sub iterator for the current element (same class as $this) */
1638: SPL_METHOD(Array, getChildren)
1639: {
1640: zval *object = getThis(), **entry, *flags;
1641: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1642: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1643:
1644: if (zend_parse_parameters_none() == FAILURE) {
1645: return;
1646: }
1647:
1.1.1.3 misho 1648: if (spl_array_object_verify_pos(intern, aht TSRMLS_CC) == FAILURE) {
1.1 misho 1649: return;
1650: }
1651:
1652: if (zend_hash_get_current_data_ex(aht, (void **) &entry, &intern->pos) == FAILURE) {
1653: return;
1654: }
1655:
1656: if (Z_TYPE_PP(entry) == IS_OBJECT) {
1657: if ((intern->ar_flags & SPL_ARRAY_CHILD_ARRAYS_ONLY) != 0) {
1658: return;
1659: }
1660: if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
1.1.1.4 ! misho 1661: RETURN_ZVAL(*entry, 1, 0);
1.1 misho 1662: }
1663: }
1664:
1665: MAKE_STD_ZVAL(flags);
1666: ZVAL_LONG(flags, SPL_ARRAY_USE_OTHER | intern->ar_flags);
1667: spl_instantiate_arg_ex2(Z_OBJCE_P(getThis()), &return_value, 0, *entry, flags TSRMLS_CC);
1668: zval_ptr_dtor(&flags);
1669: }
1670: /* }}} */
1671:
1.1.1.2 misho 1672: /* {{{ proto string ArrayObject::serialize()
1673: Serialize the object */
1674: SPL_METHOD(Array, serialize)
1675: {
1676: zval *object = getThis();
1677: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(object TSRMLS_CC);
1.1 misho 1678: HashTable *aht = spl_array_get_hash_table(intern, 0 TSRMLS_CC);
1679: zval members, *pmembers;
1.1.1.2 misho 1680: php_serialize_data_t var_hash;
1.1 misho 1681: smart_str buf = {0};
1682: zval *flags;
1683:
1.1.1.2 misho 1684: if (zend_parse_parameters_none() == FAILURE) {
1685: return;
1686: }
1687:
1.1 misho 1688: if (!aht) {
1689: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Array was modified outside object and is no longer an array");
1.1.1.2 misho 1690: return;
1.1 misho 1691: }
1692:
1.1.1.2 misho 1693: PHP_VAR_SERIALIZE_INIT(var_hash);
1694:
1.1 misho 1695: MAKE_STD_ZVAL(flags);
1696: ZVAL_LONG(flags, (intern->ar_flags & SPL_ARRAY_CLONE_MASK));
1697:
1698: /* storage */
1699: smart_str_appendl(&buf, "x:", 2);
1.1.1.2 misho 1700: php_var_serialize(&buf, &flags, &var_hash TSRMLS_CC);
1.1 misho 1701: zval_ptr_dtor(&flags);
1702:
1703: if (!(intern->ar_flags & SPL_ARRAY_IS_SELF)) {
1.1.1.2 misho 1704: php_var_serialize(&buf, &intern->array, &var_hash TSRMLS_CC);
1.1 misho 1705: smart_str_appendc(&buf, ';');
1706: }
1707:
1708: /* members */
1709: smart_str_appendl(&buf, "m:", 2);
1710: INIT_PZVAL(&members);
1.1.1.2 misho 1711: if (!intern->std.properties) {
1712: rebuild_object_properties(&intern->std);
1713: }
1.1 misho 1714: Z_ARRVAL(members) = intern->std.properties;
1715: Z_TYPE(members) = IS_ARRAY;
1716: pmembers = &members;
1.1.1.2 misho 1717: php_var_serialize(&buf, &pmembers, &var_hash TSRMLS_CC); /* finishes the string */
1.1 misho 1718:
1719: /* done */
1.1.1.2 misho 1720: PHP_VAR_SERIALIZE_DESTROY(var_hash);
1.1 misho 1721:
1722: if (buf.c) {
1723: RETURN_STRINGL(buf.c, buf.len, 0);
1724: }
1725:
1726: RETURN_NULL();
1727: } /* }}} */
1728:
1.1.1.2 misho 1729: /* {{{ proto void ArrayObject::unserialize(string serialized)
1730: * unserialize the object
1731: */
1732: SPL_METHOD(Array, unserialize)
1.1 misho 1733: {
1.1.1.2 misho 1734: spl_array_object *intern = (spl_array_object*)zend_object_store_get_object(getThis() TSRMLS_CC);
1.1 misho 1735:
1.1.1.2 misho 1736: char *buf;
1737: int buf_len;
1.1 misho 1738: const unsigned char *p, *s;
1.1.1.2 misho 1739: php_unserialize_data_t var_hash;
1.1 misho 1740: zval *pmembers, *pflags = NULL;
1741: long flags;
1.1.1.2 misho 1742:
1743: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
1744: return;
1745: }
1746:
1747: if (buf_len == 0) {
1748: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Empty serialized string cannot be empty");
1749: return;
1750: }
1.1 misho 1751:
1752: /* storage */
1.1.1.2 misho 1753: s = p = (const unsigned char*)buf;
1754: PHP_VAR_UNSERIALIZE_INIT(var_hash);
1.1 misho 1755:
1756: if (*p!= 'x' || *++p != ':') {
1757: goto outexcept;
1758: }
1759: ++p;
1760:
1761: ALLOC_INIT_ZVAL(pflags);
1.1.1.2 misho 1762: if (!php_var_unserialize(&pflags, &p, s + buf_len, &var_hash TSRMLS_CC) || Z_TYPE_P(pflags) != IS_LONG) {
1.1 misho 1763: zval_ptr_dtor(&pflags);
1764: goto outexcept;
1765: }
1766:
1767: --p; /* for ';' */
1768: flags = Z_LVAL_P(pflags);
1769: zval_ptr_dtor(&pflags);
1770: /* flags needs to be verified and we also need to verify whether the next
1771: * thing we get is ';'. After that we require an 'm' or somethign else
1772: * where 'm' stands for members and anything else should be an array. If
1773: * neither 'a' or 'm' follows we have an error. */
1774:
1775: if (*p != ';') {
1776: goto outexcept;
1777: }
1778: ++p;
1779:
1780: if (*p!='m') {
1.1.1.4 ! misho 1781: if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
1.1 misho 1782: goto outexcept;
1783: }
1784: intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
1785: intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1786: zval_ptr_dtor(&intern->array);
1787: ALLOC_INIT_ZVAL(intern->array);
1.1.1.2 misho 1788: if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash TSRMLS_CC)) {
1.1 misho 1789: goto outexcept;
1790: }
1791: }
1792: if (*p != ';') {
1793: goto outexcept;
1794: }
1795: ++p;
1796:
1797: /* members */
1798: if (*p!= 'm' || *++p != ':') {
1799: goto outexcept;
1800: }
1801: ++p;
1802:
1803: ALLOC_INIT_ZVAL(pmembers);
1.1.1.2 misho 1804: if (!php_var_unserialize(&pmembers, &p, s + buf_len, &var_hash TSRMLS_CC)) {
1.1 misho 1805: zval_ptr_dtor(&pmembers);
1806: goto outexcept;
1807: }
1808:
1809: /* copy members */
1.1.1.2 misho 1810: if (!intern->std.properties) {
1811: rebuild_object_properties(&intern->std);
1812: }
1.1 misho 1813: zend_hash_copy(intern->std.properties, Z_ARRVAL_P(pmembers), (copy_ctor_func_t) zval_add_ref, (void *) NULL, sizeof(zval *));
1814: zval_ptr_dtor(&pmembers);
1815:
1816: /* done reading $serialized */
1.1.1.2 misho 1817:
1818: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1.1 misho 1819: return;
1820:
1821: outexcept:
1.1.1.2 misho 1822: PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1823: zend_throw_exception_ex(spl_ce_UnexpectedValueException, 0 TSRMLS_CC, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
1.1 misho 1824: return;
1825:
1826: } /* }}} */
1827:
1828: /* {{{ arginfo and function tbale */
1829: ZEND_BEGIN_ARG_INFO(arginfo_array___construct, 0)
1830: ZEND_ARG_INFO(0, array)
1831: ZEND_END_ARG_INFO()
1832:
1833: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetGet, 0, 0, 1)
1834: ZEND_ARG_INFO(0, index)
1835: ZEND_END_ARG_INFO()
1836:
1837: ZEND_BEGIN_ARG_INFO_EX(arginfo_array_offsetSet, 0, 0, 2)
1838: ZEND_ARG_INFO(0, index)
1839: ZEND_ARG_INFO(0, newval)
1840: ZEND_END_ARG_INFO()
1841:
1842: ZEND_BEGIN_ARG_INFO(arginfo_array_append, 0)
1843: ZEND_ARG_INFO(0, value)
1844: ZEND_END_ARG_INFO()
1845:
1846: ZEND_BEGIN_ARG_INFO(arginfo_array_seek, 0)
1847: ZEND_ARG_INFO(0, position)
1848: ZEND_END_ARG_INFO()
1849:
1850: ZEND_BEGIN_ARG_INFO(arginfo_array_exchangeArray, 0)
1851: ZEND_ARG_INFO(0, array)
1852: ZEND_END_ARG_INFO()
1853:
1854: ZEND_BEGIN_ARG_INFO(arginfo_array_setFlags, 0)
1855: ZEND_ARG_INFO(0, flags)
1856: ZEND_END_ARG_INFO()
1857:
1858: ZEND_BEGIN_ARG_INFO(arginfo_array_setIteratorClass, 0)
1859: ZEND_ARG_INFO(0, iteratorClass)
1860: ZEND_END_ARG_INFO()
1861:
1862: ZEND_BEGIN_ARG_INFO(arginfo_array_uXsort, 0)
1863: ZEND_ARG_INFO(0, cmp_function)
1864: ZEND_END_ARG_INFO();
1865:
1866: ZEND_BEGIN_ARG_INFO(arginfo_array_unserialize, 0)
1867: ZEND_ARG_INFO(0, serialized)
1868: ZEND_END_ARG_INFO();
1869:
1870: ZEND_BEGIN_ARG_INFO(arginfo_array_void, 0)
1871: ZEND_END_ARG_INFO()
1872:
1873: static const zend_function_entry spl_funcs_ArrayObject[] = {
1874: SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1875: SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1876: SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1877: SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1878: SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1879: SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1880: SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
1881: SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
1882: SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
1883: SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1884: SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
1885: SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
1886: SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1887: SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1888: SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
1889: SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
1890: SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
1891: SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
1892: /* ArrayObject specific */
1893: SPL_ME(Array, getIterator, arginfo_array_void, ZEND_ACC_PUBLIC)
1894: SPL_ME(Array, exchangeArray, arginfo_array_exchangeArray, ZEND_ACC_PUBLIC)
1895: SPL_ME(Array, setIteratorClass, arginfo_array_setIteratorClass, ZEND_ACC_PUBLIC)
1896: SPL_ME(Array, getIteratorClass, arginfo_array_void, ZEND_ACC_PUBLIC)
1897: PHP_FE_END
1898: };
1899:
1900: static const zend_function_entry spl_funcs_ArrayIterator[] = {
1901: SPL_ME(Array, __construct, arginfo_array___construct, ZEND_ACC_PUBLIC)
1902: SPL_ME(Array, offsetExists, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1903: SPL_ME(Array, offsetGet, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1904: SPL_ME(Array, offsetSet, arginfo_array_offsetSet, ZEND_ACC_PUBLIC)
1905: SPL_ME(Array, offsetUnset, arginfo_array_offsetGet, ZEND_ACC_PUBLIC)
1906: SPL_ME(Array, append, arginfo_array_append, ZEND_ACC_PUBLIC)
1907: SPL_ME(Array, getArrayCopy, arginfo_array_void, ZEND_ACC_PUBLIC)
1908: SPL_ME(Array, count, arginfo_array_void, ZEND_ACC_PUBLIC)
1909: SPL_ME(Array, getFlags, arginfo_array_void, ZEND_ACC_PUBLIC)
1910: SPL_ME(Array, setFlags, arginfo_array_setFlags, ZEND_ACC_PUBLIC)
1911: SPL_ME(Array, asort, arginfo_array_void, ZEND_ACC_PUBLIC)
1912: SPL_ME(Array, ksort, arginfo_array_void, ZEND_ACC_PUBLIC)
1913: SPL_ME(Array, uasort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1914: SPL_ME(Array, uksort, arginfo_array_uXsort, ZEND_ACC_PUBLIC)
1915: SPL_ME(Array, natsort, arginfo_array_void, ZEND_ACC_PUBLIC)
1916: SPL_ME(Array, natcasesort, arginfo_array_void, ZEND_ACC_PUBLIC)
1917: SPL_ME(Array, unserialize, arginfo_array_unserialize, ZEND_ACC_PUBLIC)
1918: SPL_ME(Array, serialize, arginfo_array_void, ZEND_ACC_PUBLIC)
1919: /* ArrayIterator specific */
1920: SPL_ME(Array, rewind, arginfo_array_void, ZEND_ACC_PUBLIC)
1921: SPL_ME(Array, current, arginfo_array_void, ZEND_ACC_PUBLIC)
1922: SPL_ME(Array, key, arginfo_array_void, ZEND_ACC_PUBLIC)
1923: SPL_ME(Array, next, arginfo_array_void, ZEND_ACC_PUBLIC)
1924: SPL_ME(Array, valid, arginfo_array_void, ZEND_ACC_PUBLIC)
1925: SPL_ME(Array, seek, arginfo_array_seek, ZEND_ACC_PUBLIC)
1926: PHP_FE_END
1927: };
1928:
1929: static const zend_function_entry spl_funcs_RecursiveArrayIterator[] = {
1930: SPL_ME(Array, hasChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
1931: SPL_ME(Array, getChildren, arginfo_array_void, ZEND_ACC_PUBLIC)
1932: PHP_FE_END
1933: };
1934: /* }}} */
1935:
1936: /* {{{ PHP_MINIT_FUNCTION(spl_array) */
1937: PHP_MINIT_FUNCTION(spl_array)
1938: {
1939: REGISTER_SPL_STD_CLASS_EX(ArrayObject, spl_array_object_new, spl_funcs_ArrayObject);
1940: REGISTER_SPL_IMPLEMENTS(ArrayObject, Aggregate);
1941: REGISTER_SPL_IMPLEMENTS(ArrayObject, ArrayAccess);
1942: REGISTER_SPL_IMPLEMENTS(ArrayObject, Serializable);
1.1.1.3 misho 1943: REGISTER_SPL_IMPLEMENTS(ArrayObject, Countable);
1.1 misho 1944: memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1945:
1946: spl_handler_ArrayObject.clone_obj = spl_array_object_clone;
1947: spl_handler_ArrayObject.read_dimension = spl_array_read_dimension;
1948: spl_handler_ArrayObject.write_dimension = spl_array_write_dimension;
1949: spl_handler_ArrayObject.unset_dimension = spl_array_unset_dimension;
1950: spl_handler_ArrayObject.has_dimension = spl_array_has_dimension;
1951: spl_handler_ArrayObject.count_elements = spl_array_object_count_elements;
1952:
1953: spl_handler_ArrayObject.get_properties = spl_array_get_properties;
1954: spl_handler_ArrayObject.get_debug_info = spl_array_get_debug_info;
1955: spl_handler_ArrayObject.read_property = spl_array_read_property;
1956: spl_handler_ArrayObject.write_property = spl_array_write_property;
1957: spl_handler_ArrayObject.get_property_ptr_ptr = spl_array_get_property_ptr_ptr;
1958: spl_handler_ArrayObject.has_property = spl_array_has_property;
1959: spl_handler_ArrayObject.unset_property = spl_array_unset_property;
1960:
1.1.1.2 misho 1961: spl_handler_ArrayObject.compare_objects = spl_array_compare_objects;
1962:
1.1 misho 1963: REGISTER_SPL_STD_CLASS_EX(ArrayIterator, spl_array_object_new, spl_funcs_ArrayIterator);
1964: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Iterator);
1965: REGISTER_SPL_IMPLEMENTS(ArrayIterator, ArrayAccess);
1966: REGISTER_SPL_IMPLEMENTS(ArrayIterator, SeekableIterator);
1967: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Serializable);
1.1.1.3 misho 1968: REGISTER_SPL_IMPLEMENTS(ArrayIterator, Countable);
1.1 misho 1969: memcpy(&spl_handler_ArrayIterator, &spl_handler_ArrayObject, sizeof(zend_object_handlers));
1970: spl_ce_ArrayIterator->get_iterator = spl_array_get_iterator;
1971:
1972: REGISTER_SPL_SUB_CLASS_EX(RecursiveArrayIterator, ArrayIterator, spl_array_object_new, spl_funcs_RecursiveArrayIterator);
1973: REGISTER_SPL_IMPLEMENTS(RecursiveArrayIterator, RecursiveIterator);
1974: spl_ce_RecursiveArrayIterator->get_iterator = spl_array_get_iterator;
1975:
1976: REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1977: REGISTER_SPL_CLASS_CONST_LONG(ArrayObject, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1978:
1979: REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "STD_PROP_LIST", SPL_ARRAY_STD_PROP_LIST);
1980: REGISTER_SPL_CLASS_CONST_LONG(ArrayIterator, "ARRAY_AS_PROPS", SPL_ARRAY_ARRAY_AS_PROPS);
1981:
1982: REGISTER_SPL_CLASS_CONST_LONG(RecursiveArrayIterator, "CHILD_ARRAYS_ONLY", SPL_ARRAY_CHILD_ARRAYS_ONLY);
1983:
1984: return SUCCESS;
1985: }
1986: /* }}} */
1987:
1988: /*
1989: * Local variables:
1990: * tab-width: 4
1991: * c-basic-offset: 4
1992: * End:
1993: * vim600: fdm=marker
1994: * vim: noet sw=4 ts=4
1995: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>