+#define M_PRI 5
+#define M_SEC 2
+#define M_ANY 1
+#define M_NOT 0
+#define M_ALL ~0
+static inline unsigned php_http_negotiate_match(const char *param_str, size_t param_len, const char *supported_str, size_t supported_len, const char *sep_str, size_t sep_len)
+{
+ unsigned match = M_NOT;
+
+ if (param_len == supported_len && !strncasecmp(param_str, supported_str, param_len)) {
+ /* that was easy */
+ match = M_ALL;
+ } else if (sep_str && sep_len) {
+ const char *param_sec = php_http_locate_str(param_str, param_len, sep_str, sep_len);
+ size_t param_pri_len = param_sec ? param_sec - param_str : param_len;
+ const char *supported_sec = php_http_locate_str(supported_str, supported_len, sep_str, sep_len);
+ size_t supported_pri_len = supported_sec ? supported_sec - supported_str : supported_len;
+ size_t cmp_len = MIN(param_pri_len, supported_pri_len);
+
+ if (((*param_str == '*') || (*supported_str == '*'))
+ || ((param_pri_len == supported_pri_len) && !strncasecmp(param_str, supported_str, param_pri_len))
+ || ((!param_sec || !supported_sec) && cmp_len && !strncasecmp(param_str, supported_str, cmp_len))
+ ) {
+ match += M_PRI;
+ }
+
+ if (param_sec && supported_sec && !strcasecmp(param_sec, supported_sec)) {
+ match += M_SEC;
+ }
+
+ if ((param_sec && *(param_sec + sep_len) == '*')
+ || (supported_sec && *(supported_sec + sep_len) == '*')
+ || ((*param_str == '*') || (*supported_str == '*'))
+ ) {
+ match += M_ANY;
+ }
+ }
+#if 0
+ fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match);
+#endif
+ return match;
+}
+static int php_http_negotiate_reduce(zval *p, int num_args, va_list args, zend_hash_key *hash_key)