build and file maintenance
[m6w6/ext-http] / php_http_negotiate.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http.h"
14
15 #include <ext/standard/php_string.h>
16
17 #ifndef PHP_HTTP_DBG_NEG
18 # define PHP_HTTP_DBG_NEG 0
19 #endif
20
21 char *php_http_negotiate_language_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
22 {
23 zval **value;
24 HashPosition pos;
25 const char *dash_test;
26
27 FOREACH_HASH_VAL(pos, supported, value) {
28 #if PHP_HTTP_DBG_NEG
29 fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
30 #endif
31 if (!strcasecmp(Z_STRVAL_PP(value), test)) {
32 return Z_STRVAL_PP(value);
33 }
34 }
35
36 /* no distinct match found, so try primaries */
37 if ((dash_test = strchr(test, '-'))) {
38 FOREACH_HASH_VAL(pos, supported, value) {
39 int len = dash_test - test;
40 #if PHP_HTTP_DBG_NEG
41 fprintf(stderr, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value), test, len);
42 #endif
43 if ( (!strncasecmp(Z_STRVAL_PP(value), test, len)) &&
44 ( (Z_STRVAL_PP(value)[len] == '\0') ||
45 (Z_STRVAL_PP(value)[len] == '-'))) {
46 *quality *= .9;
47 return Z_STRVAL_PP(value);
48 }
49 }
50 }
51
52 return NULL;
53 }
54
55
56 char *php_http_negotiate_default_func(const char *test, double *quality, HashTable *supported TSRMLS_DC)
57 {
58 zval **value;
59 HashPosition pos;
60 (void) quality;
61
62 FOREACH_HASH_VAL(pos, supported, value) {
63 #if PHP_HTTP_DBG_NEG
64 fprintf(stderr, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value), test);
65 #endif
66 if (!strcasecmp(Z_STRVAL_PP(value), test)) {
67 return Z_STRVAL_PP(value);
68 }
69 }
70
71 return NULL;
72 }
73
74
75 static int php_http_negotiate_sort(const void *a, const void *b TSRMLS_DC)
76 {
77 zval result, *first, *second;
78
79 first = *((zval **) (*((Bucket **) a))->pData);
80 second= *((zval **) (*((Bucket **) b))->pData);
81
82 if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
83 return 0;
84 }
85 return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
86 }
87
88
89 PHP_HTTP_API HashTable *php_http_negotiate(const char *value, HashTable *supported, php_http_negotiate_func_t neg TSRMLS_DC)
90 {
91 HashTable *result = NULL;
92
93 if (*value) {
94 zval ex_arr, ex_del, ex_val;
95
96 INIT_PZVAL(&ex_del);
97 INIT_PZVAL(&ex_arr);
98 INIT_PZVAL(&ex_val);
99 ZVAL_STRINGL(&ex_del, ",", 1, 0);
100 ZVAL_STRING(&ex_val, value, 1);
101 array_init(&ex_arr);
102
103 php_explode(&ex_del, &ex_val, &ex_arr, INT_MAX);
104
105 if (zend_hash_num_elements(Z_ARRVAL(ex_arr)) > 0) {
106 int i = 0;
107 HashPosition pos;
108 zval **entry, array;
109
110 INIT_PZVAL(&array);
111 array_init(&array);
112
113 if (!neg) {
114 neg = php_http_negotiate_default_func;
115 }
116
117 FOREACH_HASH_VAL(pos, Z_ARRVAL(ex_arr), entry) {
118 int ident_len;
119 double quality;
120 char *selected, *identifier, *freeme;
121 const char *separator;
122
123 #if PHP_HTTP_DBG_NEG
124 fprintf(stderr, "Checking %s\n", Z_STRVAL_PP(entry));
125 #endif
126
127 if ((separator = strchr(Z_STRVAL_PP(entry), ';'))) {
128 const char *ptr = separator;
129
130 while (*++ptr && !PHP_HTTP_IS_CTYPE(digit, *ptr) && '.' != *ptr);
131
132 quality = zend_strtod(ptr, NULL);
133 identifier = estrndup(Z_STRVAL_PP(entry), ident_len = separator - Z_STRVAL_PP(entry));
134 } else {
135 quality = 1000.0 - i++;
136 identifier = estrndup(Z_STRVAL_PP(entry), ident_len = Z_STRLEN_PP(entry));
137 }
138 freeme = identifier;
139
140 while (PHP_HTTP_IS_CTYPE(space, *identifier)) {
141 ++identifier;
142 --ident_len;
143 }
144 while (ident_len && PHP_HTTP_IS_CTYPE(space, identifier[ident_len - 1])) {
145 identifier[--ident_len] = '\0';
146 }
147
148 if ((selected = neg(identifier, &quality, supported TSRMLS_CC))) {
149 /* don't overwrite previously set with higher quality */
150 if (!zend_symtable_exists(Z_ARRVAL(array), selected, strlen(selected) + 1)) {
151 add_assoc_double(&array, selected, quality);
152 }
153 }
154
155 efree(freeme);
156 }
157
158 result = Z_ARRVAL(array);
159 zend_hash_sort(result, zend_qsort, php_http_negotiate_sort, 0 TSRMLS_CC);
160 }
161
162 zval_dtor(&ex_arr);
163 zval_dtor(&ex_val);
164 }
165
166 return result;
167 }
168
169
170
171 /*
172 * Local variables:
173 * tab-width: 4
174 * c-basic-offset: 4
175 * End:
176 * vim600: noet sw=4 ts=4 fdm=marker
177 * vim<600: noet sw=4 ts=4
178 */
179
180