1#define IN_LIBEXSLT
2#include "libexslt/libexslt.h"
3
4#if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
5#include <win32config.h>
6#else
7#include "config.h"
8#endif
9
10#include <libxml/tree.h>
11#include <libxml/xpath.h>
12#include <libxml/xpathInternals.h>
13
14#include <libxslt/xsltutils.h>
15#include <libxslt/xsltInternals.h>
16#include <libxslt/extensions.h>
17
18#include "exslt.h"
19
20/**
21 * exsltSetsDifferenceFunction:
22 * @ctxt:  an XPath parser context
23 * @nargs:  the number of arguments
24 *
25 * Wraps #xmlXPathDifference for use by the XPath processor
26 */
27static void
28exsltSetsDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs) {
29    xmlNodeSetPtr arg1, arg2, ret;
30
31    if (nargs != 2) {
32	xmlXPathSetArityError(ctxt);
33	return;
34    }
35
36    arg2 = xmlXPathPopNodeSet(ctxt);
37    if (xmlXPathCheckError(ctxt)) {
38	xmlXPathSetTypeError(ctxt);
39	return;
40    }
41
42    arg1 = xmlXPathPopNodeSet(ctxt);
43    if (xmlXPathCheckError(ctxt)) {
44	xmlXPathSetTypeError(ctxt);
45	return;
46    }
47
48    ret = xmlXPathDifference(arg1, arg2);
49
50    if (ret != arg1)
51	xmlXPathFreeNodeSet(arg1);
52    xmlXPathFreeNodeSet(arg2);
53
54    xmlXPathReturnNodeSet(ctxt, ret);
55}
56
57/**
58 * exsltSetsIntersectionFunction:
59 * @ctxt:  an XPath parser context
60 * @nargs:  the number of arguments
61 *
62 * Wraps #xmlXPathIntersection for use by the XPath processor
63 */
64static void
65exsltSetsIntersectionFunction (xmlXPathParserContextPtr ctxt, int nargs) {
66    xmlNodeSetPtr arg1, arg2, ret;
67
68    if (nargs != 2) {
69	xmlXPathSetArityError(ctxt);
70	return;
71    }
72
73    arg2 = xmlXPathPopNodeSet(ctxt);
74    if (xmlXPathCheckError(ctxt)) {
75	xmlXPathSetTypeError(ctxt);
76	return;
77    }
78
79    arg1 = xmlXPathPopNodeSet(ctxt);
80    if (xmlXPathCheckError(ctxt)) {
81	xmlXPathSetTypeError(ctxt);
82	return;
83    }
84
85    ret = xmlXPathIntersection(arg1, arg2);
86
87    xmlXPathFreeNodeSet(arg1);
88    xmlXPathFreeNodeSet(arg2);
89
90    xmlXPathReturnNodeSet(ctxt, ret);
91}
92
93/**
94 * exsltSetsDistinctFunction:
95 * @ctxt:  an XPath parser context
96 * @nargs:  the number of arguments
97 *
98 * Wraps #xmlXPathDistinct for use by the XPath processor
99 */
100static void
101exsltSetsDistinctFunction (xmlXPathParserContextPtr ctxt, int nargs) {
102    xmlXPathObjectPtr obj;
103    xmlNodeSetPtr ns, ret;
104    int boolval = 0;
105    void *user = NULL;
106
107    if (nargs != 1) {
108	xmlXPathSetArityError(ctxt);
109	return;
110    }
111
112    if (ctxt->value != NULL) {
113        boolval = ctxt->value->boolval;
114	user = ctxt->value->user;
115	ctxt->value->boolval = 0;
116	ctxt->value->user = NULL;
117    }
118    ns = xmlXPathPopNodeSet(ctxt);
119    if (xmlXPathCheckError(ctxt))
120	return;
121
122    /* !!! must be sorted !!! */
123    ret = xmlXPathDistinctSorted(ns);
124
125	if (ret != ns)
126		xmlXPathFreeNodeSet(ns);
127
128    obj = xmlXPathWrapNodeSet(ret);
129    obj->user = user;
130    obj->boolval = boolval;
131    valuePush((ctxt), obj);
132}
133
134/**
135 * exsltSetsHasSameNodesFunction:
136 * @ctxt:  an XPath parser context
137 * @nargs:  the number of arguments
138 *
139 * Wraps #xmlXPathHasSameNodes for use by the XPath processor
140 */
141static void
142exsltSetsHasSameNodesFunction (xmlXPathParserContextPtr ctxt,
143			      int nargs) {
144    xmlNodeSetPtr arg1, arg2;
145    int ret;
146
147    if (nargs != 2) {
148	xmlXPathSetArityError(ctxt);
149	return;
150    }
151
152    arg2 = xmlXPathPopNodeSet(ctxt);
153    if (xmlXPathCheckError(ctxt)) {
154	xmlXPathSetTypeError(ctxt);
155	return;
156    }
157
158    arg1 = xmlXPathPopNodeSet(ctxt);
159    if (xmlXPathCheckError(ctxt)) {
160	xmlXPathSetTypeError(ctxt);
161	return;
162    }
163
164    ret = xmlXPathHasSameNodes(arg1, arg2);
165
166    xmlXPathFreeNodeSet(arg1);
167    xmlXPathFreeNodeSet(arg2);
168
169    xmlXPathReturnBoolean(ctxt, ret);
170}
171
172/**
173 * exsltSetsLeadingFunction:
174 * @ctxt:  an XPath parser context
175 * @nargs:  the number of arguments
176 *
177 * Wraps #xmlXPathLeading for use by the XPath processor
178 */
179static void
180exsltSetsLeadingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
181    xmlNodeSetPtr arg1, arg2, ret;
182
183    if (nargs != 2) {
184	xmlXPathSetArityError(ctxt);
185	return;
186    }
187
188    arg2 = xmlXPathPopNodeSet(ctxt);
189    if (xmlXPathCheckError(ctxt)) {
190	xmlXPathSetTypeError(ctxt);
191	return;
192    }
193
194    arg1 = xmlXPathPopNodeSet(ctxt);
195    if (xmlXPathCheckError(ctxt)) {
196	xmlXPathSetTypeError(ctxt);
197	return;
198    }
199
200    /*  If the second node set is empty, then the first node set is
201     * returned.
202     */
203    if (xmlXPathNodeSetIsEmpty(arg2)) {
204	xmlXPathReturnNodeSet(ctxt, arg1);
205
206	xmlXPathFreeNodeSet(arg2);
207
208	return;
209    }
210    /* !!! must be sorted */
211    ret = xmlXPathNodeLeadingSorted(arg1, xmlXPathNodeSetItem(arg2, 0));
212
213    xmlXPathFreeNodeSet(arg1);
214    xmlXPathFreeNodeSet(arg2);
215
216    xmlXPathReturnNodeSet(ctxt, ret);
217}
218
219/**
220 * exsltSetsTrailingFunction:
221 * @ctxt:  an XPath parser context
222 * @nargs:  the number of arguments
223 *
224 * Wraps #xmlXPathTrailing for use by the XPath processor
225 */
226static void
227exsltSetsTrailingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
228    xmlNodeSetPtr arg1, arg2, ret;
229
230    if (nargs != 2) {
231	xmlXPathSetArityError(ctxt);
232	return;
233    }
234
235    arg2 = xmlXPathPopNodeSet(ctxt);
236    if (xmlXPathCheckError(ctxt)) {
237	xmlXPathSetTypeError(ctxt);
238	return;
239    }
240
241    arg1 = xmlXPathPopNodeSet(ctxt);
242    if (xmlXPathCheckError(ctxt)) {
243	xmlXPathSetTypeError(ctxt);
244	return;
245    }
246
247    /*  If the second node set is empty, then the first node set is
248     * returned.
249     */
250    if (xmlXPathNodeSetIsEmpty(arg2)) {
251	xmlXPathReturnNodeSet(ctxt, arg1);
252
253	xmlXPathFreeNodeSet(arg2);
254
255	return;
256    }
257    /* !!! mist be sorted */
258    ret = xmlXPathNodeTrailingSorted(arg1, xmlXPathNodeSetItem(arg2, 0));
259
260    xmlXPathFreeNodeSet(arg1);
261    xmlXPathFreeNodeSet(arg2);
262
263    xmlXPathReturnNodeSet(ctxt, ret);
264}
265
266/**
267 * exsltSetsRegister:
268 *
269 * Registers the EXSLT - Sets module
270 */
271
272void
273exsltSetsRegister (void) {
274    xsltRegisterExtModuleFunction ((const xmlChar *) "difference",
275				   EXSLT_SETS_NAMESPACE,
276				   exsltSetsDifferenceFunction);
277    xsltRegisterExtModuleFunction ((const xmlChar *) "intersection",
278				   EXSLT_SETS_NAMESPACE,
279				   exsltSetsIntersectionFunction);
280    xsltRegisterExtModuleFunction ((const xmlChar *) "distinct",
281				   EXSLT_SETS_NAMESPACE,
282				   exsltSetsDistinctFunction);
283    xsltRegisterExtModuleFunction ((const xmlChar *) "has-same-node",
284				   EXSLT_SETS_NAMESPACE,
285				   exsltSetsHasSameNodesFunction);
286    xsltRegisterExtModuleFunction ((const xmlChar *) "leading",
287				   EXSLT_SETS_NAMESPACE,
288				   exsltSetsLeadingFunction);
289    xsltRegisterExtModuleFunction ((const xmlChar *) "trailing",
290				   EXSLT_SETS_NAMESPACE,
291				   exsltSetsTrailingFunction);
292}
293
294/**
295 * exsltSetsXpathCtxtRegister:
296 *
297 * Registers the EXSLT - Sets module for use outside XSLT
298 */
299int
300exsltSetsXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
301{
302    if (ctxt
303        && prefix
304        && !xmlXPathRegisterNs(ctxt,
305                               prefix,
306                               (const xmlChar *) EXSLT_SETS_NAMESPACE)
307        && !xmlXPathRegisterFuncNS(ctxt,
308                                   (const xmlChar *) "difference",
309                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
310                                   exsltSetsDifferenceFunction)
311        && !xmlXPathRegisterFuncNS(ctxt,
312                                   (const xmlChar *) "intersection",
313                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
314                                   exsltSetsIntersectionFunction)
315        && !xmlXPathRegisterFuncNS(ctxt,
316                                   (const xmlChar *) "distinct",
317                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
318                                   exsltSetsDistinctFunction)
319        && !xmlXPathRegisterFuncNS(ctxt,
320                                   (const xmlChar *) "has-same-node",
321                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
322                                   exsltSetsHasSameNodesFunction)
323        && !xmlXPathRegisterFuncNS(ctxt,
324                                   (const xmlChar *) "leading",
325                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
326                                   exsltSetsLeadingFunction)
327        && !xmlXPathRegisterFuncNS(ctxt,
328                                   (const xmlChar *) "trailing",
329                                   (const xmlChar *) EXSLT_SETS_NAMESPACE,
330                                   exsltSetsTrailingFunction)) {
331        return 0;
332    }
333    return -1;
334}
335