2 #include "libexslt/libexslt.h"
4 #if defined(WIN32) && !defined (__CYGWIN__)
5 #include <win32config.h>
10 #include <libxml/tree.h>
11 #include <libxml/xpath.h>
12 #include <libxml/xpathInternals.h>
13 #include <libxml/parser.h>
14 #include <libxml/encoding.h>
16 #include <libxslt/xsltconfig.h>
17 #include <libxslt/xsltutils.h>
18 #include <libxslt/xsltInternals.h>
19 #include <libxslt/extensions.h>
24 * exsltStrTokenizeFunction:
25 * @ctxt: an XPath parser context
26 * @nargs: the number of arguments
28 * Splits up a string and returns a node set of token elements, each
29 * containing one token from the string.
32 exsltStrTokenizeFunction (xmlXPathParserContextPtr ctxt, int nargs) {
33 xmlChar *str, *delimiters, *cur;
34 const xmlChar *token, *delimiter;
37 xmlXPathObjectPtr ret;
39 if ((nargs < 1) || (nargs > 2)) {
40 xmlXPathSetArityError (ctxt);
45 delimiters = xmlXPathPopString (ctxt);
46 if (xmlXPathCheckError(ctxt))
49 delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
51 if (delimiters == NULL)
54 str = xmlXPathPopString (ctxt);
55 if (xmlXPathCheckError(ctxt) || (str == NULL)) {
60 doc = xsltXPathGetTransformContext(ctxt)->document->doc;
61 ret = xmlXPathNewNodeSet (NULL);
65 * This is a hack: token elements are added as children of a
66 * fake element node. This is necessary to free them up
67 * correctly when freeing the node-set.
69 ret->user = (void *) xmlNewDocNode (doc, NULL,
70 (const xmlChar *) "fake", NULL);
71 if (ret->user == NULL)
75 for (cur = str, token = str; *cur != 0; cur++) {
76 for (delimiter = delimiters; *delimiter != 0; delimiter++) {
77 if (*cur == *delimiter) {
79 /* discard empty tokens */
83 node = xmlNewDocNode (doc, NULL,
84 (const xmlChar *) "token", token);
88 xmlAddChild ((xmlNodePtr) ret->user, node);
89 xmlXPathNodeSetAdd (ret->nodesetval, node);
94 node = xmlNewDocNode (doc, NULL, (const xmlChar *) "token", token);
95 xmlAddChild ((xmlNodePtr) ret->user, node);
96 xmlXPathNodeSetAdd (ret->nodesetval, node);
98 valuePush (ctxt, ret);
99 ret = NULL; /* hack to prevent freeing ret later */
103 xmlXPathFreeObject (ret);
106 if (delimiters != NULL)
111 * exsltStrPaddingFunction:
112 * @ctxt: an XPath parser context
113 * @nargs: the number of arguments
115 * Creates a padding string of a certain length.
118 exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
119 int number, str_len = 0;
120 xmlChar *str = NULL, *ret = NULL, *tmp;
122 if ((nargs < 1) && (nargs > 2)) {
123 xmlXPathSetArityError(ctxt);
128 str = xmlXPathPopString(ctxt);
129 str_len = xmlUTF8Strlen(str);
132 if (str != NULL) xmlFree(str);
133 str = xmlStrdup((const xmlChar *) " ");
137 number = (int) xmlXPathPopNumber(ctxt);
140 xmlXPathReturnEmptyString(ctxt);
145 while (number >= str_len) {
146 ret = xmlStrncat(ret, str, str_len);
149 tmp = xmlUTF8Strndup (str, number);
150 ret = xmlStrcat(ret, tmp);
154 xmlXPathReturnString(ctxt, ret);
161 * exsltStrAlignFunction:
162 * @ctxt: an XPath parser context
163 * @nargs: the number of arguments
165 * Aligns a string within another string.
168 exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
169 xmlChar *str, *padding, *alignment, *ret;
170 int str_l, padding_l;
172 if ((nargs < 2) || (nargs > 3)) {
173 xmlXPathSetArityError(ctxt);
178 alignment = xmlXPathPopString(ctxt);
182 padding = xmlXPathPopString(ctxt);
183 str = xmlXPathPopString(ctxt);
185 str_l = xmlUTF8Strlen (str);
186 padding_l = xmlUTF8Strlen (padding);
188 if (str_l == padding_l) {
189 xmlXPathReturnString (ctxt, str);
195 if (str_l > padding_l) {
196 ret = xmlUTF8Strndup (str, padding_l);
198 if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
199 ret = xmlUTF8Strndup (padding, padding_l - str_l);
200 ret = xmlStrcat (ret, str);
201 } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
202 int left = (padding_l - str_l) / 2;
205 ret = xmlUTF8Strndup (padding, left);
206 ret = xmlStrcat (ret, str);
208 right_start = xmlUTF8Strsize (padding, left + str_l);
209 ret = xmlStrcat (ret, padding + right_start);
213 str_s = xmlStrlen (str);
214 ret = xmlStrdup (str);
215 ret = xmlStrcat (ret, padding + str_s);
219 xmlXPathReturnString (ctxt, ret);
227 * exsltStrConcatFunction:
228 * @ctxt: an XPath parser context
229 * @nargs: the number of arguments
231 * Takes a node set and returns the concatenation of the string values
232 * of the nodes in that node set. If the node set is empty, it
233 * returns an empty string.
236 exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
237 xmlXPathObjectPtr obj;
242 xmlXPathSetArityError(ctxt);
246 if (!xmlXPathStackIsNodeSet(ctxt)) {
247 xmlXPathSetTypeError(ctxt);
251 obj = valuePop (ctxt);
253 if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
254 xmlXPathReturnEmptyString(ctxt);
258 for (i = 0; i < obj->nodesetval->nodeNr; i++) {
260 tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
262 ret = xmlStrcat (ret, tmp);
267 xmlXPathFreeObject (obj);
269 xmlXPathReturnString(ctxt, ret);
275 * Registers the EXSLT - Strings module
279 exsltStrRegister (void) {
280 xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
281 EXSLT_STRINGS_NAMESPACE,
282 exsltStrTokenizeFunction);
283 xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
284 EXSLT_STRINGS_NAMESPACE,
285 exsltStrPaddingFunction);
286 xsltRegisterExtModuleFunction ((const xmlChar *) "align",
287 EXSLT_STRINGS_NAMESPACE,
288 exsltStrAlignFunction);
289 xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
290 EXSLT_STRINGS_NAMESPACE,
291 exsltStrConcatFunction);