+/* {{{ HashTable *http_negotiate_q(const char *, HashTable *, negotiate_func_t) */
+PHP_HTTP_API HashTable *_http_negotiate_q(const char *header, HashTable *supported, negotiate_func_t neg TSRMLS_DC)
+{
+ zval *accept;
+ HashTable *result = NULL;
+
+#if HTTP_DBG_NEG
+ fprintf(stderr, "Reading header %s: ", header);
+#endif
+ HTTP_GSC(accept, header, NULL);
+#if HTTP_DBG_NEG
+ fprintf(stderr, "%s\n", Z_STRVAL_P(accept));
+#endif
+
+ if (Z_STRLEN_P(accept)) {
+ zval ex_arr, ex_del;
+
+ INIT_PZVAL(&ex_del);
+ INIT_PZVAL(&ex_arr);
+ ZVAL_STRINGL(&ex_del, ",", 1, 0);
+ array_init(&ex_arr);
+
+ php_explode(&ex_del, accept, &ex_arr, -1);
+
+ if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) {
+ int i = 0;
+ zval **entry, array;
+
+ INIT_PZVAL(&array);
+ array_init(&array);
+
+ FOREACH_HASH_VAL(Z_ARRVAL(ex_arr), entry) {
+ double quality;
+ char *selected, *identifier;
+ const char *separator;
+
+#if HTTP_DBG_NEG
+ fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry));
+#endif
+
+ if (separator = strchr(Z_STRVAL_PP(entry), ';')) {
+ const char *ptr = separator;
+
+ while (*++ptr && !isdigit(*ptr));
+
+ quality = atof(ptr);
+ identifier = estrndup(Z_STRVAL_PP(entry), separator - Z_STRVAL_PP(entry));
+ } else {
+ quality = 1000.0 - i++;
+ identifier = estrndup(Z_STRVAL_PP(entry), Z_STRLEN_PP(entry));
+ }
+
+ if (selected = neg(identifier, &quality, supported TSRMLS_CC)) {
+ /* don't overwrite previously set with higher quality */
+ if (!zend_hash_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) {
+ add_assoc_double(&array, selected, quality);
+ }
+ }
+
+ efree(identifier);
+ }
+
+ result = Z_ARRVAL(array);
+ zend_hash_sort(result, zend_qsort, http_sort_q, 0 TSRMLS_CC);
+ }
+
+ zval_dtor(&ex_arr);
+ }
+
+ return result;