root/tags/2007080101/fastxsl.c

Revision 33, 42.9 kB (checked in by jesus, 7 years ago)

refactor, no function change

Line 
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 4                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2003 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 2.02 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available at through the world-wide-web at                           |
10   | http://www.php.net/license/2_02.txt.                                 |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Sterling Hughes <sterling@php.net>                           |
16   |         George Schlossnagle <george@omniti.com>                      |
17   +----------------------------------------------------------------------+
18
19   $Id: fastxsl.c,v 1.1.1.1 2004/02/17 23:31:44 sterling Exp $
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <libxml/xmlmemory.h>
27 #include <libxml/debugXML.h>
28 #include <libxml/HTMLtree.h>
29 #include <libxml/xmlIO.h>
30 #include <libxml/xinclude.h>
31 #include <libxml/catalog.h>
32 #include <libxml/xpathInternals.h>
33 #include <libxml/xpath.h>
34 #include <libxslt/xslt.h>
35 #include <libxslt/xsltInternals.h>
36 #include <libxslt/transform.h>
37 #include <libxslt/xsltutils.h>
38 #include <libxslt/extensions.h>
39 #include <libxslt/functions.h>
40
41 #ifdef FASTXSL_MM
42 #include <mm.h>
43 #endif
44 #include <sys/types.h>
45 #include <sys/file.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48
49 #include "fl_hash.h"
50 #include "php.h"
51 #include "php_ini.h"
52 #include "ext/standard/info.h"
53 #include "php_fastxsl.h"
54
55 ZEND_DECLARE_MODULE_GLOBALS(fastxsl)
56
57 static int inshm = 0;
58
59 static int le_fastxsl_stylesheet;
60 #define le_fastxsl_stylesheet_name "FastXSL Stylesheet"
61 static int le_fastxsl_document;
62 #define le_fastxsl_document_name "FastXSL Document"
63
64 #define FASTXSL_PRM_ALLOC 1
65 #define FASTXSL_SHARED_ALLOC 2
66
67 void fastxsl_errorfunc(void *ctx, const char *msg, ...);
68 static void ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC);
69 static void _SS_Wrapper_Dtor(php_ss_wrapper *wrapper);
70 static void _XD_Wrapper_Dtor(php_xd_wrapper *wrapper);
71
72 static php_ss_wrapper *
73 SS_Wrapper_Alloc(int shared TSRMLS_DC)
74 {
75         php_ss_wrapper *wrapper;
76
77         if (shared) {
78 #ifdef FASTXSL_MM
79                 if (shared == FASTXSL_SHARED_ALLOC) {
80                         wrapper = (php_ss_wrapper *) mm_calloc(FASTXSL_G(cache)->mm, 1, sizeof(php_ss_wrapper));
81                 } else {
82                         wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
83                 }
84                 if(!wrapper) {
85                         mm_display_info(FASTXSL_G(cache)->mm);
86                 }
87                 wrapper->persistant = 1;
88 #else
89                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
90                 wrapper->persistant = 1;
91 #endif
92         } else {
93                 wrapper = (php_ss_wrapper *) calloc(1, sizeof(php_ss_wrapper));
94         }
95
96         return wrapper;
97 }
98
99 static php_xd_wrapper *
100 XD_Wrapper_Alloc(void)
101 {
102         php_xd_wrapper *wrapper;
103
104         wrapper = (php_xd_wrapper *) calloc(1, sizeof(php_xd_wrapper));
105         return wrapper;
106 }
107
108 static xmlFreeFunc    free_ptr;
109 static xmlMallocFunc  malloc_ptr;
110 static xmlMallocFunc  mallocatomic_ptr;
111 static xmlReallocFunc realloc_ptr;
112 static xmlStrdupFunc  strdup_ptr;
113
114 #ifdef FASTXSL_MM
115 void
116 ShmCache_Free(void *ptr)
117 {
118         TSRMLS_FETCH();
119 #ifdef DEBUGMM
120         if(!inshm) assert(0);
121 #endif
122         FASTXSL_G(tmp_allocated_size) -= mm_sizeof(FASTXSL_G(cache)->mm, ptr);
123         mm_free(FASTXSL_G(cache)->mm, ptr);
124 }
125
126 void *
127 ShmCache_Malloc(size_t size)
128 {
129         void *ptr;
130         TSRMLS_FETCH();
131 #ifdef DEBUGMM
132         if(!inshm) assert(0);
133 #endif
134         ptr = mm_malloc(FASTXSL_G(cache)->mm, size);
135         if (!ptr) {
136                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
137                                            "in function %s() cannot allocate %ld bytes (%ld available, %ld allocated)",
138                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
139                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
140                 return NULL;
141         }
142
143         FASTXSL_G(tmp_allocated_size) += size;
144         return ptr;
145 }
146
147 void *
148 ShmCache_Calloc(size_t nmemb, size_t size)
149 {
150         void *ptr;
151
152 #ifdef DEBUGMM
153         if(!inshm) assert(0);
154 #endif
155         ptr = ShmCache_Malloc(nmemb * size);
156         memset(ptr, 0, nmemb * size);
157         return ptr;
158 }
159
160 void *
161 ShmCache_Realloc(void *ptr, size_t size)
162 {
163         void *newptr;
164         long  oldsize;
165         TSRMLS_FETCH();
166
167 #ifdef DEBUGMM
168         if(!inshm) assert(0);
169 #endif
170         oldsize = mm_sizeof(FASTXSL_G(cache)->mm, ptr);
171         newptr = mm_realloc(FASTXSL_G(cache)->mm, ptr, size);
172         if (!newptr) {
173                 TSRMLS_FETCH();
174                 php_error(E_ERROR, "Ran out of Shared memory to allocate data for FastXSL cache, "
175                                            "in function %s() cannot allocate %d bytes (%d available, %d allocated)",
176                                                    get_active_function_name(TSRMLS_C), size, mm_available(FASTXSL_G(cache)->mm),
177                                                    mm_maxsize() - mm_available(FASTXSL_G(cache)->mm));
178                 return NULL;
179         }
180         FASTXSL_G(tmp_allocated_size) += (size - oldsize);
181         return newptr;
182 }
183
184 char *
185 ShmCache_Strdup(const char *string)
186 {
187         char *newstring;
188         int   string_length;
189
190 #ifdef DEBUGMM
191         if(!inshm) assert(0);
192 #endif
193         string_length = strlen(string);
194         newstring = ShmCache_Malloc(string_length + 1);
195         memcpy(newstring, string, string_length);
196         newstring[string_length] = 0;
197
198         return newstring;
199 }
200 #endif
201
202 static void
203 Php_Free(void *ptr)
204 {
205         efree(ptr);
206 }
207
208 static void *
209 Php_Malloc(size_t size)
210 {
211         return emalloc(size);
212 }
213
214 static void *
215 Php_Realloc(void *ptr, size_t size)
216 {
217         return erealloc(ptr, size);
218 }
219
220 static char *
221 Php_Strdup(const char *string)
222 {
223         return estrdup(string);
224 }
225
226 #ifdef FASTXSL_MM
227 static void
228 ShmCache_UseAllocationFunctions(void)
229 {
230         xmlMemSetup(ShmCache_Free, ShmCache_Malloc, ShmCache_Realloc, ShmCache_Strdup);
231 }
232 #endif
233
234 static void
235 Php_UseAllocationFunctions(void)
236 {
237         xmlMemSetup(Php_Free, Php_Malloc, Php_Realloc, Php_Strdup);
238 }
239
240 static void
241 Xml_UseAllocationFunctions(void)
242 {
243         xmlMemSetup(free_ptr, malloc_ptr,  realloc_ptr, strdup);
244 }
245
246 #ifdef FASTXSL_MM
247 static php_ss_wrapper *
248 ShmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
249 {
250         php_ss_wrapper *wrapper;
251         int rv;
252         wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
253
254         ShmCache_UseAllocationFunctions();
255         wrapper->alloc_type = FASTXSL_SHMALLOC;
256         FASTXSL_G(tmp_allocated_size) = 0;
257         zend_set_timeout(0);
258         wrapper->data.ss = xsltParseStylesheetFile((unsigned char *)filename);
259         wrapper->data_type = FASTXSL_STYLESHEET;
260         Xml_UseAllocationFunctions();
261         if (!wrapper->data.ss) {
262                 _SS_Wrapper_Dtor(wrapper);
263                 return NULL;
264         }
265         wrapper->mtime = mtime;
266         wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
267         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
268         rv = fl_hash_add(FASTXSL_G(cache)->table, filename, filename_len, wrapper);
269         mm_unlock(FASTXSL_G(cache)->mm);
270         if(rv == 0) {
271                 /* we failed */
272                 php_ss_wrapper *fallback;
273                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
274                 fallback = fl_hash_find(FASTXSL_G(cache)->table, filename,
275                                         filename_len);
276                 mm_unlock(FASTXSL_G(cache)->mm);
277                 if(fallback && fallback->data_type == FASTXSL_STYLESHEET) {
278                         ShmCache_Stylesheet_Free(wrapper);
279                         wrapper = fallback;
280                 } else {
281                 }
282         } else {
283         }
284
285         return wrapper;
286 }
287
288 static void
289 ShmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
290 {
291         if (wrapper->data_type == FASTXSL_STYLESHEET) {
292                 if (wrapper->data.ss) {
293                         //xmlCleanupParserr();
294                         ShmCache_UseAllocationFunctions();
295 inshm = 1;
296                         xsltFreeStylesheet(wrapper->data.ss);
297 inshm = 0;
298                         //xmlCleanupParserr();
299                         Xml_UseAllocationFunctions();
300                 }
301                 mm_free(FASTXSL_G(cache)->mm, wrapper);
302         }
303 }
304
305 static void
306 ShmCache_XPathObject_Free(php_ss_wrapper *wrapper TSRMLS_DC)
307 {
308         if (wrapper->data_type == FASTXSL_XPATHOBJ) {
309                 if (wrapper->data.ss) {
310                         //xmlCleanupParserr();
311                         ShmCache_UseAllocationFunctions();
312 inshm = 1;
313                         xmlXPathFreeObject(wrapper->data.op);
314 inshm = 0;
315                         //xmlCleanupParserr();
316                         Xml_UseAllocationFunctions();
317                 }
318                 mm_free(FASTXSL_G(cache)->mm, wrapper);
319         }
320 }
321
322 static void
323 ShmCache_Document_Delete(char *filename, size_t filename_len)
324 {
325         php_ss_wrapper *wrapper;
326
327         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
328         wrapper = fl_hash_find(FASTXSL_G(cache)->table, filename, filename_len);
329         mm_unlock(FASTXSL_G(cache)->mm);
330         if (wrapper) {
331                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
332                 fl_hash_delete(FASTXSL_G(cache)->table, filename, filename_len);
333                 mm_unlock(FASTXSL_G(cache)->mm);
334                 switch(wrapper->data_type) {
335                         case FASTXSL_STYLESHEET:
336                                 ShmCache_Stylesheet_Free(wrapper);
337                                 break;
338                         case FASTXSL_XPATHOBJ:
339                                 ShmCache_XPathObject_Free(wrapper);
340                                 break;
341                         default:
342                                 break;
343                 }
344         }
345 }
346 #endif
347
348 #ifdef F_SETLK
349 #define ACQUIRE(lockfd) do { \
350         struct flock lock; \
351         lock.l_start = 0; \
352         lock.l_whence = SEEK_SET; \
353         lock.l_len = 0; \
354         lock.l_type = F_WRLCK; \
355         fcntl((lockfd), F_SETLKW, &lock); \
356 } while(0)
357 #define RELEASE(lockfd) do { \
358         struct flock lock; \
359         lock.l_start = 0; \
360         lock.l_whence = SEEK_SET; \
361         lock.l_len = 0; \
362         lock.l_type = F_UNLCK; \
363         fcntl((lockfd), F_SETLK, &lock); \
364 } while(0)
365 #else
366 #define ACQUIRE(lockfd) flock((lockfd), LOCK_EX)
367 #define RELEASE(lockfd) flock((lockfd), LOCK_UN)
368 #endif
369
370 #ifdef FASTXSL_MM
371 /* {{{ proto void fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
372    Emulate xsltDocumentFunction but leverage the MM shared cache for speed. */
373 static void
374 fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
375 {
376         xmlXPathFunction func;
377         xmlXPathObjectPtr idoc, obj;
378         int lockfd;
379         int popped = 0;
380         char *ss_filename;
381         int ss_filename_len;
382         struct stat sb;
383         php_ss_wrapper *ss_wrapper;
384
385         xmlXPathStringFunction(ctxt, 1);
386         if (ctxt->value->type != XPATH_STRING) {
387                 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
388                                                  "document() : invalid arg expecting a string\n");
389                 goto error;
390         }
391         obj = ctxt->value;
392         ss_filename_len = strlen((char *)obj->stringval);
393         ss_filename = alloca(ss_filename_len + 1);
394         strcpy(ss_filename, (char *)obj->stringval);
395
396         lockfd = open(ss_filename, O_RDONLY);
397         if(lockfd < 0) {
398                 /* FIXME non-existent file */
399                 goto error;
400         }
401         if (!FASTXSL_G(nostat)) {
402                 if (fstat(lockfd, &sb) == -1) {
403                         ShmCache_UseAllocationFunctions();
404 inshm = 1;
405                         ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
406 inshm = 0;
407                         Xml_UseAllocationFunctions();
408                         close(lockfd);
409                         goto error;
410                 }
411         } else {
412                 sb.st_mtime = 0;
413         }
414         ACQUIRE(lockfd);
415         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
416         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
417         mm_unlock(FASTXSL_G(cache)->mm);
418         if (!ss_wrapper) {
419                 ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
420                 if(ss_wrapper) {
421                         int rv;
422                         ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
423                         ss_wrapper->data_type = FASTXSL_STYLESHEET;
424                         func = xmlXPathFunctionLookup(ctxt->context, (const xmlChar *)"document");
425                         ShmCache_UseAllocationFunctions();
426 inshm = 1;
427                         FASTXSL_G(tmp_allocated_size) = 0;
428                         func(ctxt, nargs);
429                         ss_wrapper->data.op = ctxt->value;
430                         ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
431                         valuePop(ctxt);
432                         popped = 1;
433 inshm = 0;
434                         Xml_UseAllocationFunctions();
435                         ss_wrapper->mtime = sb.st_mtime;
436                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
437                         rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
438                         mm_unlock(FASTXSL_G(cache)->mm);
439                         if(rv == 0) {
440                                 /* we failed */
441                                 php_ss_wrapper *fallback;
442                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
443                                 fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
444                                 mm_unlock(FASTXSL_G(cache)->mm);
445                                 if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
446                                         ShmCache_UseAllocationFunctions();
447 inshm = 1;
448                                         ShmCache_XPathObject_Free(ss_wrapper);
449 inshm = 0;
450                                         Xml_UseAllocationFunctions();
451                                         ss_wrapper = fallback;
452                                 } else {
453                                 }
454                         } else {
455                         }
456                 }
457                 if (!ss_wrapper) {
458                         RELEASE(lockfd);
459                         close(lockfd);
460                         //xmlCleanupParserr();
461                         Xml_UseAllocationFunctions();
462                         goto error;
463                 }
464         } else {
465                 if (!FASTXSL_G(nostat)) {
466                         if (ss_wrapper->mtime != sb.st_mtime) {
467                                 ShmCache_UseAllocationFunctions();
468 inshm = 1;
469                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
470 inshm = 0;
471                                 Xml_UseAllocationFunctions();
472                                 ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
473                                 if(ss_wrapper) {
474                                         int rv;
475                                         ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
476                                         ss_wrapper->data_type = FASTXSL_STYLESHEET;
477                                         func = xmlXPathFunctionLookup(ctxt->context, (const xmlChar *)"document");
478                                         ShmCache_UseAllocationFunctions();
479 inshm = 1;
480                                         FASTXSL_G(tmp_allocated_size) = 0;
481                                         func(ctxt, nargs);
482                                         ss_wrapper->data.op = ctxt->value;
483                                         valuePop(ctxt);
484                                         popped = 1;
485 inshm = 0;
486                                         Xml_UseAllocationFunctions();
487                                         ss_wrapper->mtime = sb.st_mtime;
488                                         ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
489                                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
490                                         rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
491                                         mm_unlock(FASTXSL_G(cache)->mm);
492                                         if(rv == 0) {
493                                                 /* we failed */
494                                                 php_ss_wrapper *fallback;
495                                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
496                                                 fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
497                                                 mm_unlock(FASTXSL_G(cache)->mm);
498                                                 if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
499                                                         ShmCache_UseAllocationFunctions();
500 inshm = 1;
501                                                         ShmCache_XPathObject_Free(ss_wrapper);
502 inshm = 0;
503                                                         Xml_UseAllocationFunctions();
504                                                         ss_wrapper = fallback;
505                                                 } else {
506                                                 }
507                                         } else {
508                                         }
509                                 }
510                                 //xmlCleanupParserr();
511                                 if (!ss_wrapper) {
512                                         RELEASE(lockfd);
513                                         close(lockfd);
514                                         goto error;
515                                 }
516                         }
517                 }
518         }
519         ss_wrapper->hits++;
520         //xmlCleanupParserr();
521         Xml_UseAllocationFunctions();
522         RELEASE(lockfd);
523         close(lockfd);
524
525         if(!popped) valuePop(ctxt);
526         valuePush(ctxt, xmlXPathObjectCopy(ss_wrapper->data.op));
527         return;
528 error:
529         ctxt->error = XPATH_INVALID_TYPE;
530         return;
531 }
532 /* }}} */
533 #endif
534
535 static php_ss_wrapper *
536 PrmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
537 {
538         php_ss_wrapper *wrapper;
539
540         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(FASTXSL_PRM_ALLOC TSRMLS_CC);
541         wrapper->alloc_type = FASTXSL_PRMALLOC;
542
543         wrapper->data.ss = xsltParseStylesheetFile((xmlChar *)filename);
544         wrapper->data_type = FASTXSL_STYLESHEET;
545         if (!wrapper->data.ss) {
546                 return NULL;
547         }
548         wrapper->mtime = mtime;
549        
550         if(fl_hash_add(FASTXSL_G(cache)->prmtable, filename, filename_len, wrapper) == 0) {
551                 /* we failed, not much we can do here, and no race */
552         }
553
554         return wrapper;
555 }
556
557 static void
558 PrmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
559 {
560         if (wrapper->data_type == FASTXSL_STYLESHEET) {
561                 if (wrapper->data.ss) {
562                         xsltFreeStylesheet(wrapper->data.ss);
563                 }
564                 free(wrapper);
565         }
566 }
567
568 static void
569 PrmCache_XPathObject_Free(php_ss_wrapper *wrapper TSRMLS_DC)
570 {
571         if (wrapper->data_type == FASTXSL_XPATHOBJ) {
572                 if (wrapper->data.op) {
573                         xmlXPathFreeObject(wrapper->data.op);
574                 }
575                 free(wrapper);
576         }
577 }
578
579 static void
580 PrmCache_Document_Delete(char *filename, size_t filename_len TSRMLS_DC)
581 {
582         php_ss_wrapper *wrapper;
583
584         wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, filename, filename_len);
585         if (wrapper) {
586                 fl_hash_delete(FASTXSL_G(cache)->prmtable, filename, filename_len);
587                 switch(wrapper->data_type) {
588                         case FASTXSL_STYLESHEET:
589                                 PrmCache_Stylesheet_Free(wrapper TSRMLS_CC);
590                                 break;
591                         case FASTXSL_XPATHOBJ:
592                                 PrmCache_XPathObject_Free(wrapper TSRMLS_CC);
593                                 break;
594                         default:
595                                 break;
596                 }
597         }
598 }
599
600 /* {{{ proto array fastxsl_prmcache_getstatistics(void)
601    Get an array of statistics regarding the fastxsl documents in the process resident memory cache */
602 PHP_FUNCTION(fastxsl_prmcache_getstatistics)
603 {
604         php_ss_wrapper *wrapper;       
605
606         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
607                 return;
608         }
609
610 }
611 /* }}} */
612
613 /* {{{ proto array fastxsl_shmcache_getstatistics(void)
614    Get an array of statistics regarding the documents in the shared memory cache */
615 #ifdef FASTXSL_MM
616 PHP_FUNCTION(fastxsl_shmcache_getstatistics)
617 {
618         php_ss_wrapper *ss_wrapper;
619         FL_Bucket      *bucket;
620         zval           *files_array;
621         zval           *info_array;
622         int             i;
623         long            allocated_bytes = 0;
624        
625         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
626                 return;
627         }
628
629         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
630        
631         array_init(return_value);
632
633         MAKE_STD_ZVAL(files_array);
634         array_init(files_array);
635
636         for (i = 0; i < FL_HASH_SIZE; i++) {
637                 for (bucket = FASTXSL_G(cache)->table->buckets[i]; bucket != NULL; bucket = bucket->next) {
638                         ss_wrapper = (php_ss_wrapper *) bucket->data;
639
640                         MAKE_STD_ZVAL(info_array);
641                         array_init(info_array);
642
643                         add_assoc_long(info_array, "allocated", ss_wrapper->allocsize);
644                         add_assoc_long(info_array, "hits", ss_wrapper->hits);
645                         add_assoc_long(info_array, "mtime", ss_wrapper->mtime);
646
647                         add_assoc_zval(files_array, bucket->key, info_array);
648
649                         allocated_bytes += ss_wrapper->allocsize;
650                 }
651         }
652         add_assoc_zval(return_value, "files", files_array);
653
654         add_assoc_long(return_value, "apparent_allocated", allocated_bytes);
655         add_assoc_long(return_value, "allocated",
656           (FASTXSL_G(memalloc)?FASTXSL_G(memalloc):mm_maxsize()) - mm_available(FASTXSL_G(cache)->mm));
657         add_assoc_long(return_value, "shm_size", (long) FASTXSL_G(memalloc)?FASTXSL_G(memalloc):mm_maxsize());
658         mm_unlock(FASTXSL_G(cache)->mm);
659 }
660
661 #endif
662 /* }}} */
663
664 /* {{{ proto array fastxsl_version(void)
665    Returns the version number */
666 PHP_FUNCTION(fastxsl_version)
667 {
668         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
669                 return;
670         }
671         RETURN_STRING(PHP_FASTXSL_VERSION, 1);
672 }
673
674 /* }}} */
675
676 /* {{{ proto resource fastxsl_stylesheet_parsefile(string filename)
677    Parse a stylesheet file located at filename. */
678 PHP_FUNCTION(fastxsl_stylesheet_parsefile)
679 {
680         php_ss_wrapper *wrapper;
681         char           *filename;
682         size_t          filename_len;
683
684         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
685                                 &filename_len) == FAILURE) {
686                 return;
687         }
688
689         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
690         wrapper->alloc_type = FASTXSL_PRMALLOC;
691         Xml_UseAllocationFunctions();
692         wrapper->data.ss = xsltParseStylesheetFile((xmlChar*)filename);
693         if (!wrapper->data.ss) {
694                 RETURN_FALSE;
695         }
696
697         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_stylesheet);
698 }
699 /* }}} */
700
701 /* {{{ proto resource fastxsl_xml_parsestring(string text)
702   Parse a string containing an XML document and return a resource pointer to the resulting libxml2 tree */
703 PHP_FUNCTION(fastxsl_xml_parsestring)
704 {
705         php_xd_wrapper *wrapper;
706         char           *text;
707         size_t          text_len;
708
709         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_len) == FAILURE) {
710                 return;
711         }
712
713         wrapper = XD_Wrapper_Alloc();
714         wrapper->alloc_type = FASTXSL_PRMALLOC;
715         Xml_UseAllocationFunctions();
716         wrapper->xd = xmlParseDoc((xmlChar *) text);
717         if (!wrapper->xd) {
718                 _XD_Wrapper_Dtor(wrapper);
719                 RETURN_FALSE;
720         }
721
722         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
723 }
724 /* }}} */
725
726 /* {{{ proto resource fastxsl_xml_parsefile(string filename)
727    Parse an XML file into a FastXSL resource */
728 PHP_FUNCTION(fastxsl_xml_parsefile)
729 {
730         php_xd_wrapper *wrapper;
731         char           *filename;
732         size_t          filename_len;
733
734         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
735                                 &filename_len) == FAILURE) {
736                 return;
737         }
738
739         wrapper = XD_Wrapper_Alloc();
740         wrapper->alloc_type = FASTXSL_PRMALLOC;
741         wrapper->xd = xmlParseFile((const char *) filename);
742         if (!wrapper->xd) {
743                 _XD_Wrapper_Dtor(wrapper);
744                 RETURN_FALSE;
745         }
746
747         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
748 }
749 /* }}} */
750
751 static int
752 ParseTransformParameters(zval *z_parameters, char ***parameters TSRMLS_DC)
753 {
754         zval         **current;
755         HashTable     *h_parameters;
756         HashPosition   pos;
757         char          *key;
758         uint           key_length;
759         unsigned long  ival;
760         int            index = 0;
761
762         h_parameters = Z_ARRVAL_P(z_parameters);
763
764         if (zend_hash_num_elements(h_parameters) == 0) {
765                 *parameters = NULL;
766                 return SUCCESS;
767         }
768        
769         *parameters = calloc(1, (zend_hash_num_elements(h_parameters) * (2 * sizeof(char *))) + 1);
770         if (!*parameters) {
771                 php_error(E_WARNING, "Cannot allocate parameters array to pass to FastXSL");
772                 return FAILURE;
773         }
774        
775         for (zend_hash_internal_pointer_reset_ex(h_parameters, &pos);
776              zend_hash_get_current_data_ex(h_parameters, (void **) &current, &pos) == SUCCESS;
777                  zend_hash_move_forward_ex(h_parameters, &pos)) {
778                 if (zend_hash_get_current_key_ex(h_parameters, &key, &key_length,
779                                         &ival, 0, &pos) == HASH_KEY_IS_LONG) {
780                         efree(*parameters);
781                         *parameters = NULL;
782
783                         php_error(E_WARNING,
784                                         "Parameters array passed to %s() may not contain numeric keys",
785                                         get_active_function_name(TSRMLS_C));
786                         return FAILURE;
787                 }
788
789                 convert_to_string_ex(current);
790
791                 (*parameters)[index++] = key;
792                 (*parameters)[index++] = Z_STRVAL_PP(current);
793         }
794         (*parameters)[index] = NULL;
795
796         return SUCCESS;
797 }
798
799 /* {{{ proto resource fastxsl_shmcache_transform(string filename, resource xmldoc[, array parameters])
800    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
801 #ifdef FASTXSL_MM
802 PHP_FUNCTION(fastxsl_shmcache_transform)
803 {
804         xsltTransformContextPtr ctxt;
805         char            **parameters = NULL;
806         php_xd_wrapper   *xd_wrapper;
807         php_xd_wrapper   *result_wrapper;
808         php_ss_wrapper   *ss_wrapper;
809         char             *ss_filename;
810         size_t            ss_filename_len;
811         zval             *z_xd_wrapper;
812         zval             *z_parameters;
813         struct stat       sb;
814         int lockfd;
815        
816         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
817                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
818                 return;
819         }
820        
821         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
822                         le_fastxsl_document);
823
824         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
825                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
826                         RETURN_FALSE;
827                 }
828         }
829
830         result_wrapper = XD_Wrapper_Alloc();
831         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
832         lockfd = open(ss_filename, O_RDONLY);
833         if(lockfd < 0) {
834                 /* FIXME non-existent file */
835                 RETURN_FALSE;
836         }
837         if (!FASTXSL_G(nostat)) {
838                 if (fstat(lockfd, &sb) == -1) {
839                         ShmCache_UseAllocationFunctions();
840 inshm = 1;
841                         ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
842 inshm = 0;
843                         Xml_UseAllocationFunctions();
844                         _XD_Wrapper_Dtor(result_wrapper);
845                         free(parameters);
846                         close(lockfd);
847                         RETURN_FALSE;
848                 }
849         } else {
850                 sb.st_mtime = 0;
851         }
852         ACQUIRE(lockfd);
853         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
854         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
855         mm_unlock(FASTXSL_G(cache)->mm);
856         if (!ss_wrapper) {
857                 ShmCache_UseAllocationFunctions();
858 inshm = 1;
859                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime);
860 inshm = 0;
861                 if (!ss_wrapper) {
862                         RELEASE(lockfd);
863                         close(lockfd);
864                         //xmlCleanupParserr();
865                         Xml_UseAllocationFunctions();
866                         _XD_Wrapper_Dtor(result_wrapper);
867                         free(parameters);
868                         RETURN_FALSE;
869                 }
870         } else {
871                 if (!FASTXSL_G(nostat)) {
872                         if (ss_wrapper->mtime != sb.st_mtime) {
873                                 //xmlCleanupParserr();
874                                 ShmCache_UseAllocationFunctions();
875 inshm = 1;
876                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
877                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
878 inshm = 0;
879                                 //xmlCleanupParserr();
880                                 Xml_UseAllocationFunctions();
881                                 if (!ss_wrapper) {
882                                         RELEASE(lockfd);
883                                         close(lockfd);
884                                         _XD_Wrapper_Dtor(result_wrapper);
885                                         free(parameters);
886                                         RETURN_FALSE;
887                                 }
888                         }
889                 }
890         }
891         ss_wrapper->hits++;
892         //xmlCleanupParserr();
893         Xml_UseAllocationFunctions();
894         RELEASE(lockfd);
895         close(lockfd);
896
897         ctxt = xsltNewTransformContext(ss_wrapper->data.ss, xd_wrapper->xd);
898 #ifdef FASTXSL_MM
899         xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "cached_document",
900                                 fastxsl_CachedDocumentFunction);
901 #endif
902         result_wrapper->xd = xsltApplyStylesheetUser(ss_wrapper->data.ss, xd_wrapper->xd,
903                         (const char **) parameters, NULL, NULL, ctxt);
904         xsltFreeTransformContext(ctxt);
905        
906         if (parameters)
907                 free(parameters);
908        
909         if (!result_wrapper->xd) {
910                 RETURN_FALSE;
911         }       
912        
913         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
914 }
915 #endif
916 /* }}} */
917
918 /* {{{ proto resource fastxsl_prmcache_transform(string filename, resource xmldoc[, array parameters])
919    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
920 PHP_FUNCTION(fastxsl_prmcache_transform)
921 {
922         char            **parameters = NULL;
923         php_xd_wrapper   *xd_wrapper;
924         php_xd_wrapper   *result_wrapper;
925         php_ss_wrapper   *ss_wrapper;
926         char             *ss_filename;
927         size_t            ss_filename_len;
928         zval             *z_xd_wrapper;
929         zval             *z_parameters;
930         struct stat       sb;
931        
932         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
933                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
934                 return;
935         }
936         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
937                         le_fastxsl_document);
938
939         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
940                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
941                         RETURN_FALSE;
942                 }
943         }
944
945         result_wrapper = XD_Wrapper_Alloc();
946         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
947
948         if (!FASTXSL_G(nostat)) {
949                 if (stat(ss_filename, &sb) == -1) {
950                         PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
951                         _XD_Wrapper_Dtor(result_wrapper);
952                         free(parameters);
953                         RETURN_FALSE;
954                 }
955         } else {
956                 sb.st_mtime = 0;
957         }
958        
959         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
960         if (!ss_wrapper) {
961                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
962                 if (!ss_wrapper) {
963                         _XD_Wrapper_Dtor(result_wrapper);
964                         free(parameters);
965                         RETURN_FALSE;
966                 }
967         } else {
968                 if (!FASTXSL_G(nostat)) {
969                         if (ss_wrapper->mtime != sb.st_mtime) {
970                                 PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
971                                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
972                                 if (!ss_wrapper) {
973                                         _XD_Wrapper_Dtor(result_wrapper);
974                                         free(parameters);
975                                         RETURN_FALSE;
976                                 }
977                         }
978                 }
979         }
980         ss_wrapper->hits++;
981         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
982                         (const char **) parameters);
983         ////xmlCleanupParserr();
984
985         if (parameters)
986                 free(parameters);
987        
988         if (!result_wrapper->xd) {
989                 _XD_Wrapper_Dtor(result_wrapper);
990                 RETURN_FALSE;
991         }       
992        
993         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
994 }
995
996 /* {{{ proto void fastxsl_nocache_transform(resource stylesheet, resource xmldoc[, array parameters])
997    Transform the stylesheet document by the xml document with parameters. */
998 PHP_FUNCTION(fastxsl_nocache_transform)
999 {
1000         char           **parameters = NULL;
1001         php_xd_wrapper  *xd_wrapper;
1002         php_xd_wrapper  *result_wrapper;
1003         php_ss_wrapper  *ss_wrapper;
1004         zval            *z_xd_wrapper;
1005         zval            *z_ss_wrapper;
1006         zval            *z_parameters;
1007
1008         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", &z_ss_wrapper,
1009                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
1010                 return;
1011         }
1012         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1013                         le_fastxsl_stylesheet);
1014         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1015                         le_fastxsl_document);
1016
1017         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1018                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1019                         RETURN_FALSE;
1020                 }
1021         }
1022
1023         result_wrapper = XD_Wrapper_Alloc();
1024         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1025         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1026                         (const char **) parameters);
1027         if (parameters)
1028                 free(parameters);
1029
1030         if (!result_wrapper->xd) {
1031                 _XD_Wrapper_Dtor(result_wrapper);
1032                 RETURN_FALSE;
1033         }       
1034
1035        
1036         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1037 }
1038 /* }}} */
1039
1040 /* {{{ proto void fastxsl_nocache_profile(resource stylesheet, resource xmldoc[, array parameters, string filename])
1041    Profile the stylesheet document by the xml document with parameters and output the results to filename (or stderr, if filename doesn't exist). */
1042 PHP_FUNCTION(fastxsl_nocache_profile)
1043 {
1044         char           **parameters = NULL;
1045         char            *filename = "php://stderr";
1046         php_xd_wrapper  *xd_wrapper;
1047         php_xd_wrapper  *result_wrapper;
1048         php_ss_wrapper  *ss_wrapper;
1049         zval            *z_xd_wrapper;
1050         zval            *z_ss_wrapper;
1051         zval            *z_parameters;
1052         FILE            *dbgprof;
1053         int              filename_len;
1054
1055         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|zs", &z_ss_wrapper,
1056                                 &z_xd_wrapper, &z_parameters, &filename, &filename_len) == FAILURE) {
1057                 return;
1058         }
1059         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1060                         le_fastxsl_stylesheet);
1061         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1062                         le_fastxsl_document);
1063
1064         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1065                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1066                         RETURN_FALSE;
1067                 }
1068         }
1069
1070         if (!strcmp(filename, "php://stdout")) {
1071                 dbgprof = stdout;
1072         } else if (!strcmp(filename, "php://stderr")) {
1073                 dbgprof = stderr;
1074         } else {
1075                 dbgprof = fopen(filename, "w");
1076         }
1077
1078         result_wrapper = XD_Wrapper_Alloc();
1079         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1080
1081         result_wrapper->xd = xsltProfileStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1082                         (const char **) parameters, dbgprof);
1083         if (parameters)
1084                 free(parameters);
1085
1086         fclose(dbgprof);
1087        
1088         if (!result_wrapper->xd) {
1089                 _XD_Wrapper_Dtor(result_wrapper);
1090                 RETURN_FALSE;
1091         }       
1092        
1093         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1094 }
1095 /* }}} */
1096
1097 /* {{{ proto string fastxsl_nocache_tostring(resource stylesheet, resource xmldoc)
1098    Return the contents of an XML stylesheet result as a string */
1099 PHP_FUNCTION(fastxsl_nocache_tostring)
1100 {
1101         zval           *z_xd_wrapper;
1102         zval           *z_ss_wrapper;
1103         php_ss_wrapper *ss_wrapper;
1104         php_xd_wrapper *xd_wrapper;
1105         xmlChar        *result = NULL;
1106         int             length;
1107
1108         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &z_ss_wrapper,
1109                                 &z_xd_wrapper) == FAILURE) {
1110                 return;
1111         }
1112         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL XML Stylesheet",
1113                         le_fastxsl_stylesheet);
1114         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1115                         le_fastxsl_document);
1116
1117         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1118
1119         if (result) {
1120                 RETVAL_STRINGL((char *) result, length, 1);
1121                 xmlFree(result);
1122         } else {
1123                 RETURN_FALSE;
1124         }
1125 }
1126 /* }}} */
1127
1128 /* {{{ proto string fastxsl_shmcache_tostring(string filename, resource xmldoc)
1129    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1130 #ifdef FASTXSL_MM
1131 PHP_FUNCTION(fastxsl_shmcache_tostring)
1132 {
1133         zval           *z_xd_wrapper;
1134         php_ss_wrapper *ss_wrapper;
1135         php_xd_wrapper *xd_wrapper;
1136         xmlChar        *result = NULL;
1137         char           *ss_filename;
1138         size_t          ss_filename_len;
1139         int             length;
1140
1141         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1142                                 &z_xd_wrapper) == FAILURE) {
1143                 return;
1144         }
1145         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1146                         le_fastxsl_document);
1147         Xml_UseAllocationFunctions();
1148         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
1149         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
1150         mm_unlock(FASTXSL_G(cache)->mm);
1151         if (!ss_wrapper) {
1152                 RETURN_FALSE;
1153         }
1154         ss_wrapper->hits++;
1155         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1156         if (result) {
1157                 RETVAL_STRINGL((char *) result, length, 1);
1158                 xmlFree(result);
1159         } else {
1160                 RETVAL_FALSE;
1161         }
1162         Xml_UseAllocationFunctions();
1163 }
1164 #endif
1165 /* }}} */
1166
1167 /* {{{ proto string fastxsl_prmcache_tostring(string filename, resource xmldoc)
1168    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1169 PHP_FUNCTION(fastxsl_prmcache_tostring)
1170 {
1171         zval           *z_xd_wrapper;
1172         php_ss_wrapper *ss_wrapper;
1173         php_xd_wrapper *xd_wrapper;
1174         xmlChar        *result = NULL;
1175         char           *ss_filename;
1176         size_t          ss_filename_len;
1177         int             length;
1178
1179         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1180                                 &z_xd_wrapper) == FAILURE) {
1181                 return;
1182         }
1183         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1184                         le_fastxsl_document);
1185
1186         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
1187         if (!ss_wrapper) {
1188                 RETURN_FALSE;
1189         }
1190         ss_wrapper->hits++;
1191         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1192        
1193         if (result) {
1194                 RETVAL_STRINGL((char *) result, length, 1);
1195                 xmlFree(result);
1196         } else {
1197                 RETURN_FALSE;
1198         }
1199 }
1200 /* }}} */
1201
1202 function_entry fastxsl_functions[] = {
1203         PHP_FE(fastxsl_stylesheet_parsefile,         NULL)
1204         PHP_FE(fastxsl_xml_parsefile,                NULL)
1205         PHP_FE(fastxsl_xml_parsestring,              NULL)
1206 #ifdef FASTXSL_MM
1207         PHP_FE(fastxsl_shmcache_transform,           NULL)
1208         PHP_FE(fastxsl_shmcache_tostring,            NULL)
1209         PHP_FE(fastxsl_shmcache_getstatistics,       NULL)
1210 #endif
1211         PHP_FE(fastxsl_version,                      NULL)
1212         PHP_FE(fastxsl_prmcache_transform,           NULL)
1213         PHP_FE(fastxsl_nocache_transform,            NULL)
1214         PHP_FE(fastxsl_nocache_profile,              NULL)
1215         PHP_FE(fastxsl_nocache_tostring,             NULL)
1216         PHP_FE(fastxsl_prmcache_tostring,            NULL)
1217         PHP_FE(fastxsl_prmcache_getstatistics,       NULL)
1218         {NULL, NULL, NULL}
1219 };
1220
1221
1222 zend_module_entry fastxsl_module_entry = {
1223 #if ZEND_MODULE_API_NO >= 20010901
1224         STANDARD_MODULE_HEADER,
1225 #endif
1226         "fastxsl",
1227         fastxsl_functions,
1228         PHP_MINIT(fastxsl),
1229         PHP_MSHUTDOWN(fastxsl),
1230         PHP_RINIT(fastxsl),
1231         PHP_RSHUTDOWN(fastxsl),
1232         PHP_MINFO(fastxsl),
1233 #if ZEND_MODULE_API_NO >= 20010901
1234         "0.1",
1235 #endif
1236         STANDARD_MODULE_PROPERTIES
1237 };
1238
1239
1240 #ifdef COMPILE_DL_FASTXSL
1241 ZEND_GET_MODULE(fastxsl)
1242 #endif
1243
1244 static void
1245 _SS_Wrapper_Dtor(php_ss_wrapper *wrapper)
1246 {
1247         if(wrapper->data.ss) {
1248                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1249                         //xmlCleanupParserr();
1250                         ShmCache_UseAllocationFunctions();
1251                 } else {
1252                         Xml_UseAllocationFunctions();
1253                 }
1254                 inshm = 1;
1255                 xsltFreeStylesheet(wrapper->data.ss);
1256                 inshm = 0;
1257                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1258                         //xmlCleanupParserr();
1259                         Xml_UseAllocationFunctions();
1260                 }
1261         }
1262         if(wrapper->persistant) {
1263 #ifdef FASTXSL_MM
1264                 mm_free(FASTXSL_G(cache)->mm, wrapper);
1265 #endif
1266         } else {
1267                 free(wrapper);
1268         }
1269 }
1270
1271 static void
1272 SS_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1273 {
1274         php_ss_wrapper *wrapper = (php_ss_wrapper *) rsrc->ptr;
1275         if (wrapper->persistant) {
1276                 return;
1277         }
1278         _SS_Wrapper_Dtor(wrapper);
1279 }
1280
1281 static void _XD_Wrapper_Dtor(php_xd_wrapper *wrapper) {
1282         if (wrapper->xd) {
1283                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1284                         ShmCache_UseAllocationFunctions();
1285                 } else {
1286                         Xml_UseAllocationFunctions();
1287                 }
1288 inshm = 1;
1289                 xmlFreeDoc(wrapper->xd);
1290 inshm = 0;
1291                 Xml_UseAllocationFunctions();
1292         }
1293         free(wrapper);
1294 }
1295
1296 static void
1297 XD_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1298 {
1299         php_xd_wrapper *wrapper = (php_xd_wrapper *) rsrc->ptr;
1300         _XD_Wrapper_Dtor(wrapper);
1301 }
1302
1303 void fastxsl_errorfunc(void *ctx, const char *msg, ...)
1304 {
1305         char *frag;
1306         int fraglen;
1307         int output = 0;
1308         va_list args;
1309         TSRMLS_FETCH();
1310
1311         va_start(args, msg);
1312         fraglen = vspprintf(&frag, 0, msg, args);
1313         while(fraglen && frag[fraglen - 1] == '\n') {
1314                 frag[--fraglen] = '\0';
1315                 output = 1;
1316         }
1317         if(fraglen) {
1318                 if(FASTXSL_G(errbuf)) {
1319                         FASTXSL_G(errbuf) = erealloc(FASTXSL_G(errbuf), fraglen + strlen(FASTXSL_G(errbuf)));
1320                         strcat(FASTXSL_G(errbuf), frag);
1321                 } else {
1322                         FASTXSL_G(errbuf) = frag;
1323                 }
1324         }
1325         va_end(args);
1326         if(output) {
1327                 php_error_docref(NULL TSRMLS_CC, E_WARNING, FASTXSL_G(errbuf));
1328                 efree(FASTXSL_G(errbuf));
1329                 FASTXSL_G(errbuf) = NULL;
1330         }
1331 }
1332
1333 static int
1334 Stream_MatchWrapper(const char *filename)
1335 {
1336         TSRMLS_FETCH();
1337         return php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ? 1 : 0;
1338 }
1339
1340 static void *
1341 Stream_XmlWrite_OpenWrapper(const char *filename)
1342 {
1343         TSRMLS_FETCH();
1344         return php_stream_open_wrapper((char *) filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
1345 }
1346
1347 static int
1348 Stream_XmlWrite_WriteWrapper(void *context, const char *buffer, int length)
1349 {
1350         TSRMLS_FETCH();
1351         return php_stream_write((php_stream *) context, (char *) buffer, length);
1352 }
1353
1354 static int
1355 Stream_CloseWrapper(void *context)
1356 {
1357         TSRMLS_FETCH();
1358         return php_stream_close((php_stream *) context);
1359 }
1360
1361
1362 extern int xmlLoadExtDtdDefaultValue;
1363
1364 /**
1365  * Allocators for the fl_hash storage
1366  */
1367 #ifdef FASTXSL_MM
1368 static FL_Allocator mm_allocators = {ShmCache_Free, ShmCache_Malloc, ShmCache_Calloc};
1369 #endif
1370 static FL_Allocator normal_allocators = {free, malloc, calloc};
1371
1372 static void
1373 php_fastxsl_init_globals(zend_fastxsl_globals *globals)
1374 {
1375         memset(globals, 0, sizeof(zend_fastxsl_globals));
1376        
1377         globals->cache = calloc(1, sizeof(fl_cache));
1378 }
1379
1380
1381 static void
1382 php_fastxsl_destroy_globals(zend_fastxsl_globals *globals)
1383 {
1384         fl_cache *cache;
1385        
1386         cache = globals->cache;
1387         if (cache) {
1388                 if (cache->owner != getpid()) {
1389                         return;
1390                 }
1391                 fl_hash_free(cache->prmtable);
1392         }
1393 }
1394
1395 /* {{{ php function -> xslt exporting
1396  */
1397  
1398 static void fastxsl_ext_function(xmlXPathParserContextPtr ctxt, int nargs)
1399 {
1400         xsltTransformContextPtr tctxt;
1401         zval **params;
1402         zval *param;
1403         zval *function = NULL;
1404         zval *ret = NULL;
1405         xmlChar *fname;
1406         int param_count = nargs - 1;
1407         int i;
1408         TSRMLS_FETCH();
1409        
1410         tctxt = (xsltTransformContextPtr) xsltXPathGetTransformContext(ctxt);
1411         ////xmlCleanupParserr();
1412         if (tctxt == NULL) {
1413                 xsltGenericError(xsltGenericErrorContext,
1414                 "fastxsl extension functions: failed to get the transformation context\n");
1415                 return;
1416         }
1417         /* allocate for args.  first position is function name */
1418         params = emalloc(sizeof(zval *) * param_count);
1419         for(i = param_count - 1; i >=0; i--) {
1420                 xmlXPathObjectPtr obj;
1421                 xmlChar *tmp;
1422                 obj = valuePop(ctxt);
1423                 MAKE_STD_ZVAL(param);
1424                 switch(obj->type) {
1425                         case XPATH_UNDEFINED:
1426                                 ZVAL_NULL(param);
1427                                 break;
1428                         case XPATH_NODESET:
1429                                 tmp = xmlXPathCastToString(obj);
1430                                 ZVAL_STRING(param, (char *) tmp, 1);
1431                                 xmlFree(tmp);
1432                                 break;
1433                         case XPATH_BOOLEAN:
1434                                 ZVAL_BOOL(param, obj->boolval);
1435                                 break;
1436                         case XPATH_NUMBER:
1437                                 ZVAL_DOUBLE(param, obj->floatval);
1438                                 break;
1439                         case XPATH_STRING:
1440                                 ZVAL_STRING(param, (char *)obj->stringval, 1);
1441                                 break;
1442                         default:
1443                                 zend_error(E_WARNING, "inexact type conversion %d", obj->type);
1444                                 tmp = xmlXPathCastToString(obj);
1445                                 ZVAL_STRING(param, (char *)tmp, 1);
1446                                 xmlFree(tmp);
1447                                 break;
1448                 }
1449                 params[i] = param;
1450                 xmlXPathFreeObject(obj);
1451         }
1452         fname = xmlXPathPopString(ctxt);
1453         if(!fname) {
1454                 xsltGenericError(xsltGenericDebugContext,
1455                         "passed function name is not a string");
1456                 xmlXPathReturnEmptyString(ctxt);
1457                 goto cleanup;
1458         }
1459         MAKE_STD_ZVAL(function);
1460         ZVAL_STRING(function, (char *)fname, 1);
1461         xmlFree(fname);
1462         MAKE_STD_ZVAL(ret);
1463         ZVAL_FALSE(ret);
1464         if(call_user_function(EG(function_table), NULL, function, ret,
1465                                  param_count, params TSRMLS_CC) == FAILURE) {
1466                         xsltGenericError(xsltGenericDebugContext,
1467                                 "function evaluation error");
1468                 xmlXPathReturnEmptyString(ctxt);
1469                 goto cleanup;
1470         }
1471         switch(ret->type) {
1472                 case IS_BOOL:
1473                         xmlXPathReturnBoolean(ctxt, Z_BVAL_P(ret));
1474                         break;
1475                 case IS_LONG:
1476                         xmlXPathReturnNumber(ctxt, (float) Z_LVAL_P(ret));
1477                         break;
1478                 case IS_DOUBLE:
1479                         xmlXPathReturnNumber(ctxt, Z_DVAL_P(ret));
1480                         break;
1481                 case IS_STRING:
1482                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1483                         break;
1484                 default:
1485                         convert_to_string_ex(&ret);
1486                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1487                         break;
1488         }
1489 cleanup:
1490         if(params) {
1491                 for(i=0; i < param_count; i++) {
1492                         zval_ptr_dtor(&params[i]);
1493                 }
1494                 efree(params); params = NULL;
1495         }
1496         if(function) {
1497                 efree(function); function = NULL;
1498         }
1499         if(ret) {
1500                 efree(ret); ret = NULL;
1501         }
1502         return;
1503 }               
1504 /* }}} */
1505
1506
1507 PHP_INI_BEGIN()
1508         STD_PHP_INI_ENTRY("fastxsl.shmpath", "/tmp/fastxsl_mem", PHP_INI_SYSTEM, OnUpdateString, shmpath, zend_fastxsl_globals, fastxsl_globals)
1509         STD_PHP_INI_BOOLEAN("fastxsl.nostat", "0", PHP_INI_ALL, OnUpdateLong, nostat, zend_fastxsl_globals, fastxsl_globals)
1510         STD_PHP_INI_BOOLEAN("fastxsl.memalloc", "0", PHP_INI_SYSTEM, OnUpdateLong, memalloc, zend_fastxsl_globals, fastxsl_globals)
1511         STD_PHP_INI_BOOLEAN("fastxsl.register_functions", "0", PHP_INI_ALL, OnUpdateLong, register_functions, zend_fastxsl_globals, fastxsl_globals)
1512 PHP_INI_END()
1513
1514 PHP_MINIT_FUNCTION(fastxsl)
1515 {
1516         char   *shmpath;
1517         size_t  shmpath_len;
1518         char    euid[30];
1519
1520         ZEND_INIT_MODULE_GLOBALS(fastxsl, php_fastxsl_init_globals, php_fastxsl_destroy_globals);
1521        
1522         REGISTER_INI_ENTRIES();
1523        
1524         le_fastxsl_stylesheet = zend_register_list_destructors_ex(SS_Wrapper_Dtor, NULL,
1525         le_fastxsl_stylesheet_name, module_number);
1526         le_fastxsl_document   = zend_register_list_destructors_ex(XD_Wrapper_Dtor, NULL,
1527                         le_fastxsl_document_name,   module_number);
1528 #ifdef FASTXSL_MM
1529         if (!sprintf(euid, "%d", geteuid())) {
1530                 return FAILURE;
1531         }
1532
1533         shmpath_len = strlen(FASTXSL_G(shmpath)) + strlen(euid);
1534         shmpath = do_alloca(shmpath_len + 1);
1535
1536         strcpy(shmpath, FASTXSL_G(shmpath));
1537         strcat(shmpath, euid);
1538        
1539         FASTXSL_G(cache)->owner = getpid();
1540         FASTXSL_G(cache)->mm = mm_create(FASTXSL_G(memalloc), shmpath);
1541         free_alloca(shmpath);
1542         if (!FASTXSL_G(cache)->mm) {
1543                 return FAILURE;
1544         }
1545
1546         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
1547         FASTXSL_G(cache)->table = fl_hash_new(&mm_allocators, NULL);
1548         mm_unlock(FASTXSL_G(cache)->mm);
1549 #endif
1550         FASTXSL_G(cache)->prmtable = fl_hash_new(&normal_allocators, NULL);
1551         //xmlGcMemGet(&free_ptr, &malloc_ptr, &mallocatomic_ptr, &realloc_ptr, &strdup_ptr);
1552         xmlMemGet(&free_ptr, &malloc_ptr, &realloc_ptr, &strdup_ptr);
1553         //xmlCleanupParserr();
1554         ShmCache_UseAllocationFunctions();
1555 inshm = 1;
1556         xsltRegisterAllExtras();
1557 #if HAVE_DOMEXSLT
1558         exsltRegisterAll();
1559 #endif
1560         xmlSubstituteEntitiesDefault(1);
1561         xmlLoadExtDtdDefaultValue = 1;
1562
1563         xmlRegisterOutputCallbacks(Stream_MatchWrapper, Stream_XmlWrite_OpenWrapper,
1564                                            Stream_XmlWrite_WriteWrapper, Stream_CloseWrapper);
1565         xsltSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1566         xmlSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1567        
1568         if(FASTXSL_G(register_functions)) {
1569                 xsltRegisterExtModuleFunction ((const xmlChar *) "function",
1570                                            (const xmlChar *) "http://php.net/fastxsl",
1571                                            fastxsl_ext_function);
1572         }
1573         xsltRegisterExtModuleFunction ((const xmlChar *) "cached_document",
1574                                    (const xmlChar *) "http://php.net/fastxsl/cached_document",
1575                                    fastxsl_CachedDocumentFunction);
1576         //xmlCleanupParserr();
1577 inshm = 0;
1578         Xml_UseAllocationFunctions();
1579         return SUCCESS;
1580 }
1581
1582 PHP_MSHUTDOWN_FUNCTION(fastxsl)
1583 {
1584   UNREGISTER_INI_ENTRIES();
1585 }
1586 PHP_RINIT_FUNCTION(fastxsl)
1587 {
1588 #ifdef FASTXSL_MM
1589   /* just in case, set back the allocators */
1590   Xml_UseAllocationFunctions();
1591 #endif
1592 }
1593 PHP_RSHUTDOWN_FUNCTION(fastxsl)
1594 {
1595 #ifdef FASTXSL_MM
1596   /* just in case, set back the allocators */
1597   Xml_UseAllocationFunctions();
1598 #endif
1599 }
1600
1601 PHP_MINFO_FUNCTION(fastxsl)
1602 {
1603         php_info_print_table_start();
1604         php_info_print_table_header(2, "fastxsl support", "enabled");
1605         php_info_print_table_row(2, "libxml Version", LIBXML_DOTTED_VERSION);
1606         php_info_print_table_row(2, "libxslt Version", LIBXSLT_DOTTED_VERSION);
1607 #if HAVE_DOMEXSLT
1608         php_info_print_table_row(2, "libexslt Version", LIBEXSLT_DOTTED_VERSION);
1609 #endif
1610         php_info_print_table_end();
1611 }
Note: See TracBrowser for help on using the browser.