+               /* Generate open and close pattern for tag with child */
+               if (hasChild) {
+                       /* Child array and value */
+                       zval *child, *ccval;
+
+                       /* Close pattern length */
+                       int len2, cpos2;
+
+                       /* Close pattern buf */
+                       char *buf2;
+
+                       /* Retrieve child array */
+                       /* XXX: child should exists here and be an array */
+                       ZEND_ASSERT(((child = zend_hash_str_find(Z_ARR_P(val), "child", strlen("child"))) != NULL) && Z_TYPE_P(child) == IS_ARRAY);
+
+                       /* Init open pattern buffer and length */
+                       /* XXX: lagest bbcode tag length seems to be 7, we guess that 10 is enough to contain every tag and pipe */
+                       buf = (char *)malloc((len = strlen("/\\[()(?:=([^\\]]*))?\\]/") + zend_array_count(Z_ARR_P(child))*10)*sizeof(char));
+
+                       /* Init close pattern buffer and length */
+                       /* XXX: lagest bbcode tag length seems to be 7, we guess that 10 is enough to contain every tag and pipe */
+                       buf2 = (char *)malloc((len2 = strlen("/\\[\\/()\\]/") + zend_array_count(Z_ARR_P(child))*10)*sizeof(char));
+
+                       /* Init cpos and cpos2 */
+                       cpos = 4; cpos2 = 6;
+
+                       /* Assign open pattern begin */
+                       ZEND_ASSERT(memcpy(buf, &"/\\[(", 4) != NULL);
+
+                       /* Assign close pattern begin */
+                       ZEND_ASSERT(memcpy(buf2, &"/\\[\\/(", 6) != NULL);
+
+                       /* Iterate on each val until hash end is reached */
+                       ZEND_HASH_FOREACH_VAL(Z_ARR_P(child), ccval) {
+                               /* Check that child val is a string */
+                               /* XXX: ccval should be an array here */
+                               ZEND_ASSERT(Z_TYPE_P(ccval) == IS_STRING);
+
+                               /* Init zval node and type */
+                               zval *znode, *ztype;
+
+                               /* Init zend_long type */
+                               zend_long ltype;
+
+                               /* Retrieve the node */
+                               ZEND_ASSERT((znode = zend_hash_find(tag, Z_STR_P(ccval))) != NULL && Z_TYPE_P(znode) == IS_ARRAY);
+
+                               /* Try to retrieve the type */
+                               //ZEND_ASSERT((ztype = zend_hash_str_find(Z_ARR_P(znode), "type", strlen("type"))) != NULL && Z_TYPE_P(ztype) == IS_LONG);
+                               /* XXX: the type may not yet available here, it is fixed when checking the tag itself later */
+                               if ((ztype = zend_hash_str_find(Z_ARR_P(znode), "type", strlen("type"))) == NULL || Z_TYPE_P(ztype) != IS_LONG) {
+                                       /* Check if empty tag */
+                                       if (Z_STRLEN_P(ccval) == 0) {
+                                               /* Set as root */
+                                               ltype = BBCODE_TYPE_ROOT;
+                                       } else if (strcmp("img", Z_STRVAL_P(ccval)) == 0) {
+                                               /* Set as single */
+                                               ltype = BBCODE_TYPE_SINGLE;
+                                       } else {
+                                               /* Set as multi */
+                                               ltype = BBCODE_TYPE_MULTI;
+                                       }
+                               /* Type zval available and usable */
+                               } else {
+                                       /* Set type from zval value */
+                                       ltype = Z_LVAL_P(ztype);
+                               }
+
+                               /* Check if not first string to add */
+                               if (cpos > 4) {
+                                       /* Set pipe before next tag */
+                                       *(buf+cpos) = '|';
+                                       /* Move position */
+                                       cpos++;
+                                       /* Check if not single type */
+                                       if (ltype != BBCODE_TYPE_SINGLE) {
+                                               /* Set pipe before next tag */
+                                               *(buf2+cpos2) = '|';
+                                               /* Move position */
+                                               cpos2++;
+                                       }
+                               }
+
+                               /* Check if not single type */
+                               if (ltype != BBCODE_TYPE_SINGLE) {
+                                       /* Grow buf if necessary */
+                                       if (cpos + Z_STRLEN_P(ccval) + 18 > len) {
+                                               /* We resize buf to current length(cpos), the string size plus eighteen char for trailing pattern */
+                                               buf = (char *)realloc(buf, (len = cpos + Z_STRLEN_P(ccval) + 18)*sizeof(char));
+                                       }
+
+                                       /* Copy string in buf */
+                                       ZEND_ASSERT(memcpy(buf+cpos, Z_STRVAL_P(ccval), Z_STRLEN_P(ccval)) != NULL);
+
+                                       /* Move cpos */
+                                       cpos += Z_STRLEN_P(ccval);
+
+                                       /* Grow buf2 if necessary */
+                                       if (cpos2 + Z_STRLEN_P(ccval) + 4 > len2) {
+                                               /* We resize buf2 to current length(cpos2), the string size plus four char for trailing pattern */
+                                               buf2 = (char *)realloc(buf2, (len2 = cpos2 + Z_STRLEN_P(ccval) + 4)*sizeof(char));
+                                       }
+
+                                       /* Copy string in buf2 */
+                                       ZEND_ASSERT(memcpy(buf2+cpos2, Z_STRVAL_P(ccval), Z_STRLEN_P(ccval)) != NULL);
+
+                                       /* Move cpos2 */
+                                       cpos2 += Z_STRLEN_P(ccval);
+                               /* Single type case */
+                               } else {
+                                       /* Grow buf if necessary */
+                                       if (cpos + Z_STRLEN_P(ccval) + strlen("(?:\\/)?") + 18 > len) {
+                                               /* We resize buf to current length(cpos), the string size plus three plus eighteen char for trailing pattern */
+                                               buf = (char *)realloc(buf, (len = cpos + Z_STRLEN_P(ccval) + strlen("(?:\\/)?") + 18)*sizeof(char));
+                                       }
+
+                                       /* Copy string in buf */
+                                       ZEND_ASSERT(memcpy(buf+cpos, Z_STRVAL_P(ccval), Z_STRLEN_P(ccval)) != NULL);
+
+                                       /* Append pattern in buf */
+                                       ZEND_ASSERT(memcpy(buf+cpos+Z_STRLEN_P(ccval), &"(?:\\/)?", strlen("(?:\\/)?")) != NULL);
+
+                                       /* Move cpos */
+                                       cpos += Z_STRLEN_P(ccval) + strlen("(?:\\/)?");
+                               }
+                       } ZEND_HASH_FOREACH_END();
+
+                       /* Assign open pattern begin */
+                       ZEND_ASSERT(memcpy(buf+cpos, &")(?:=([^\\]]*))?\\]/", 18) != NULL);
+
+                       /* Assign open pattern begin */
+                       ZEND_ASSERT(memcpy(buf2+cpos2, &")\\]/", 4) != NULL);
+
+                       /* Open key string */
+                       zend_string *okey = zend_string_init("opattern", strlen("opattern"), 0);
+
+                       /* Close key string */
+                       zend_string *ckey = zend_string_init("cpattern", strlen("cpattern"), 0);
+
+                       /* Open and close value */
+                       zval oval, cval;
+
+                       /* Set open value */
+                       ZVAL_STRINGL(&oval, buf, cpos + 18);
+
+                       /* Set close value */
+                       ZVAL_STRINGL(&cval, buf2, cpos2 + 4);
+
+                       /* Free buffers */
+                       free(buf); free(buf2);
+
+                       /* Add open key */
+                       ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), okey, &oval) != NULL);
+
+                       /* Add close key */
+                       ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), ckey, &cval) != NULL);
+
+                       /* Free open key */
+                       zend_string_release(okey);
+
+                       /* Free close key */
+                       zend_string_release(ckey);
+               }