409266351e624acea31faf95ea8d4dc76506e3d1
[platform/upstream/libxslt.git] / libexslt / strings.c
1 #include "libexslt/libexslt.h"
2
3 #if defined(WIN32) && !defined (__CYGWIN__)
4 #include <win32config.h>
5 #else
6 #include "config.h"
7 #endif
8
9 #include <libxml/tree.h>
10 #include <libxml/xpath.h>
11 #include <libxml/xpathInternals.h>
12 #include <libxml/parser.h>
13 #include <libxml/encoding.h>
14
15 #include <libxslt/xsltconfig.h>
16 #include <libxslt/xsltutils.h>
17 #include <libxslt/xsltInternals.h>
18 #include <libxslt/extensions.h>
19
20 #include "exslt.h"
21
22 /**
23  * exsltStrTokenizeFunction:
24  * @ctxt: an XPath parser context
25  * @nargs: the number of arguments
26  *
27  * Splits up a string and returns a node set of token elements, each
28  * containing one token from the string. 
29  */
30 static void
31 exsltStrTokenizeFunction (xmlXPathParserContextPtr ctxt, int nargs) {
32     xmlChar *str, *delimiters, *cur;
33     const xmlChar *token, *delimiter;
34     xmlNodePtr node;
35     xmlDocPtr doc;
36     xmlXPathObjectPtr ret;
37
38     if ((nargs < 1) || (nargs > 2)) {
39         xmlXPathSetArityError (ctxt);
40         return;
41     }
42
43     if (nargs == 2) {
44         delimiters = xmlXPathPopString (ctxt);
45         if (xmlXPathCheckError(ctxt))
46             return;
47     } else {
48         delimiters = xmlStrdup((const xmlChar *) "\t\r\n ");
49     }
50     if (delimiters == NULL)
51         return;
52
53     str = xmlXPathPopString (ctxt);
54     if (xmlXPathCheckError(ctxt) || (str == NULL)) {
55         xmlFree (delimiters);
56         return;
57     }
58
59     doc = xsltXPathGetTransformContext(ctxt)->document->doc;
60     ret = xmlXPathNewNodeSet (NULL);
61     if (ret != NULL) {
62         ret->boolval = 1;
63         /*
64          * This is a hack: token elements are added as children of a
65          * fake element node. This is necessary to free them up
66          * correctly when freeing the node-set.
67          */
68         ret->user = (void *) xmlNewDocNode (doc, NULL,
69                                 (const xmlChar *) "fake", NULL);
70         if (ret->user == NULL)
71             goto error;
72     }
73
74     for (cur = str, token = str; *cur != 0; cur++) {
75         for (delimiter = delimiters; *delimiter != 0; delimiter++) {
76             if (*cur == *delimiter) {
77                 if (cur == token) {
78                     /* discard empty tokens */
79                     break;
80                 }
81                 *cur = 0;
82                 node = xmlNewDocNode (doc, NULL,
83                                       (const xmlChar *) "token", token);
84                 *cur = *delimiter;
85                 token = cur + 1;
86
87                 xmlAddChild ((xmlNodePtr) ret->user, node);
88                 xmlXPathNodeSetAdd (ret->nodesetval, node);
89                 break;
90             }
91         }
92     }
93     node = xmlNewDocNode (doc, NULL, (const xmlChar *) "token", token);
94     xmlAddChild ((xmlNodePtr) ret->user, node);
95     xmlXPathNodeSetAdd (ret->nodesetval, node);
96
97     valuePush (ctxt, ret);
98     ret = NULL;         /* hack to prevent freeing ret later */
99
100 error:
101     if (ret != NULL)
102         xmlXPathFreeObject (ret);
103     if (str != NULL)
104         xmlFree(str);
105     if (delimiters != NULL)
106         xmlFree(delimiters);
107 }
108
109 /**
110  * exsltStrPaddingFunction:
111  * @ctxt: an XPath parser context
112  * @nargs: the number of arguments
113  *
114  * Creates a padding string of a certain length.
115  */
116 static void
117 exsltStrPaddingFunction (xmlXPathParserContextPtr ctxt, int nargs) {
118     int number, str_len = 0;
119     xmlChar *str = NULL, *ret = NULL, *tmp;
120
121     if ((nargs < 1) && (nargs > 2)) {
122         xmlXPathSetArityError(ctxt);
123         return;
124     }
125
126     if (nargs == 2) {
127         str = xmlXPathPopString(ctxt);
128         str_len = xmlUTF8Strlen(str);
129     }
130     if (str_len == 0) {
131         if (str != NULL) xmlFree(str);
132         str = xmlStrdup((const xmlChar *) " ");
133         str_len = 1;
134     }
135
136     number = (int) xmlXPathPopNumber(ctxt);
137
138     if (number <= 0) {
139         xmlXPathReturnEmptyString(ctxt);
140         xmlFree(str);
141         return;
142     }
143
144     while (number >= str_len) {
145         ret = xmlStrncat(ret, str, str_len);
146         number -= str_len;
147     }
148     tmp = xmlUTF8Strndup (str, number);
149     ret = xmlStrcat(ret, tmp);
150     if (tmp != NULL)
151         xmlFree (tmp);
152
153     xmlXPathReturnString(ctxt, ret);
154
155     if (str != NULL)
156         xmlFree(str);
157 }
158
159 /**
160  * exsltStrAlignFunction:
161  * @ctxt: an XPath parser context
162  * @nargs: the number of arguments
163  *
164  * Aligns a string within another string.
165  */
166 static void
167 exsltStrAlignFunction (xmlXPathParserContextPtr ctxt, int nargs) {
168     xmlChar *str, *padding, *alignment, *ret;
169     int str_l, padding_l;
170
171     if ((nargs < 2) || (nargs > 3)) {
172         xmlXPathSetArityError(ctxt);
173         return;
174     }
175
176     if (nargs == 3)
177         alignment = xmlXPathPopString(ctxt);
178     else
179         alignment = NULL;
180
181     padding = xmlXPathPopString(ctxt);
182     str = xmlXPathPopString(ctxt);
183
184     str_l = xmlUTF8Strlen (str);
185     padding_l = xmlUTF8Strlen (padding);
186
187     if (str_l == padding_l) {
188         xmlXPathReturnString (ctxt, str);
189         xmlFree(padding);
190         xmlFree(alignment);
191         return;
192     }
193
194     if (str_l > padding_l) {
195         ret = xmlUTF8Strndup (str, padding_l);
196     } else {
197         if (xmlStrEqual(alignment, (const xmlChar *) "right")) {
198             ret = xmlUTF8Strndup (padding, padding_l - str_l);
199             ret = xmlStrcat (ret, str);
200         } else if (xmlStrEqual(alignment, (const xmlChar *) "center")) {
201             int left = (padding_l - str_l) / 2;
202             int right_start;
203
204             ret = xmlUTF8Strndup (padding, left);
205             ret = xmlStrcat (ret, str);
206
207             right_start = xmlUTF8Strsize (padding, left + str_l);
208             ret = xmlStrcat (ret, padding + right_start);
209         } else {
210             int str_s;
211
212             str_s = xmlStrlen (str);
213             ret = xmlStrdup (str);
214             ret = xmlStrcat (ret, padding + str_s);
215         }
216     }
217
218     xmlXPathReturnString (ctxt, ret);
219
220     xmlFree(str);
221     xmlFree(padding);
222     xmlFree(alignment);
223 }
224
225 /**
226  * exsltStrConcatFunction:
227  * @ctxt: an XPath parser context
228  * @nargs: the number of arguments
229  *
230  * Takes a node set and returns the concatenation of the string values
231  * of the nodes in that node set.  If the node set is empty, it
232  * returns an empty string.
233  */
234 static void
235 exsltStrConcatFunction (xmlXPathParserContextPtr ctxt, int nargs) {
236     xmlXPathObjectPtr obj;
237     xmlChar *ret = NULL;
238     int i;
239
240     if (nargs  != 1) {
241         xmlXPathSetArityError(ctxt);
242         return;
243     }
244
245     if (!xmlXPathStackIsNodeSet(ctxt)) {
246         xmlXPathSetTypeError(ctxt);
247         return;
248     }
249
250     obj = valuePop (ctxt);
251
252     if (xmlXPathNodeSetIsEmpty(obj->nodesetval)) {
253         xmlXPathReturnEmptyString(ctxt);
254         return;
255     }
256
257     for (i = 0; i < obj->nodesetval->nodeNr; i++) {
258         xmlChar *tmp;
259         tmp = xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
260
261         ret = xmlStrcat (ret, tmp);
262
263         xmlFree(tmp);
264     }
265
266     xmlXPathFreeObject (obj);
267
268     xmlXPathReturnString(ctxt, ret);
269 }
270
271 /**
272  * exsltStrRegister:
273  *
274  * Registers the EXSLT - Strings module
275  */
276
277 void
278 exsltStrRegister (void) {
279     xsltRegisterExtModuleFunction ((const xmlChar *) "tokenize",
280                                    EXSLT_STRINGS_NAMESPACE,
281                                    exsltStrTokenizeFunction);
282     xsltRegisterExtModuleFunction ((const xmlChar *) "padding",
283                                    EXSLT_STRINGS_NAMESPACE,
284                                    exsltStrPaddingFunction);
285     xsltRegisterExtModuleFunction ((const xmlChar *) "align",
286                                    EXSLT_STRINGS_NAMESPACE,
287                                    exsltStrAlignFunction);
288     xsltRegisterExtModuleFunction ((const xmlChar *) "concat",
289                                    EXSLT_STRINGS_NAMESPACE,
290                                    exsltStrConcatFunction);
291 }