#include "Zend/zend_exceptions.h"
#include "php_bbcode.h"
+#include <stdbool.h>
+
/* If you declare any globals in php_bbcode.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(bbcode)
*/
zend_class_entry *bbcode_exception_ce;
/* Define all constants */
-#define BBCODE_DEF(GEN) \
- /* Types */ \
+#ifdef old_code_dropped
GEN(TYPE_ARG) /*BBCODE_TYPE_ARG*/\
GEN(TYPE_NOARG) /*BBCODE_TYPE_NOARG*/\
- GEN(TYPE_SINGLE) /*BBCODE_TYPE_SINGLE*/\
GEN(TYPE_OPTARG) /*BBCODE_TYPE_OPTARG*/\
+
+#endif
+
+#define BBCODE_DEF(GEN) \
+ /* Types */ \
GEN(TYPE_ROOT) /*BBCODE_TYPE_ROOT*/\
+ GEN(TYPE_MULTI) /*BBCODE_TYPE_ARG|BBCODE_TYPE_OPTARG|BBCODE_TYPE_NOARG*/\
+ GEN(TYPE_SINGLE) /*BBCODE_TYPE_SINGLE*/\
\
/* Quotes */ \
GEN(QUOTE_DOUBLE) /*BBCODE_ARG_DOUBLE_QUOTE*/\
/* Generate zend const version */
#define BBCODE_GEN_CONST(NAME) zend_declare_class_constant_long(bbcode_ce, #NAME, sizeof(#NAME) - 1, BBCODE_ ## NAME TSRMLS_CC);
+/* Defined in /usr/include/php/Zend/zend_types.h +382 */
+#define BBCODE_GET_TYPE(TYPE) (TYPE==IS_UNDEF)?"undef":( \
+ (TYPE==IS_NULL)?"null":( \
+ (TYPE==IS_FALSE)?"false":( \
+ (TYPE==IS_TRUE)?"true":( \
+ (TYPE==IS_LONG)?"long":( \
+ (TYPE==IS_DOUBLE)?"double":( \
+ (TYPE==IS_STRING)?"string":( \
+ (TYPE==IS_ARRAY)?"array":( \
+ (TYPE==IS_OBJECT)?"object":( \
+ (TYPE==IS_RESOURCE)?"resource":( \
+ (TYPE==IS_REFERENCE)?"reference":( \
+ (TYPE==IS_CONSTANT_AST)?"constant":"unknown"\
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ ) \
+ )
+
/* All flags enum set */
enum {
BBCODE_DEF(BBCODE_GEN_ENUM)
* TODO: Set it in an ini ? */
#define BBCODE_DEFAULT_FLAG BBCODE_QUOTE_DOUBLE|BBCODE_QUOTE_SIMPLE|BBCODE_QUOTE_ESCAPE|BBCODE_CORRECT_AUTO|BBCODE_CORRECT_REOPEN|BBCODE_SMILEY_ON|BBCODE_CLOSE_AUTO|BBCODE_REMOVE_EMPTY
-/*static inline bbcode_object *bbcode_object_from_zend_object(zend_object *obj) {
- return (bbcode_object *)((char*)(obj) - XtOffsetOf(bbcode_object, std));
-}*/
-
-static inline bbcode_object* bbcode_fetch(zend_object *obj) {
- return (bbcode_object *)((char *)obj - XtOffsetOf(bbcode_object, std));
-}
-
-#define Z_BBCODE_P(zv) bbcode_fetch(Z_OBJ_P((zv)))
-
+/* {{{ Function prototypes (bbcode_destroy|bbcode_free|bbcode_clone|bbcode_create) */
static void bbcode_destroy(bbcode_object *obj TSRMLS_DC);
static void bbcode_free(bbcode_object *obj TSRMLS_DC);
static zend_object *bbcode_clone(zval *obj TSRMLS_DC);
static zend_object *bbcode_create(zend_class_entry *ce TSRMLS_DC);
+/* }}} */
+
+/* {{{ static inline bbcode_object* bbcode_fetch(zend_object *obj TSRMLS_DC) {
+ * BBCode object fetch function */
+static inline bbcode_object* bbcode_fetch(zend_object *obj TSRMLS_DC) {
+ return (bbcode_object *)((char *)obj - XtOffsetOf(bbcode_object, std));
+}
+/* }}} */
+
+/* {{{ Z_BBCODE_P(zv) bbcode_fetch(Z_OBJ_P((zv)))
+ * BBCode object pointer fetch macro */
+#define Z_BBCODE_P(zv) bbcode_fetch(Z_OBJ_P((zv)))
+/* }}} */
/* {{{ static void bbcode_destroy(bbcode_object *obj TSRMLS_DC) {
* BBCode object destroy call */
}
/* }}} */
-/* {{{ static zend_object *bbcode_clone(zval *obj) {
+/* {{{ static zend_object *bbcode_clone(zval *obj TSRMLS_DC) {
* BBCode object clone call */
-static zend_object *bbcode_clone(zval *obj) {
+static zend_object *bbcode_clone(zval *obj TSRMLS_DC) {
+ /* Fetch pointer on old obj */
zend_object *oldobj = Z_OBJ_P(obj);
+ /* Create pointer on nex obj */
zend_object *newobj = bbcode_create(oldobj->ce);
+ /* Call members cloning function */
zend_objects_clone_members(newobj, oldobj);
- /*Retrieve from zend object old bbcode*/
+ /* Retrieve from zend object old bbcode */
bbcode_object *bboldobj = Z_BBCODE_P(obj);
- /*Retrieve from zend object new bbcode*/
+
+ /* Retrieve from zend object new bbcode */
bbcode_object *bbnewobj = bbcode_fetch(newobj);
- /*Restore object member values*/
- /*TODO: deal with the other one*/
+ /* Restore object member values */
+ //TODO: deal with the other one (tag|smiley)
Z_LVAL(bbnewobj->flag) = Z_LVAL(bboldobj->flag);
+ /* Return the new object */
return newobj;
}
/* }}} */
/* }}} */
/* {{{ ZEND_BEGIN_ARG_INFO_EX(bbcode_construct_arginfo) */
+// ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args)
ZEND_BEGIN_ARG_INFO_EX(bbcode_construct_arginfo, 0, 0, 1)
- ZEND_ARG_ARRAY_INFO(0, tag, 1)
- ZEND_ARG_ARRAY_INFO(0, smiley, 1)
+ // ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null)
+ ZEND_ARG_ARRAY_INFO(0, tag, 0)
+ ZEND_ARG_ARRAY_INFO(0, smiley, 0)
+ // ZEND_ARG_INFO(pass_by_ref, name)
ZEND_ARG_INFO(0, flag)
ZEND_END_ARG_INFO()
/* }}} */
/* {{{ ZEND_BEGIN_ARG_INFO_EX(bbcode_parse_arginfo) */
+// ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args)
ZEND_BEGIN_ARG_INFO_EX(bbcode_parse_arginfo, 0, 0, 1)
+ // ZEND_ARG_INFO(pass_by_ref, name)
ZEND_ARG_INFO(0, str)
ZEND_END_ARG_INFO()
/* }}} */
-/* { { { PHP_METHOD(BBCode, __construct) {
+/* { { { static zend_bool *bbcode_check_tag(HashTable *tag TSRMLS_DC) {
+ * Check that tag hash is valid */
+static zend_bool bbcode_check_tag(HashTable *tag TSRMLS_DC) {
+ /* Key numeric value */
+ zend_long idx;
+ /* Key string */
+ zend_string *key;
+ /* Value */
+ zval *val;
+
+ /* Key position */
+ int pos = 0;
+
+ /* Has a root */
+ int hasRoot = 0;
+
+ /* Iterate on each key val until hash end is reached */
+ ZEND_HASH_FOREACH_KEY_VAL(tag, idx, key, val) {
+ /* Check if key is a string */
+ if (!key) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %ld[%d] from argument tag is not an expected string", idx, pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Check that value exists */
+ if (val == NULL) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d] from argument tag is NULL instead of expected array", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ /* Check that value is an array */
+ } else if (Z_TYPE_P(val) != IS_ARRAY) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d] from argument tag is %s[%d] instead of expected array", ZSTR_VAL(key), pos, BBCODE_GET_TYPE(Z_TYPE_P(val)), Z_TYPE_P(val));
+ /* Return failure */
+ return 0;
+ }
+
+ /* Store child tag array */
+ HashTable *ctag = Z_ARRVAL_P(val);
+ /* Child key numeric value */
+ zend_long cidx;
+ /* Child key string */
+ zend_string *ckey;
+ /* Child value */
+ zval *cval;
+
+ /* Child key position */
+ int cpos = 0, type;
+
+ /* Detect if entry has a type, parent, child, open, close, default or arg key to display error if mandatory field is missing */
+ bool hasType = false, hasParent = false, hasChild = false, hasOpen = false, hasClose = false, hasDefault = false, hasArg = false;
+
+ /* Iterate on each ckey cval until hash end is reached */
+ ZEND_HASH_FOREACH_KEY_VAL(ctag, cidx, ckey, cval) {
+ /* Check if ckey is a string */
+ if (!ckey) {
+ /* Display error about long ckey */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d]/%ld[%d] from argument tag is not an expected string", ZSTR_VAL(key), pos, cidx, cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Check if ckey is empty */
+ if (ZSTR_LEN(ckey) == 0) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d]/%s[%d] from argument tag is empty not one of expected type|parent|child|open|close|default string", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ /* Check if current ckey is type */
+ } else if (strcmp("type", ZSTR_VAL(ckey)) == 0) {
+ /* Extract type */
+ type = Z_LVAL_P(cval);
+
+ /* Check that current type is valid */
+ if (
+ type != BBCODE_TYPE_ROOT &&
+ type != BBCODE_TYPE_MULTI &&
+ type != BBCODE_TYPE_SINGLE
+ ) {
+ /* Display error about unexpected type value */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value '%d' for key %s[%d]/%s[%d] from argument tag is not one of expected BBCODE::TYPE_(ROOT|MULTI|SINGLE) constant", type, ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ /* Check if root */
+ } else if (type == BBCODE_TYPE_ROOT) {
+ /* Grow hasRoot */
+ hasRoot++;
+ }
+
+ /* Set hasType */
+ hasType = true;
+ /* Check if current key is parent */
+ } else if (strcmp("parent", ZSTR_VAL(ckey)) == 0) {
+ /* Check that value exists */
+ if (cval == NULL) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d]/%s[%d] from argument tag is NULL instead of expected array", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ /* Check that value is an array */
+ } else if (Z_TYPE_P(cval) != IS_ARRAY) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d]/%s[%d] from argument tag is %s[%d] instead of expected array", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos, BBCODE_GET_TYPE(Z_TYPE_P(cval)), Z_TYPE_P(cval));
+ /* Return failure */
+ return 0;
+ }
+
+ /* Parent value */
+ zval *pval;
+
+ /* Child key position */
+ int ppos = 0;
+
+ /* Iterate on each val until hash end is reached */
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(cval), pval) {
+ /* Check that parent val is a string */
+ if (Z_TYPE_P(pval) != IS_STRING) {
+ /* Display error about not string */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Parent value %s[%d] for key %s[%d]/%s[%d] is not an expected string", Z_STRVAL_P(pval), ppos, ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Tag key */
+ zend_string *tkey;
+
+ /* Reset found flag */
+ bool found = false;
+
+ /* Iterate on each key until hash end is reached */
+ ZEND_HASH_FOREACH_STR_KEY(tag, tkey) {
+ /* Check that tkey is a string and is identical */
+ if (tkey != NULL && strcmp(Z_STRVAL_P(pval), ZSTR_VAL(tkey)) == 0) {
+ /* We found parent value in tag keys*/
+ found = true;
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ /* Check if we found the key */
+ if (!found) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Parent value %s for key %s[%d]/%s[%d] is not present in tag keys", Z_STRVAL_P(pval), ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Grow ppos */
+ ppos++;
+ } ZEND_HASH_FOREACH_END();
+
+ /* Set hasParent */
+ hasParent = true;
+ /* Check if current key is child */
+ } else if (strcmp("child", ZSTR_VAL(ckey)) == 0) {
+ /* Check that value exists */
+ if (cval == NULL) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d]/%s[%d] from argument tag is NULL instead of expected array", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ /* Check that value is an array */
+ } else if (Z_TYPE_P(cval) != IS_ARRAY) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d]/%s[%d] from argument tag is %s[%d] instead of expected array", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos, BBCODE_GET_TYPE(Z_TYPE_P(cval)), Z_TYPE_P(cval));
+ /* Return failure */
+ return 0;
+ }
+
+ /* Child value */
+ zval *ccval;
+
+ /* Child key position */
+ int ccpos = 0;
+
+ /* Iterate on each val until hash end is reached */
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(cval), ccval) {
+ /* Check that child val is a string */
+ if (Z_TYPE_P(ccval) != IS_STRING) {
+ /* Display error about not string */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Child value %s[%d] for key %s[%d]/%s[%d] is not an expected string", Z_STRVAL_P(ccval), ccpos, ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Tag key */
+ zend_string *tkey;
+
+ /* Reset found flag */
+ bool found = false;
+
+ /* Iterate on each key until hash end is reached */
+ ZEND_HASH_FOREACH_STR_KEY(tag, tkey) {
+ /* Check that tkey is a string and is identical */
+ if (tkey != NULL && strcmp(Z_STRVAL_P(ccval), ZSTR_VAL(tkey)) == 0) {
+ /* We found child value in tag keys*/
+ found = true;
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ /* Check if we found the key */
+ if (!found) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Child value %s for key %s[%d]/%s[%d] is not present in tag keys", Z_STRVAL_P(ccval), ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Grow ccpos */
+ ccpos++;
+ } ZEND_HASH_FOREACH_END();
+
+ /* Set hasChild */
+ hasChild = true;
+ /* Check if current key is open */
+ } else if (strcmp("open", ZSTR_VAL(ckey)) == 0) {
+ /* Set hasOpen */
+ hasOpen = true;
+ /* Check if current key is close */
+ } else if (strcmp("close", ZSTR_VAL(ckey)) == 0) {
+ /* Set hasClose */
+ hasClose = true;
+ /* Check if current key is default */
+ } else if (strcmp("default", ZSTR_VAL(ckey)) == 0) {
+ /* Set hasDefault */
+ hasDefault = true;
+ /* Check if current key is arg */
+ } else if (strcmp("arg", ZSTR_VAL(ckey)) == 0) {
+ /* Set hasArg */
+ hasArg = true;
+ /* Check if current key is unknown */
+ } else {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d]/%s[%d] from argument tag is not one of expected type|parent|child|open|close|default string", ZSTR_VAL(key), pos, ZSTR_VAL(ckey), cpos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Grow cpos */
+ cpos++;
+ } ZEND_HASH_FOREACH_END();
+
+ /* Check if val array is initialized */
+ /*XXX: this step is required to workaround zend engine half initialized hashtable when val array is empty that trigger a segfault*/
+ if ((GC_FLAGS(Z_ARR_P(val)) & HASH_FLAG_INITIALIZED) != HASH_FLAG_INITIALIZED) {
+ /* Allocate hash table */
+ /* XXX: this is required to avoid segfault in zend_hash_add when the array is empty */
+ ALLOC_HASHTABLE(Z_ARR_P(val));
+ /* Init hash table */
+ zend_hash_init(Z_ARR_P(val), 0, NULL, ZVAL_PTR_DTOR, 0);
+ zend_hash_copy(Z_ARR_P(val), ctag, (copy_ctor_func_t) zval_add_ref);
+ }
+
+ /* Check if entry has no type */
+ if (!hasType) {
+ /* Type zval */
+ zval tval;
+
+ /* Type key string */
+ zend_string *tkey = zend_string_init("type", strlen("type"), 0);
+
+ /* Check if key is '' */
+ if (ZSTR_LEN(key) == 0) {
+ /* Set tval value to root */
+ ZVAL_LONG(&tval, (type = BBCODE_TYPE_ROOT));
+
+ /* Grow hasRoot */
+ hasRoot++;
+ /* Check if key is img */
+ } else if (strcmp("img", ZSTR_VAL(key)) == 0) {
+ /* Set tval value to single */
+ ZVAL_LONG(&tval, (type = BBCODE_TYPE_SINGLE));
+ /* Handle other key as multi */
+ } else {
+ /* Set tval value to multi */
+ ZVAL_LONG(&tval, (type = BBCODE_TYPE_MULTI));
+ }
+
+ /* Add new type key */
+ ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), tkey, &tval) != NULL);
+
+ /* Free type key */
+ zend_string_release(tkey);
+
+ /* Set hasType */
+ hasType = true;
+ }
+
+ /* Check for root type */
+ if (type == BBCODE_TYPE_ROOT) {
+ /* Check if has parent */
+ if (hasParent) {
+ /* Display error about parent entry */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d] from argument tag of type BBCODE::TYPE_ROOT cannot have a parent entry", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* TODO: Compute child here */
+ //TODO: set child if not provided for ROOT (has to loop on each possible type and check if a parent array is present with this tag inside, if none set to all possible tag except '' one)
+ //TODO: display error if type=root and child was not provided| XXX: we can compute that shit here for lazy morons
+ if (!hasChild) {
+ //TODO compute child by looping on each non root element and element with no parent or with root in parent
+ //XXX: it seems that a better approach would be to save root element en push each element one by one ?
+ }
+ /* Check for multi type */
+ } else if (type == BBCODE_TYPE_MULTI) {
+ /* Check if has open entry */
+ if (!hasOpen) {
+ /* Key string */
+ zend_string *mkey = zend_string_init("open", strlen("open"), 0);
+
+ /* Value */
+ zval mval;
+
+ /* Tag */
+ zend_string *mtag = zend_string_init("<>", strlen("<>") + ZSTR_LEN(key) + (hasArg?strlen("%s"):0), 0);
+ memcpy(ZSTR_VAL(mtag)+sizeof(char), ZSTR_VAL(key), ZSTR_LEN(key));
+ if (hasArg) {
+ memcpy(ZSTR_VAL(mtag)+(1+ZSTR_LEN(key))*sizeof(char), "%s>", strlen("%s>"));
+ } else {
+ memcpy(ZSTR_VAL(mtag)+(1+ZSTR_LEN(key))*sizeof(char), ">", strlen(">"));
+ }
+
+ /* Set value */
+ ZVAL_STRING(&mval, ZSTR_VAL(mtag));
+
+ /* Add new key */
+ ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), mkey, &mval) != NULL);
+
+ /* Free tag */
+ zend_string_release(mtag);
+
+ /* Free key */
+ zend_string_release(mkey);
+ }
+
+ /* Check if has close entry */
+ if (!hasClose) {
+ /* Key string */
+ zend_string *mkey = zend_string_init("close", strlen("close"), 0);
+
+ /* Value */
+ zval mval;
+
+ /* Tag */
+ zend_string *mtag = zend_string_init("</>", strlen("</>") + ZSTR_LEN(key), 0);
+ memcpy(ZSTR_VAL(mtag)+2*sizeof(char), ZSTR_VAL(key), ZSTR_LEN(key));
+ memcpy(ZSTR_VAL(mtag)+(2+ZSTR_LEN(key))*sizeof(char), ">", strlen(">"));
+
+ /* Set value */
+ ZVAL_STRING(&mval, ZSTR_VAL(mtag));
+
+ /* Add new key */
+ ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), mkey, &mval) != NULL);
+
+ /* Free tag */
+ zend_string_release(mtag);
+
+ /* Free key */
+ zend_string_release(mkey);
+ }
+
+ /* Check if has not default */
+ if (!hasDefault) {
+ /* Key string */
+ zend_string *mkey = zend_string_init("default", strlen("default"), 0);
+
+ /* Value */
+ zval mval;
+
+ /* Set value */
+ ZVAL_STRING(&mval, "%s");
+
+ /* Add new key */
+ ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), mkey, &mval) != NULL);
+
+ /* Free key */
+ zend_string_release(mkey);
+ }
+
+ //TODO: set parent&child if not provided for ARG|OPTARG|NOARG|SINGLE (has to loop on each possible type and check if no child array or present in child array if available)
+
+ /* Check for single type */
+ } else if (type == BBCODE_TYPE_SINGLE) {
+ /* Check if has open entry */
+ if (hasOpen) {
+ /* Display error about open entry */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d] from argument tag of type BBCODE::TYPE_SINGLE cannot have an open entry", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Check if has close entry */
+ if (hasClose) {
+ /* Display error about close entry */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d] from argument tag of type BBCODE::TYPE_SINGLE cannot have a close entry", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Check if has not default */
+ if (!hasDefault) {
+ /* Key string */
+ zend_string *skey = zend_string_init("default", strlen("default"), 0);
+
+ /* Value */
+ zval sval;
+
+ /* Tag */
+ zend_string *stag;
+
+ /* Check if jey is img */
+ if (strcmp("img", ZSTR_VAL(key)) == 0) {
+ stag = zend_string_init("<img src=\"%s\"/>", strlen("<img src=\"%s\"/>") + (hasArg?strlen("%s"):0), 0);
+ if (hasArg) {
+ memcpy(ZSTR_VAL(stag)+strlen("<img src=\"%s\"")*sizeof(char), "%s/>", strlen("%s/>"));
+ } else {
+ memcpy(ZSTR_VAL(stag)+strlen("<img src=\"%s\"")*sizeof(char), "/>", strlen("/>"));
+ }
+ } else {
+ stag = zend_string_init("</>", strlen("</>") + ZSTR_LEN(key) + (hasArg?strlen("%s"):0), 0);
+ memcpy(ZSTR_VAL(stag)+sizeof(char), ZSTR_VAL(key), ZSTR_LEN(key));
+ if (hasArg) {
+ memcpy(ZSTR_VAL(stag)+(1+ZSTR_LEN(key))*sizeof(char), "%s/>", strlen("%s/>"));
+ } else {
+ memcpy(ZSTR_VAL(stag)+(1+ZSTR_LEN(key))*sizeof(char), "/>", strlen("/>"));
+ }
+ }
+
+ /* Set value */
+ ZVAL_STRING(&sval, ZSTR_VAL(stag));
+
+ /* Add new key */
+ ZEND_ASSERT(zend_hash_add(Z_ARR_P(val), skey, &sval) != NULL);
+
+ /* Free tag */
+ zend_string_release(stag);
+
+ /* Free key */
+ zend_string_release(skey);
+ }
+
+ /* Check if has child */
+ if (hasChild) {
+ /* Display error about child entry */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %s[%d] from argument tag of type BBCODE::TYPE_SINGLE cannot have a child entry", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ }
+
+ //TODO: set parent if not provided for ARG|OPTARG|NOARG|SINGLE (has to loop on each possible type and check if no child array or present in child array if available)
+ }
+
+#ifndef DEBUG
+ printf("key=>%s\n", ZSTR_VAL(key));
+ fflush(NULL);
+ php_debug_zval_dump(val, 0);
+ fflush(NULL);
+#endif
+
+ /* Grow pos */
+ pos++;
+ } ZEND_HASH_FOREACH_END();
+
+ /* Check if not one unique root */
+ if (hasRoot != 1) {
+ /* Display error about multiple root */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Has %d BBCODE::TYPE_ROOT entry, require one unique", hasRoot);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Return success */
+ return 1;
+}
+/* }}} */
+
+/* {{{ static zend_bool *bbcode_check_smiley(HashTable *smiley TSRMLS_DC) {
+ * Check that smiley hash is valid */
+static zend_bool bbcode_check_smiley(HashTable *smiley TSRMLS_DC) {
+ /* Key numeric value */
+ zend_long idx;
+ /* Key string */
+ zend_string *key;
+ /* Value */
+ zval *val;
+
+ /* Key position */
+ int pos = 0;
+
+ /* Iterate on each key val until hash end is reached */
+ ZEND_HASH_FOREACH_KEY_VAL(smiley, idx, key, val) {
+ /* Check that key is a string */
+ if (key == NULL) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Key %ld[%d] from argument smiley is not an expected string", idx, pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Check that value exists */
+ if (val == NULL) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d] from argument smiley is NULL instead of expected array", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ /* Check that value is not an array */
+ } else if (Z_TYPE_P(val) == IS_ARRAY) {
+ /* Display error about long key */
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "Value for key %s[%d] from argument smiley is an array instead of expected string", ZSTR_VAL(key), pos);
+ /* Return failure */
+ return 0;
+ }
+
+ /* Grow pos */
+ pos++;
+ } ZEND_HASH_FOREACH_END();
+
+ /* Return success */
+ return 1;
+}
+/* }}} */
+
+/* {{{ PHP_METHOD(BBCode, __construct) {
*/
PHP_METHOD(BBCode, __construct) {
HashTable *tag = NULL;
HashTable *smiley = NULL;
- long flag = BBCODE_DEFAULT_FLAG;
+ zend_long flag = BBCODE_DEFAULT_FLAG;
/*TODO: init tag with [
'' => [ ? ]
* TODO: make sure it's not really a global and per-app param ?
* */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|Hl", &tag, &smiley, &flag) == FAILURE) {
- return;
- }
-
- //bbcode_object *obj = bbcode_fetch(Z_OBJ_P(getThis()));
+ /* Retrieve the pointer to this object */
bbcode_object *obj = Z_BBCODE_P(getThis());
+
+ /* Verify that the pointer is leading somewhere */
assert(obj != NULL);
- //TODO: set tag and smiley
+ /* Set default values */
+ obj->tag = tag;
+ obj->smiley = smiley;
+ Z_LVAL(obj->flag) = flag;
- if (flag) {
- Z_LVAL(obj->flag) = flag;
+ /* Parse parameters */
+ ZEND_PARSE_PARAMETERS_START(1, 3)
+ Z_PARAM_ARRAY_HT(tag)
+ Z_PARAM_ARRAY_HT(smiley)
+ Z_PARAM_LONG(flag)
+ ZEND_PARSE_PARAMETERS_END();
+
+ /*if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "h|hl", &tag, &smiley, &flag) == FAILURE) {
+ return;
+ }*/
+
+ /* Save tag argument hash in current object */
+ //TODO: check tag structure
+ if (bbcode_check_tag(tag)) {
+ obj->tag = tag;
+ } else {
+ zend_hash_destroy(tag);
+ zend_hash_destroy(smiley);
+ ZVAL_NULL(getThis() TSRMLS_CC);
+ return;
}
+ /* Save smiley argument hash in current object if provided */
+ //TODO: check smiley structure
if (smiley) {
- obj->smiley = smiley;
+ if (bbcode_check_smiley(smiley)) {
+ obj->smiley = smiley;
+ } else {
+ zend_hash_destroy(tag);
+ zend_hash_destroy(smiley);
+ ZVAL_NULL(getThis() TSRMLS_CC);
+ return;
+ }
}
- obj->tag = tag;
-
- //obj = zend_object_store_get_object(getThis() TSRMLS_CC);
- //if (error) {
- //ZVAL_NULL(this);
- //}
+ /* Save flag argument long in current object if provided */
+ if (flag) {
+ Z_LVAL(obj->flag) = flag;
+ }
}
/* }}} */
/* {{{ PHP_METHOD(BBCode, __destruct) {
*/
PHP_METHOD(BBCode, __destruct) {
+ /* Retrieve the pointer to this object */
+ bbcode_object *obj = Z_BBCODE_P(getThis());
+
+ /* Verify that the pointer is leading somewhere */
+ assert(obj != NULL);
+
+ /* Free tag hashtable */
+ if (obj->tag) {
+ efree(obj->tag);
+ }
+
+ /* Free smiley hashtable */
+ if (obj->smiley) {
+ efree(obj->smiley);
+ }
}
/* }}} */
-/* {{{ PHP_METHOD(BBCode, parse) {
+/* { { { PHP_METHOD(BBCode, parse) {
*/
PHP_METHOD(BBCode, parse) {
zend_string *str = NULL;
return;
}
- //TODO: apply the parsing on string
+ //TODO: create a tree for storing result
+ //TODO: apply recursively search of next possible tags (or a closing parent tag ?) regexp and store result inside
+ //TODO: d
+ //TODO: apply the smiley parsing on string
RETURN_STR(str);
}