Index: /trunk/mod_cacher/xc_cacher.c
===================================================================
--- /trunk/mod_cacher/xc_cacher.c	(revision 1140)
+++ /trunk/mod_cacher/xc_cacher.c	(revision 1146)
@@ -144,4 +144,8 @@
 
 static zend_bool xc_readonly_protection = 0;
+
+static zend_ulong xc_var_namespace_mode = 0;
+static char *xc_var_namespace = NULL;
+
 
 zend_bool xc_have_op_array_ctor = 0;
@@ -257,5 +261,5 @@
 			if (entry1->name_type == IS_UNICODE) {
 				return entry1->name.ustr.len == entry2->name.ustr.len
-				    && memcmp(entry1->name.ustr.val, entry2->name.ustr.val, (entry1->name.ustr.len + 1) * sizeof(UChar)) == 0;
+				    && memcmp(entry1->name.ustr.val, entry2->name.ustr.val, (entry1->name.ustr.len + 1) * sizeof(entry1->name.ustr.val[0])) == 0;
 			}
 #endif
@@ -268,31 +272,4 @@
 	}
 	return 0;
-}
-/* }}} */
-static inline int xc_entry_has_prefix_unlocked(xc_entry_type_t type, xc_entry_t *entry, zval *prefix) /* {{{ */
-{
-	/* this function isn't required but can be in unlocked */
-
-#ifdef IS_UNICODE
-	if (entry->name_type != prefix->type) {
-		return 0;
-	}
-
-	if (entry->name_type == IS_UNICODE) {
-		if (entry->name.ustr.len < Z_USTRLEN_P(prefix)) {
-			return 0;
-		}
-		return memcmp(entry->name.ustr.val, Z_USTRVAL_P(prefix), Z_USTRLEN_P(prefix) * sizeof(UChar)) == 0;
-	}
-#endif
-	if (prefix->type != IS_STRING) {
-		return 0;
-	}
-
-	if (entry->name.str.len < Z_STRLEN_P(prefix)) {
-		return 0;
-	}
-
-	return memcmp(entry->name.str.val, Z_STRVAL_P(prefix), Z_STRLEN_P(prefix)) == 0;
 }
 /* }}} */
@@ -2307,4 +2284,306 @@
 /* }}} */
 
+/* variable namespace */
+#ifdef IS_UNICODE
+void xc_var_namespace_init_from_unicodel(const UChar *string, int len TSRMLS_DC) /* {{{ */
+{
+	if (!len) {
+#ifdef IS_UNICODE
+		ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_hard));
+#endif
+		ZVAL_EMPTY_STRING(&XG(var_namespace_hard));
+	}
+	else {
+		ZVAL_UNICODE_L(&XG(uvar_namespace_hard), string, len, 1);
+		/* TODO: copy to var */
+	}
+}
+/* }}} */
+#endif
+void xc_var_namespace_init_from_stringl(const char *string, int len TSRMLS_DC) /* {{{ */
+{
+	if (!len) {
+#ifdef IS_UNICODE
+		ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_hard));
+#endif
+		ZVAL_EMPTY_STRING(&XG(var_namespace_hard));
+	}
+	else {
+		ZVAL_STRINGL(&XG(var_namespace_hard), string, len, 1);
+#ifdef IS_UNICODE
+		/* TODO: copy to uvar */
+#endif
+	}
+}
+/* }}} */
+void xc_var_namespace_init_from_long(long value TSRMLS_DC) /* {{{ */
+{
+	ZVAL_LONG(&XG(var_namespace_hard), value);
+#ifdef IS_UNICODE
+	/* TODO: copy to uvar_namespace */
+#endif
+}
+/* }}} */
+#ifdef IS_UNICODE
+void xc_var_namespace_set_unicodel(const UChar *unicode, int len TSRMLS_DC) /* {{{ */
+{
+	zval_dtor(&XG(uvar_namespace_soft));
+	zval_dtor(&XG(var_namespace_soft));
+	if (len) {
+		if (!Z_USTRLEN_P(&XG(uvar_namespace_soft))) {
+			ZVAL_UNICODEL(&XG(uvar_namespace_soft), unicode, len, 1);
+		}
+		else {
+			int buffer_len = Z_USTRLEN_P(&XG(var_namespace_hard)) + 1 + len;
+			char *buffer = emalloc((buffer_len + 1) * sizeof(unicode[0]));
+			char *p = buffer;
+			memcpy(p, Z_USTRVAL_P(&XG(var_namespace_hard)), (Z_USTRLEN_P(&XG(var_namespace_hard)) + 1));
+			p += (Z_USTRLEN_P(&XG(var_namespace_hard)) + 1) * sizeof(unicode[0]);
+			memcpy(p, unicode, (len + 1) * sizeof(unicode[0]));
+			ZVAL_UNICODEL(&XG(uvar_namespace_soft), buffer, buffer_len, 0);
+		}
+		/* TODO: copy to var */
+	}
+	else {
+#ifdef IS_UNICODE
+		XG(uvar_namespace_soft) = XG(uvar_namespace_hard);
+		zval_copy_ctor(&XG(uvar_namespace_soft));
+#endif
+		XG(var_namespace_soft) = XG(var_namespace_hard);
+		zval_copy_ctor(&XG(var_namespace_soft));
+	}
+}
+/* }}} */
+#endif
+void xc_var_namespace_set_stringl(const char *string, int len TSRMLS_DC) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_soft));
+	if (len) {
+		if (!Z_STRLEN_P(&XG(var_namespace_soft))) {
+			ZVAL_STRINGL(&XG(var_namespace_soft), string, len, 1);
+		}
+		else {
+			int buffer_len = Z_STRLEN_P(&XG(var_namespace_hard)) + 1 + len;
+			char *buffer = emalloc(buffer_len + 1);
+			char *p = buffer;
+			memcpy(p, Z_STRVAL_P(&XG(var_namespace_hard)), Z_STRLEN_P(&XG(var_namespace_hard)) + 1);
+			p += Z_STRLEN_P(&XG(var_namespace_hard)) + 1;
+			memcpy(p, string, len + 1);
+			ZVAL_STRINGL(&XG(var_namespace_soft), buffer, buffer_len, 0);
+		}
+#ifdef IS_UNICODE
+		/* TODO: copy to uvar */
+#endif
+	}
+	else {
+#ifdef IS_UNICODE
+		XG(uvar_namespace_soft) = XG(uvar_namespace_hard);
+		zval_copy_ctor(&XG(uvar_namespace_soft));
+#endif
+		XG(var_namespace_soft) = XG(var_namespace_hard);
+		zval_copy_ctor(&XG(var_namespace_soft));
+	}
+}
+/* }}} */
+static void xc_var_namespace_break(TSRMLS_D) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_soft));
+#ifdef IS_UNICODE
+	ZVAL_EMPTY_UNICODE(&XG(uvar_namespace_soft));
+#endif
+	ZVAL_EMPTY_STRING(&XG(var_namespace_soft));
+}
+/* }}} */
+static void xc_var_namespace_init(TSRMLS_D) /* {{{ */
+{
+	uid_t id = (uid_t) -1;
+
+	switch (xc_var_namespace_mode) {
+		case 1:
+			{
+				zval **server;
+				HashTable *ht;
+				zval **val;
+
+#ifdef ZEND_ENGINE_2_1
+				zend_is_auto_global("_SERVER", sizeof("_SERVER") - 1 TSRMLS_CC);
+#endif
+
+				if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void**)&server) == FAILURE
+				 || Z_TYPE_PP(server) != IS_ARRAY
+				 || !(ht = Z_ARRVAL_P(*server))
+				 || zend_hash_find(ht, xc_var_namespace, strlen(xc_var_namespace) + 1, (void**)&val) == FAILURE) {
+					xc_var_namespace_init_from_stringl(NULL, 0 TSRMLS_CC);
+				}
+				else {
+#ifdef IS_UNICODE
+					if (Z_TYPE_PP(val) == IS_UNICODE) {
+						xc_var_namespace_init_from_unicodel(Z_USTRVAL_PP(val), Z_USTRLEN_PP(val) TSRMLS_CC);
+					}
+					else
+#endif
+					{
+						xc_var_namespace_init_from_stringl(Z_STRVAL_PP(val), Z_STRLEN_PP(val) TSRMLS_CC);
+					}
+				}
+			}
+			break;
+
+		case 2:
+			if (strncmp(xc_var_namespace, "uid", 3) == 0) {
+				id = getuid();
+			}
+			else if (strncmp(xc_var_namespace, "gid", 3) == 0) {
+				id = getgid();
+			}
+
+			if (id == (uid_t) -1){
+				xc_var_namespace_init_from_stringl(NULL, 0 TSRMLS_CC);
+			}
+			else {
+				xc_var_namespace_init_from_long((long) id TSRMLS_CC);
+			}
+			break;
+
+		case 0:
+		default:
+			xc_var_namespace_init_from_stringl(xc_var_namespace, strlen(xc_var_namespace) TSRMLS_CC);
+			break;
+	}
+
+#ifdef IS_UNICODE
+	INIT_ZVAL(XG(uvar_namespace_soft));
+#endif
+	INIT_ZVAL(XG(var_namespace_soft));
+	xc_var_namespace_set_stringl("", 0 TSRMLS_CC);
+}
+/* }}} */
+static void xc_var_namespace_destroy(TSRMLS_D) /* {{{ */
+{
+#ifdef IS_UNICODE
+	zval_dtor(&XG(uvar_namespace_hard));
+	zval_dtor(&XG(uvar_namespace_soft));
+#endif
+	zval_dtor(&XG(var_namespace_hard));
+	zval_dtor(&XG(var_namespace_soft));
+}
+/* }}} */
+static int xc_var_buffer_prepare(zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+	int namespace_len;
+	switch (name->type) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+do_unicode:
+			namespace_len = Z_USTRLEN_P(&XG(uvar_namespace_soft));
+			return (namespace_len ? namespace_len + 1 : 0) + Z_USTRLEN_P(name);
+#endif
+
+		case IS_STRING:
+do_string:
+			namespace_len = Z_STRLEN_P(&XG(var_namespace_soft));
+			return (namespace_len ? namespace_len + 1 : 0) + Z_STRLEN_P(name);
+
+		default:
+#ifdef IS_UNICODE
+			convert_to_unicode(name);
+			goto do_unicode;
+#else
+			convert_to_string(name);
+			goto do_string;
+#endif
+	}
+}
+/* }}} */
+static int xc_var_buffer_alloca_size(zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+	int namespace_len;
+	switch (name->type) {
+#ifdef IS_UNICODE
+		case IS_UNICODE:
+			namespace_len = Z_USTRLEN_P(&XG(uvar_namespace_soft));
+			return !namespace_len ? 0 : (namespace_len + 1 + Z_USTRLEN_P(name) + 1) * sizeof(Z_USTRVAL_P(&XG(uvar_namespace_soft))[0]);
+#endif
+
+		case IS_STRING:
+			namespace_len = Z_STRLEN_P(&XG(var_namespace_soft));
+			return !namespace_len ? 0 : (namespace_len + 1 + Z_STRLEN_P(name) + 1);
+	}
+	assert(0);
+	return 0;
+}
+/* }}} */
+static void xc_var_buffer_init(char *buffer, zval *name TSRMLS_DC) /* {{{ prepare name, calculate buffer size */
+{
+#ifdef IS_UNICODE
+	if (Z_TYPE(name) == IS_UNICODE) {
+		memcpy(buffer, Z_USTRVAL_P(&XG(uvar_namespace_soft)), (Z_USTRLEN_P(&XG(uvar_namespace_soft)) + 1) * sizeof(Z_USTRVAL_P(name)[0]));
+		buffer += (Z_USTRLEN_P(&XG(uvar_namespace_soft)) + 1) * sizeof(Z_USTRVAL_P(name)[0]);
+		memcpy(buffer, Z_USTRVAL_P(name), (Z_USTRLEN_P(name) + 1) * sizeof(Z_USTRVAL_P(name)[0]));
+	}
+#endif
+	memcpy(buffer, Z_STRVAL_P(&XG(var_namespace_soft)), (Z_STRLEN_P(&XG(var_namespace_soft)) + 1));
+	buffer += (Z_STRLEN_P(&XG(var_namespace_soft)) + 1);
+	memcpy(buffer, Z_STRVAL_P(name), (Z_STRLEN_P(name) + 1));
+}
+/* }}} */
+typedef struct xc_namebuffer_t_ { /* {{{ */
+	ALLOCA_FLAG(useheap);
+	void *buffer;
+	int alloca_size;
+	int len;
+} xc_namebuffer_t;
+/* }}} */
+
+#define VAR_BUFFER_FLAGS(name) \
+	xc_namebuffer_t name##_buffer;
+
+#define VAR_BUFFER_INIT(name) \
+	name##_buffer.len = xc_var_buffer_prepare(name TSRMLS_CC); \
+	name##_buffer.alloca_size = xc_var_buffer_alloca_size(name TSRMLS_CC); \
+	name##_buffer.buffer = name##_buffer.alloca_size \
+		? do_alloca(name##_buffer.alloca_size, name##_buffer.useheap) \
+		: UNISW(Z_STRVAL_P(name), Z_TYPE(name) == IS_UNICODE ? Z_USTRVAL_P(name) : Z_STRVAL_P(name)); \
+	if (name##_buffer.alloca_size) xc_var_buffer_init(name##_buffer.buffer, name TSRMLS_CC);
+
+#define VAR_BUFFER_FREE(name) \
+	if (name##_buffer.alloca_size) { \
+		free_alloca(name##_buffer.buffer, name##_buffer.useheap); \
+	}
+
+static inline int xc_var_has_prefix(xc_entry_t *entry, zval *prefix TSRMLS_DC) /* {{{ */
+{
+	zend_bool result = 0;
+	VAR_BUFFER_FLAGS(prefix);
+
+	if (UNISW(IS_STRING, entry->name_type) != prefix->type) {
+		return 0;
+	}
+	VAR_BUFFER_INIT(prefix);
+
+#ifdef IS_UNICODE
+	if (Z_TYPE(prefix) == IS_UNICODE) {
+		result = entry->name.ustr.len >= prefix_buffer.len
+		 && memcmp(entry->name.ustr.val, prefix_buffer.buffer, prefix_buffer.len * sizeof(Z_USTRVAL_P(prefix)[0])) == 0;
+		goto finish;
+	}
+#endif
+
+	result = entry->name.str.len >= prefix_buffer.len
+	 && memcmp(entry->name.str.val, prefix_buffer.buffer, prefix_buffer.len) == 0;
+	goto finish;
+
+finish:
+	VAR_BUFFER_FREE(prefix);
+	return result;
+}
+/* }}} */
+
 /* module helper function */
 static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
@@ -2502,5 +2781,5 @@
 		}
 	}
-
+	xc_var_namespace_init(TSRMLS_C);
 #ifdef ZEND_ENGINE_2
 	zend_llist_init(&XG(gc_op_arrays), sizeof(xc_gc_op_array_t), xc_gc_op_array, 0);
@@ -2520,4 +2799,5 @@
 	xc_gc_expires_var(TSRMLS_C);
 	xc_gc_deletes(TSRMLS_C);
+	xc_var_namespace_destroy(TSRMLS_C);
 #ifdef ZEND_ENGINE_2
 	zend_llist_destroy(&XG(gc_op_arrays));
@@ -2566,5 +2846,5 @@
 		zend_bailout();
 	}
-	ht = HASH_OF((*server));
+	ht = Z_ARRVAL_P((*server));
 
 	if (zend_hash_find(ht, "PHP_AUTH_USER", sizeof("PHP_AUTH_USER"), (void **) &user) == FAILURE) {
@@ -2799,4 +3079,12 @@
 }
 /* }}} */
+/* {{{ proto mixed xcache_admin_namespace()
+   Break out of namespace limitation */
+PHP_FUNCTION(xcache_admin_namespace)
+{
+	xcache_admin_auth_check(TSRMLS_C);
+	xc_var_namespace_break(TSRMLS_C);
+}
+/* }}} */
 
 #define VAR_CACHE_NOT_INITIALIZED() do { \
@@ -2804,25 +3092,13 @@
 } while (0)
 
-static int xc_entry_var_init_key(xc_entry_var_t *entry_var, xc_entry_hash_t *entry_hash, zval *name TSRMLS_DC) /* {{{ */
+static int xc_entry_var_init_key(xc_entry_var_t *entry_var, xc_entry_hash_t *entry_hash, xc_namebuffer_t *name_buffer TSRMLS_DC) /* {{{ */
 {
 	xc_hash_value_t hv;
-
-	switch (name->type) {
-#ifdef IS_UNICODE
-		case IS_UNICODE:
-		case IS_STRING:
-#endif
-		default:
-#ifdef IS_UNICODE
-			convert_to_unicode(name);
-#else
-			convert_to_string(name);
-#endif
-	}
 
 #ifdef IS_UNICODE
 	entry_var->name_type = name->type;
 #endif
-	entry_var->entry.name = name->value;
+	entry_var->entry.name.str.val = name_buffer->buffer;
+	entry_var->entry.name.str.len = name_buffer->len;
 
 	hv = xc_entry_hash_var((xc_entry_t *) entry_var TSRMLS_CC);
@@ -2834,4 +3110,29 @@
 }
 /* }}} */
+/* {{{ proto mixed xcache_set_namespace(string namespace)
+   Switch to user defined namespace */
+PHP_FUNCTION(xcache_set_namespace)
+{
+	zval *namespace;
+
+	if (!xc_var_caches) {
+		VAR_CACHE_NOT_INITIALIZED();
+		RETURN_NULL();
+	}
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &namespace) == FAILURE) {
+		return;
+	}
+
+	if (Z_TYPE_P(namespace) == IS_STRING) {
+		xc_var_namespace_set_stringl(Z_STRVAL_P(namespace), Z_STRLEN_P(namespace) TSRMLS_CC);
+	}
+#ifdef IS_UNICODE
+	else if (Z_TYPE_P(namespace) == IS_UNICODE) {
+		xc_var_namespace_set_unicodel(Z_USTRVAL_P(namespace), Z_USTRLEN_P(namespace) TSRMLS_CC);
+	}
+#endif
+}
+/* }}} */
 /* {{{ proto mixed xcache_get(string name)
    Get cached data by specified name */
@@ -2842,4 +3143,5 @@
 	xc_entry_var_t entry_var, *stored_entry_var;
 	zval *name;
+	VAR_BUFFER_FLAGS(name);
 
 	if (!xc_var_caches) {
@@ -2851,8 +3153,10 @@
 		return;
 	}
-	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
 	cache = &xc_var_caches[entry_hash.cacheid];
 
 	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
 		RETURN_NULL();
 	}
@@ -2869,4 +3173,5 @@
 		}
 	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
 }
 /* }}} */
@@ -2880,4 +3185,5 @@
 	zval *name;
 	zval *value;
+	VAR_BUFFER_FLAGS(name);
 
 	if (!xc_var_caches) {
@@ -2901,8 +3207,10 @@
 	}
 
-	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
 	cache = &xc_var_caches[entry_hash.cacheid];
 
 	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
 		RETURN_NULL();
 	}
@@ -2916,4 +3224,5 @@
 		RETVAL_BOOL(xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC) != NULL ? 1 : 0);
 	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
 }
 /* }}} */
@@ -2926,4 +3235,5 @@
 	xc_entry_var_t entry_var, *stored_entry_var;
 	zval *name;
+	VAR_BUFFER_FLAGS(name);
 
 	if (!xc_var_caches) {
@@ -2935,8 +3245,10 @@
 		return;
 	}
-	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
 	cache = &xc_var_caches[entry_hash.cacheid];
 
 	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
 		RETURN_FALSE;
 	}
@@ -2954,4 +3266,5 @@
 
 	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
 }
 /* }}} */
@@ -2964,4 +3277,5 @@
 	xc_entry_var_t entry_var, *stored_entry_var;
 	zval *name;
+	VAR_BUFFER_FLAGS(name);
 
 	if (!xc_var_caches) {
@@ -2973,8 +3287,10 @@
 		return;
 	}
-	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
 	cache = &xc_var_caches[entry_hash.cacheid];
 
 	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
 		RETURN_FALSE;
 	}
@@ -2990,4 +3306,5 @@
 		}
 	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
 }
 /* }}} */
@@ -3020,5 +3337,5 @@
 				for (entry = cache->cached->entries[entryslotid]; entry; entry = next) {
 					next = entry->next;
-					if (xc_entry_has_prefix_unlocked(XC_TYPE_VAR, entry, prefix)) {
+					if (xc_var_has_prefix(entry, prefix TSRMLS_CC)) {
 						xc_entry_remove_unlocked(XC_TYPE_VAR, cache, entryslotid, entry TSRMLS_CC);
 					}
@@ -3038,4 +3355,5 @@
 	long value = 0;
 	zval oldzval;
+	VAR_BUFFER_FLAGS(name);
 
 	if (!xc_var_caches) {
@@ -3054,8 +3372,10 @@
 	}
 
-	xc_entry_var_init_key(&entry_var, &entry_hash, name TSRMLS_CC);
+	VAR_BUFFER_INIT(name);
+	xc_entry_var_init_key(&entry_var, &entry_hash, &name_buffer TSRMLS_CC);
 	cache = &xc_var_caches[entry_hash.cacheid];
 
 	if (cache->cached->disabled) {
+		VAR_BUFFER_FREE(name);
 		RETURN_NULL();
 	}
@@ -3103,4 +3423,5 @@
 		xc_entry_var_store_unlocked(cache, entry_hash.entryslotid, &entry_var TSRMLS_CC);
 	} LEAVE_LOCK(cache);
+	VAR_BUFFER_FREE(name);
 }
 /* }}} */
@@ -3126,4 +3447,6 @@
 	PHP_FE(xcache_clear_cache,       NULL)
 	PHP_FE(xcache_enable_cache,      NULL)
+	PHP_FE(xcache_admin_namespace,   NULL)
+	PHP_FE(xcache_set_namespace,     NULL)
 	PHP_FE(xcache_get,               NULL)
 	PHP_FE(xcache_set,               NULL)
@@ -3221,4 +3544,6 @@
 	PHP_INI_ENTRY1     ("xcache.var_allocator",    "bestfit", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_var_allocator)
 	STD_PHP_INI_ENTRY  ("xcache.var_ttl",                "0", PHP_INI_ALL,    OnUpdateLong, var_ttl,   zend_xcache_globals, xcache_globals)
+	PHP_INI_ENTRY1     ("xcache.var_namespace_mode",     "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_var_namespace_mode)
+	PHP_INI_ENTRY1     ("xcache.var_namespace",           "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_var_namespace)
 PHP_INI_END()
 /* }}} */
@@ -3394,4 +3719,8 @@
 		pefree(xc_var_allocator, 1);
 		xc_var_allocator = NULL;
+	}
+	if (xc_var_namespace) {
+		pefree(xc_var_namespace, 1);
+		xc_var_namespace = NULL;
 	}
 
Index: /trunk/xcache_globals.h
===================================================================
--- /trunk/xcache_globals.h	(revision 1118)
+++ /trunk/xcache_globals.h	(revision 1146)
@@ -21,4 +21,10 @@
 	time_t request_time;
 	long   var_ttl;
+#ifdef IS_UNCODE
+	zval uvar_namespace_hard;
+	zval uvar_namespace_soft;
+#endif
+	zval var_namespace_hard;
+	zval var_namespace_soft;
 
 	zend_llist gc_op_arrays;
Index: /trunk/NEWS
===================================================================
--- /trunk/NEWS	(revision 1139)
+++ /trunk/NEWS	(revision 1146)
@@ -6,4 +6,5 @@
  * uses extension= to load XCache. loading via zend_extension= is unsupported
  * updates XCache admin page
+ * namespace support
  * professional helpers
    * adds an diagnosis module to give advise @ htdocs
Index: /trunk/htdocs/cacher/index.php
===================================================================
--- /trunk/htdocs/cacher/index.php	(revision 1145)
+++ /trunk/htdocs/cacher/index.php	(revision 1146)
@@ -258,4 +258,5 @@
 
 xcache_count(XC_TYPE_PHP); // trigger auth
+xcache_admin_namespace();
 
 $doTypes = array(
Index: /trunk/htdocs/cacher/edit.tpl.php
===================================================================
--- /trunk/htdocs/cacher/edit.tpl.php	(revision 1086)
+++ /trunk/htdocs/cacher/edit.tpl.php	(revision 1146)
@@ -1,5 +1,5 @@
 <?php include "../common/header.tpl.php"; ?>
 <?php
-$h_name = htmlspecialchars($name);
+$h_name = htmlspecialchars(var_export($name, true));
 $h_value = htmlspecialchars($value);
 ?>
Index: /trunk/htdocs/cacher/sub/entrylist.tpl.php
===================================================================
--- /trunk/htdocs/cacher/sub/entrylist.tpl.php	(revision 1143)
+++ /trunk/htdocs/cacher/sub/entrylist.tpl.php	(revision 1146)
@@ -61,5 +61,4 @@
 
 TR;
-	$name     = htmlspecialchars($entry['name']);
 	$hits     = number_format($entry['hits']);
 	$size     = size($entry['size']);
@@ -81,5 +80,6 @@
 
 	if ($isphp) {
-		$namelink = $name;
+		$hname = htmlspecialchars($entry['name']);
+		$namelink = $hname;
 		echo <<<ENTRY
 			<td>{$entry['cache_name']} {$i}</td>
@@ -88,10 +88,15 @@
 	}
 	else {
+		$name = $entry['name'];
+		if (!empty($config['enable_eval'])) {
+			$name = var_export($name, true);
+		}
+		$uname = urlencode($name);
+		$hname = htmlspecialchars(str_replace("\0", "\\0", $entry['name']));
 		echo <<<ENTRY
-			<td><label><input type="checkbox" name="remove[]" value="{$name}"/>{$entry['cache_name']} {$i}</label></td>
+			<td><label><input type="checkbox" name="remove[]" value="{$hname}"/>{$entry['cache_name']} {$i}</label></td>
 
 ENTRY;
-		$uname = urlencode($entry['name']);
-		$namelink = "<a href=\"edit.php?name=$uname\">$name</a>";
+		$namelink = "<a href=\"edit.php?name=$uname\">$hname</a>";
 	}
 
Index: /trunk/htdocs/cacher/edit.php
===================================================================
--- /trunk/htdocs/cacher/edit.php	(revision 1144)
+++ /trunk/htdocs/cacher/edit.php	(revision 1146)
@@ -7,7 +7,12 @@
 }
 
-$name = $_GET['name'];
 // trigger auth
 $vcnt = xcache_count(XC_TYPE_VAR);
+xcache_admin_namespace();
+
+$name = $_GET['name'];
+if (!empty($config['enable_eval'])) {
+	eval('$name = ' . $name . ';');
+}
 
 if ($_SERVER['REQUEST_METHOD'] == 'POST') {
Index: /trunk/ChangeLog
===================================================================
--- /trunk/ChangeLog	(revision 1140)
+++ /trunk/ChangeLog	(revision 1146)
@@ -4,4 +4,6 @@
  * chg: proto array xcache_clear_cache(int type, [ int id = -1 ]). -1 means all cache splits
  * new: proto array xcache_enable_cache(int type, [ int id = -1, [ bool enable = true ] ])
+ * new: proto array xcache_admin_namespace()
+ * new: proto array xcache_set_namespace(string namespace)
 
 Ini Settings Changes
@@ -18,4 +20,5 @@
  * closes #174: updates api to support "clear all cache"
  * closes #198: support for caching protocol url
+ * closes #287: namespace support
  * fixes #39: ini_set never work for xcache.coverager setting. use API instead
  * code refactor
