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