Coverage Report

Created: 2025-07-11 06:12

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