root/trunk/fastxsl.c

Revision 29, 43.5 kB (checked in by jesus, 7 years ago)

arithmetic error in the parameters space requirements. Also, rework the call to 'document' to be in normal process-local memory mode

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 FASTXSL_MM
349 /* {{{ proto void fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
350    Emulate xsltDocumentFunction but leverage the MM shared cache for speed. */
351 static void
352 fastxsl_CachedDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
353 {
354         xmlXPathFunction func;
355         xmlXPathObjectPtr idoc, obj;
356         int lockfd;
357         char *ss_filename;
358         int ss_filename_len;
359         struct stat sb;
360         php_ss_wrapper *ss_wrapper;
361 #ifdef F_SETLK
362         struct flock lock;
363
364         lock.l_start = 0;
365         lock.l_whence = SEEK_SET;
366         lock.l_len = 0;
367 #endif
368         xmlXPathStringFunction(ctxt, 1);
369         if (ctxt->value->type != XPATH_STRING) {
370                 xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
371                                                  "document() : invalid arg expecting a string\n");
372                 goto error;
373         }
374         obj = ctxt->value;
375         ss_filename_len = strlen((char *)obj->stringval);
376         ss_filename = alloca(ss_filename_len + 1);
377         strcpy(ss_filename, (char *)obj->stringval);
378
379         lockfd = open(ss_filename, O_RDONLY);
380         if(lockfd < 0) {
381                 /* FIXME non-existent file */
382                 goto error;
383         }
384         if (!FASTXSL_G(nostat)) {
385                 if (fstat(lockfd, &sb) == -1) {
386                         ShmCache_UseAllocationFunctions();
387 inshm = 1;
388                         ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
389 inshm = 0;
390                         Xml_UseAllocationFunctions();
391                         close(lockfd);
392                         goto error;
393                 }
394         } else {
395                 sb.st_mtime = 0;
396         }
397 #ifdef F_SETLK
398         lock.l_type = F_WRLCK;
399         fcntl(lockfd, F_SETLKW, &lock);
400 #else
401         flock(lockfd, LOCK_EX);
402 #endif
403         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
404         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
405         mm_unlock(FASTXSL_G(cache)->mm);
406         if (!ss_wrapper) {
407                 ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
408                 if(ss_wrapper) {
409                         int rv;
410                         ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
411                         ss_wrapper->data_type = FASTXSL_STYLESHEET;
412                         func = xmlXPathFunctionLookup(ctxt->context, (const xmlChar *)"document");
413                         valuePush(ctxt, xmlXPathObjectCopy(ctxt->value));
414                         func(ctxt, nargs);
415                         ShmCache_UseAllocationFunctions();
416 inshm = 1;
417                         FASTXSL_G(tmp_allocated_size) = 0;
418                         ss_wrapper->data.op = xmlXPathObjectCopy(ctxt->value);
419                         ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
420 inshm = 0;
421                         Xml_UseAllocationFunctions();
422                         valuePop(ctxt);
423                         ss_wrapper->mtime = sb.st_mtime;
424                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
425                         rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
426                         mm_unlock(FASTXSL_G(cache)->mm);
427                         if(rv == 0) {
428                                 /* we failed */
429                                 php_ss_wrapper *fallback;
430                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
431                                 fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
432                                 mm_unlock(FASTXSL_G(cache)->mm);
433                                 if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
434                                         ShmCache_UseAllocationFunctions();
435 inshm = 1;
436                                         ShmCache_XPathObject_Free(ss_wrapper);
437 inshm = 0;
438                                         Xml_UseAllocationFunctions();
439                                         ss_wrapper = fallback;
440                                 } else {
441                                 }
442                         } else {
443                         }
444                 }
445                 if (!ss_wrapper) {
446 #ifdef F_SETLK
447                         lock.l_type = F_UNLCK;
448                         fcntl(lockfd, F_SETLK, &lock);
449 #else
450                         flock(lockfd, LOCK_UN);
451 #endif
452                         close(lockfd);
453                         //xmlCleanupParserr();
454                         Xml_UseAllocationFunctions();
455                         goto error;
456                 }
457         } else {
458                 if (!FASTXSL_G(nostat)) {
459                         if (ss_wrapper->mtime != sb.st_mtime) {
460                                 ShmCache_UseAllocationFunctions();
461 inshm = 1;
462                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
463 inshm = 0;
464                                 Xml_UseAllocationFunctions();
465                                 ss_wrapper = SS_Wrapper_Alloc(FASTXSL_SHARED_ALLOC TSRMLS_CC);
466                                 if(ss_wrapper) {
467                                         int rv;
468                                         ss_wrapper->alloc_type = FASTXSL_SHMALLOC;
469                                         ss_wrapper->data_type = FASTXSL_STYLESHEET;
470                                         func = xmlXPathFunctionLookup(ctxt->context, (const xmlChar *)"document");
471                                         valuePush(ctxt, xmlXPathObjectCopy(ctxt->value));
472                                         func(ctxt, nargs);
473                                         ShmCache_UseAllocationFunctions();
474 inshm = 1;
475                                         FASTXSL_G(tmp_allocated_size) = 0;
476                                         ss_wrapper->data.op = xmlXPathObjectCopy(ctxt->value);
477 inshm = 0;
478                                         Xml_UseAllocationFunctions();
479                                         valuePop(ctxt);
480                                         ss_wrapper->mtime = sb.st_mtime;
481                                         ss_wrapper->allocsize = FASTXSL_G(tmp_allocated_size);
482                                         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
483                                         rv = fl_hash_add(FASTXSL_G(cache)->table, ss_filename, ss_filename_len, ss_wrapper);
484                                         mm_unlock(FASTXSL_G(cache)->mm);
485                                         if(rv == 0) {
486                                                 /* we failed */
487                                                 php_ss_wrapper *fallback;
488                                                 mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
489                                                 fallback = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
490                                                 mm_unlock(FASTXSL_G(cache)->mm);
491                                                 if(fallback && fallback->data_type == FASTXSL_XPATHOBJ) {
492                                                         ShmCache_UseAllocationFunctions();
493 inshm = 1;
494                                                         ShmCache_XPathObject_Free(ss_wrapper);
495 inshm = 0;
496                                                         Xml_UseAllocationFunctions();
497                                                         ss_wrapper = fallback;
498                                                 } else {
499                                                 }
500                                         } else {
501                                         }
502                                 }
503                                 //xmlCleanupParserr();
504                                 if (!ss_wrapper) {
505 #ifdef F_SETLK
506                                         lock.l_type = F_UNLCK;
507                                         fcntl(lockfd, F_SETLK, &lock);
508 #else
509                                         flock(lockfd, LOCK_UN);
510 #endif
511                                         close(lockfd);
512                                         goto error;
513                                 }
514                         }
515                 }
516         }
517         ss_wrapper->hits++;
518         //xmlCleanupParserr();
519         Xml_UseAllocationFunctions();
520 #ifdef F_SETLK
521         lock.l_type = F_UNLCK;
522         fcntl(lockfd, F_SETLK, &lock);
523 #else
524         flock(lockfd, LOCK_UN);
525 #endif
526         close(lockfd);
527
528         valuePop(ctxt);
529         valuePush(ctxt, xmlXPathObjectCopy(ss_wrapper->data.op));
530         return;
531 error:
532         ctxt->error = XPATH_INVALID_TYPE;
533         return;
534 }
535 /* }}} */
536 #endif
537
538 static php_ss_wrapper *
539 PrmCache_Stylesheet_ParseAndStore(char *filename, size_t filename_len, int mtime TSRMLS_DC)
540 {
541         php_ss_wrapper *wrapper;
542
543         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(FASTXSL_PRM_ALLOC TSRMLS_CC);
544         wrapper->alloc_type = FASTXSL_PRMALLOC;
545
546         wrapper->data.ss = xsltParseStylesheetFile((xmlChar *)filename);
547         wrapper->data_type = FASTXSL_STYLESHEET;
548         if (!wrapper->data.ss) {
549                 return NULL;
550         }
551         wrapper->mtime = mtime;
552        
553         if(fl_hash_add(FASTXSL_G(cache)->prmtable, filename, filename_len, wrapper) == 0) {
554                 /* we failed, not much we can do here, and no race */
555         }
556
557         return wrapper;
558 }
559
560 static void
561 PrmCache_Stylesheet_Free(php_ss_wrapper *wrapper TSRMLS_DC)
562 {
563         if (wrapper->data_type == FASTXSL_STYLESHEET) {
564                 if (wrapper->data.ss) {
565                         xsltFreeStylesheet(wrapper->data.ss);
566                 }
567                 free(wrapper);
568         }
569 }
570
571 static void
572 PrmCache_XPathObject_Free(php_ss_wrapper *wrapper TSRMLS_DC)
573 {
574         if (wrapper->data_type == FASTXSL_XPATHOBJ) {
575                 if (wrapper->data.op) {
576                         xmlXPathFreeObject(wrapper->data.op);
577                 }
578                 free(wrapper);
579         }
580 }
581
582 static void
583 PrmCache_Document_Delete(char *filename, size_t filename_len TSRMLS_DC)
584 {
585         php_ss_wrapper *wrapper;
586
587         wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, filename, filename_len);
588         if (wrapper) {
589                 fl_hash_delete(FASTXSL_G(cache)->prmtable, filename, filename_len);
590                 switch(wrapper->data_type) {
591                         case FASTXSL_STYLESHEET:
592                                 PrmCache_Stylesheet_Free(wrapper TSRMLS_CC);
593                                 break;
594                         case FASTXSL_XPATHOBJ:
595                                 PrmCache_XPathObject_Free(wrapper TSRMLS_CC);
596                                 break;
597                         default:
598                                 break;
599                 }
600         }
601 }
602
603 /* {{{ proto array fastxsl_prmcache_getstatistics(void)
604    Get an array of statistics regarding the fastxsl documents in the process resident memory cache */
605 PHP_FUNCTION(fastxsl_prmcache_getstatistics)
606 {
607         php_ss_wrapper *wrapper;       
608
609         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
610                 return;
611         }
612
613 }
614 /* }}} */
615
616 /* {{{ proto array fastxsl_shmcache_getstatistics(void)
617    Get an array of statistics regarding the documents in the shared memory cache */
618 #ifdef FASTXSL_MM
619 PHP_FUNCTION(fastxsl_shmcache_getstatistics)
620 {
621         php_ss_wrapper *ss_wrapper;
622         FL_Bucket      *bucket;
623         zval           *files_array;
624         zval           *info_array;
625         int             i;
626         long            allocated_bytes = 0;
627        
628         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
629                 return;
630         }
631
632         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
633        
634         array_init(return_value);
635
636         MAKE_STD_ZVAL(files_array);
637         array_init(files_array);
638
639         for (i = 0; i < FL_HASH_SIZE; i++) {
640                 for (bucket = FASTXSL_G(cache)->table->buckets[i]; bucket != NULL; bucket = bucket->next) {
641                         ss_wrapper = (php_ss_wrapper *) bucket->data;
642
643                         MAKE_STD_ZVAL(info_array);
644                         array_init(info_array);
645
646                         add_assoc_long(info_array, "allocated", ss_wrapper->allocsize);
647                         add_assoc_long(info_array, "hits", ss_wrapper->hits);
648                         add_assoc_long(info_array, "mtime", ss_wrapper->mtime);
649
650                         add_assoc_zval(files_array, bucket->key, info_array);
651
652                         allocated_bytes += ss_wrapper->allocsize;
653                 }
654         }
655         add_assoc_zval(return_value, "files", files_array);
656
657         add_assoc_long(return_value, "apparent_allocated", allocated_bytes);
658         add_assoc_long(return_value, "allocated",
659           (FASTXSL_G(memalloc)?FASTXSL_G(memalloc):mm_maxsize()) - mm_available(FASTXSL_G(cache)->mm));
660         add_assoc_long(return_value, "shm_size", (long) FASTXSL_G(memalloc)?FASTXSL_G(memalloc):mm_maxsize());
661         mm_unlock(FASTXSL_G(cache)->mm);
662 }
663
664 #endif
665 /* }}} */
666
667 /* {{{ proto array fastxsl_version(void)
668    Returns the version number */
669 PHP_FUNCTION(fastxsl_version)
670 {
671         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "") == FAILURE) {
672                 return;
673         }
674         RETURN_STRING(PHP_FASTXSL_VERSION, 1);
675 }
676
677 /* }}} */
678
679 /* {{{ proto resource fastxsl_stylesheet_parsefile(string filename)
680    Parse a stylesheet file located at filename. */
681 PHP_FUNCTION(fastxsl_stylesheet_parsefile)
682 {
683         php_ss_wrapper *wrapper;
684         char           *filename;
685         size_t          filename_len;
686
687         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
688                                 &filename_len) == FAILURE) {
689                 return;
690         }
691
692         wrapper = (php_ss_wrapper *) SS_Wrapper_Alloc(0 TSRMLS_CC);
693         wrapper->alloc_type = FASTXSL_PRMALLOC;
694         Xml_UseAllocationFunctions();
695         wrapper->data.ss = xsltParseStylesheetFile((xmlChar*)filename);
696         if (!wrapper->data.ss) {
697                 RETURN_FALSE;
698         }
699
700         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_stylesheet);
701 }
702 /* }}} */
703
704 /* {{{ proto resource fastxsl_xml_parsestring(string text)
705   Parse a string containing an XML document and return a resource pointer to the resulting libxml2 tree */
706 PHP_FUNCTION(fastxsl_xml_parsestring)
707 {
708         php_xd_wrapper *wrapper;
709         char           *text;
710         size_t          text_len;
711
712         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &text, &text_len) == FAILURE) {
713                 return;
714         }
715
716         wrapper = XD_Wrapper_Alloc();
717         wrapper->alloc_type = FASTXSL_PRMALLOC;
718         Xml_UseAllocationFunctions();
719         wrapper->xd = xmlParseDoc((xmlChar *) text);
720         if (!wrapper->xd) {
721                 _XD_Wrapper_Dtor(wrapper);
722                 RETURN_FALSE;
723         }
724
725         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
726 }
727 /* }}} */
728
729 /* {{{ proto resource fastxsl_xml_parsefile(string filename)
730    Parse an XML file into a FastXSL resource */
731 PHP_FUNCTION(fastxsl_xml_parsefile)
732 {
733         php_xd_wrapper *wrapper;
734         char           *filename;
735         size_t          filename_len;
736
737         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename,
738                                 &filename_len) == FAILURE) {
739                 return;
740         }
741
742         wrapper = XD_Wrapper_Alloc();
743         wrapper->alloc_type = FASTXSL_PRMALLOC;
744         wrapper->xd = xmlParseFile((const char *) filename);
745         if (!wrapper->xd) {
746                 _XD_Wrapper_Dtor(wrapper);
747                 RETURN_FALSE;
748         }
749
750         ZEND_REGISTER_RESOURCE(return_value, wrapper, le_fastxsl_document);
751 }
752 /* }}} */
753
754 static int
755 ParseTransformParameters(zval *z_parameters, char ***parameters TSRMLS_DC)
756 {
757         zval         **current;
758         HashTable     *h_parameters;
759         HashPosition   pos;
760         char          *key;
761         uint           key_length;
762         unsigned long  ival;
763         int            index = 0;
764
765         h_parameters = Z_ARRVAL_P(z_parameters);
766
767         if (zend_hash_num_elements(h_parameters) == 0) {
768                 *parameters = NULL;
769                 return SUCCESS;
770         }
771        
772         *parameters = calloc(1, (1 + zend_hash_num_elements(h_parameters) * 2) * sizeof(char *));
773         if (!*parameters) {
774                 php_error(E_WARNING, "Cannot allocate parameters array to pass to FastXSL");
775                 return FAILURE;
776         }
777        
778         for (zend_hash_internal_pointer_reset_ex(h_parameters, &pos);
779              zend_hash_get_current_data_ex(h_parameters, (void **) &current, &pos) == SUCCESS;
780                  zend_hash_move_forward_ex(h_parameters, &pos)) {
781                 if (zend_hash_get_current_key_ex(h_parameters, &key, &key_length,
782                                         &ival, 0, &pos) == HASH_KEY_IS_LONG) {
783                         efree(*parameters);
784                         *parameters = NULL;
785
786                         php_error(E_WARNING,
787                                         "Parameters array passed to %s() may not contain numeric keys",
788                                         get_active_function_name(TSRMLS_C));
789                         return FAILURE;
790                 }
791
792                 convert_to_string_ex(current);
793
794                 (*parameters)[index++] = key;
795                 (*parameters)[index++] = Z_STRVAL_PP(current);
796         }
797         (*parameters)[index] = NULL;
798
799         return SUCCESS;
800 }
801
802 /* {{{ proto resource fastxsl_shmcache_transform(string filename, resource xmldoc[, array parameters])
803    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
804 #ifdef FASTXSL_MM
805 PHP_FUNCTION(fastxsl_shmcache_transform)
806 {
807         xsltTransformContextPtr ctxt;
808         char            **parameters = NULL;
809         php_xd_wrapper   *xd_wrapper;
810         php_xd_wrapper   *result_wrapper;
811         php_ss_wrapper   *ss_wrapper;
812         char             *ss_filename;
813         size_t            ss_filename_len;
814         zval             *z_xd_wrapper;
815         zval             *z_parameters;
816         struct stat       sb;
817         int lockfd;
818 #ifdef F_SETLK
819         struct flock lock;
820
821         lock.l_start = 0;
822         lock.l_whence = SEEK_SET;
823         lock.l_len = 0;
824 #endif
825
826        
827         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
828                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
829                 return;
830         }
831        
832         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
833                         le_fastxsl_document);
834
835         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
836                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
837                         RETURN_FALSE;
838                 }
839         }
840
841         result_wrapper = XD_Wrapper_Alloc();
842         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
843         lockfd = open(ss_filename, O_RDONLY);
844         if(lockfd < 0) {
845                 /* FIXME non-existent file */
846                 RETURN_FALSE;
847         }
848         if (!FASTXSL_G(nostat)) {
849                 if (fstat(lockfd, &sb) == -1) {
850                         ShmCache_UseAllocationFunctions();
851 inshm = 1;
852                         ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
853 inshm = 0;
854                         Xml_UseAllocationFunctions();
855                         _XD_Wrapper_Dtor(result_wrapper);
856                         free(parameters);
857                         close(lockfd);
858                         RETURN_FALSE;
859                 }
860         } else {
861                 sb.st_mtime = 0;
862         }
863 #ifdef F_SETLK
864         lock.l_type = F_WRLCK;
865         fcntl(lockfd, F_SETLKW, &lock);
866 #else
867         flock(lockfd, LOCK_EX);
868 #endif
869         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
870         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
871         mm_unlock(FASTXSL_G(cache)->mm);
872         if (!ss_wrapper) {
873                 ShmCache_UseAllocationFunctions();
874 inshm = 1;
875                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime);
876 inshm = 0;
877                 if (!ss_wrapper) {
878 #ifdef F_SETLK
879                         lock.l_type = F_UNLCK;
880                         fcntl(lockfd, F_SETLK, &lock);
881 #else
882                         flock(lockfd, LOCK_UN);
883 #endif
884                         close(lockfd);
885                         //xmlCleanupParserr();
886                         Xml_UseAllocationFunctions();
887                         _XD_Wrapper_Dtor(result_wrapper);
888                         free(parameters);
889                         RETURN_FALSE;
890                 }
891         } else {
892                 if (!FASTXSL_G(nostat)) {
893                         if (ss_wrapper->mtime != sb.st_mtime) {
894                                 //xmlCleanupParserr();
895                                 ShmCache_UseAllocationFunctions();
896 inshm = 1;
897                                 ShmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
898                                 ss_wrapper = ShmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
899 inshm = 0;
900                                 //xmlCleanupParserr();
901                                 Xml_UseAllocationFunctions();
902                                 if (!ss_wrapper) {
903 #ifdef F_SETLK
904                                         lock.l_type = F_UNLCK;
905                                         fcntl(lockfd, F_SETLK, &lock);
906 #else
907                                         flock(lockfd, LOCK_UN);
908 #endif
909                                         close(lockfd);
910                                         _XD_Wrapper_Dtor(result_wrapper);
911                                         free(parameters);
912                                         RETURN_FALSE;
913                                 }
914                         }
915                 }
916         }
917         ss_wrapper->hits++;
918         //xmlCleanupParserr();
919         Xml_UseAllocationFunctions();
920 #ifdef F_SETLK
921         lock.l_type = F_UNLCK;
922         fcntl(lockfd, F_SETLK, &lock);
923 #else
924         flock(lockfd, LOCK_UN);
925 #endif
926         close(lockfd);
927
928         ctxt = xsltNewTransformContext(ss_wrapper->data.ss, xd_wrapper->xd);
929 #ifdef FASTXSL_MM
930         xmlXPathRegisterFunc(ctxt->xpathCtxt, (const xmlChar *) "cached_document",
931                                 fastxsl_CachedDocumentFunction);
932 #endif
933         result_wrapper->xd = xsltApplyStylesheetUser(ss_wrapper->data.ss, xd_wrapper->xd,
934                         (const char **) parameters, NULL, NULL, ctxt);
935         xsltFreeTransformContext(ctxt);
936        
937         if (parameters)
938                 free(parameters);
939        
940         if (!result_wrapper->xd) {
941                 RETURN_FALSE;
942         }       
943        
944         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
945 }
946 #endif
947 /* }}} */
948
949 /* {{{ proto resource fastxsl_prmcache_transform(string filename, resource xmldoc[, array parameters])
950    Transform a XML document, "xmldoc", by a XSL stylesheet "filename" with transform "parameters." */
951 PHP_FUNCTION(fastxsl_prmcache_transform)
952 {
953         char            **parameters = NULL;
954         php_xd_wrapper   *xd_wrapper;
955         php_xd_wrapper   *result_wrapper;
956         php_ss_wrapper   *ss_wrapper;
957         char             *ss_filename;
958         size_t            ss_filename_len;
959         zval             *z_xd_wrapper;
960         zval             *z_parameters;
961         struct stat       sb;
962        
963         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|z", &ss_filename, &ss_filename_len,
964                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
965                 return;
966         }
967         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
968                         le_fastxsl_document);
969
970         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
971                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
972                         RETURN_FALSE;
973                 }
974         }
975
976         result_wrapper = XD_Wrapper_Alloc();
977         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
978
979         if (!FASTXSL_G(nostat)) {
980                 if (stat(ss_filename, &sb) == -1) {
981                         PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
982                         _XD_Wrapper_Dtor(result_wrapper);
983                         free(parameters);
984                         RETURN_FALSE;
985                 }
986         } else {
987                 sb.st_mtime = 0;
988         }
989        
990         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
991         if (!ss_wrapper) {
992                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
993                 if (!ss_wrapper) {
994                         _XD_Wrapper_Dtor(result_wrapper);
995                         free(parameters);
996                         RETURN_FALSE;
997                 }
998         } else {
999                 if (!FASTXSL_G(nostat)) {
1000                         if (ss_wrapper->mtime != sb.st_mtime) {
1001                                 PrmCache_Document_Delete(ss_filename, ss_filename_len TSRMLS_CC);
1002                                 ss_wrapper = PrmCache_Stylesheet_ParseAndStore(ss_filename, ss_filename_len, sb.st_mtime TSRMLS_CC);
1003                                 if (!ss_wrapper) {
1004                                         _XD_Wrapper_Dtor(result_wrapper);
1005                                         free(parameters);
1006                                         RETURN_FALSE;
1007                                 }
1008                         }
1009                 }
1010         }
1011         ss_wrapper->hits++;
1012         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1013                         (const char **) parameters);
1014         ////xmlCleanupParserr();
1015
1016         if (parameters)
1017                 free(parameters);
1018        
1019         if (!result_wrapper->xd) {
1020                 _XD_Wrapper_Dtor(result_wrapper);
1021                 RETURN_FALSE;
1022         }       
1023        
1024         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1025 }
1026
1027 /* {{{ proto void fastxsl_nocache_transform(resource stylesheet, resource xmldoc[, array parameters])
1028    Transform the stylesheet document by the xml document with parameters. */
1029 PHP_FUNCTION(fastxsl_nocache_transform)
1030 {
1031         char           **parameters = NULL;
1032         php_xd_wrapper  *xd_wrapper;
1033         php_xd_wrapper  *result_wrapper;
1034         php_ss_wrapper  *ss_wrapper;
1035         zval            *z_xd_wrapper;
1036         zval            *z_ss_wrapper;
1037         zval            *z_parameters;
1038
1039         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|z", &z_ss_wrapper,
1040                                 &z_xd_wrapper, &z_parameters) == FAILURE) {
1041                 return;
1042         }
1043         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1044                         le_fastxsl_stylesheet);
1045         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1046                         le_fastxsl_document);
1047
1048         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1049                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1050                         RETURN_FALSE;
1051                 }
1052         }
1053
1054         result_wrapper = XD_Wrapper_Alloc();
1055         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1056         result_wrapper->xd = xsltApplyStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1057                         (const char **) parameters);
1058         if (parameters)
1059                 free(parameters);
1060
1061         if (!result_wrapper->xd) {
1062                 _XD_Wrapper_Dtor(result_wrapper);
1063                 RETURN_FALSE;
1064         }       
1065
1066        
1067         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1068 }
1069 /* }}} */
1070
1071 /* {{{ proto void fastxsl_nocache_profile(resource stylesheet, resource xmldoc[, array parameters, string filename])
1072    Profile the stylesheet document by the xml document with parameters and output the results to filename (or stderr, if filename doesn't exist). */
1073 PHP_FUNCTION(fastxsl_nocache_profile)
1074 {
1075         char           **parameters = NULL;
1076         char            *filename = "php://stderr";
1077         php_xd_wrapper  *xd_wrapper;
1078         php_xd_wrapper  *result_wrapper;
1079         php_ss_wrapper  *ss_wrapper;
1080         zval            *z_xd_wrapper;
1081         zval            *z_ss_wrapper;
1082         zval            *z_parameters;
1083         FILE            *dbgprof;
1084         int              filename_len;
1085
1086         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|zs", &z_ss_wrapper,
1087                                 &z_xd_wrapper, &z_parameters, &filename, &filename_len) == FAILURE) {
1088                 return;
1089         }
1090         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL Stylesheet",
1091                         le_fastxsl_stylesheet);
1092         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1093                         le_fastxsl_document);
1094
1095         if (ZEND_NUM_ARGS() > 2 && Z_TYPE_P(z_parameters) == IS_ARRAY) {
1096                 if (ParseTransformParameters(z_parameters, &parameters TSRMLS_CC) == FAILURE) {
1097                         RETURN_FALSE;
1098                 }
1099         }
1100
1101         if (!strcmp(filename, "php://stdout")) {
1102                 dbgprof = stdout;
1103         } else if (!strcmp(filename, "php://stderr")) {
1104                 dbgprof = stderr;
1105         } else {
1106                 dbgprof = fopen(filename, "w");
1107         }
1108
1109         result_wrapper = XD_Wrapper_Alloc();
1110         result_wrapper->alloc_type = FASTXSL_PRMALLOC;
1111
1112         result_wrapper->xd = xsltProfileStylesheet(ss_wrapper->data.ss, xd_wrapper->xd,
1113                         (const char **) parameters, dbgprof);
1114         if (parameters)
1115                 free(parameters);
1116
1117         fclose(dbgprof);
1118        
1119         if (!result_wrapper->xd) {
1120                 _XD_Wrapper_Dtor(result_wrapper);
1121                 RETURN_FALSE;
1122         }       
1123        
1124         ZEND_REGISTER_RESOURCE(return_value, result_wrapper, le_fastxsl_document);
1125 }
1126 /* }}} */
1127
1128 /* {{{ proto string fastxsl_nocache_tostring(resource stylesheet, resource xmldoc)
1129    Return the contents of an XML stylesheet result as a string */
1130 PHP_FUNCTION(fastxsl_nocache_tostring)
1131 {
1132         zval           *z_xd_wrapper;
1133         zval           *z_ss_wrapper;
1134         php_ss_wrapper *ss_wrapper;
1135         php_xd_wrapper *xd_wrapper;
1136         xmlChar        *result = NULL;
1137         int             length;
1138
1139         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &z_ss_wrapper,
1140                                 &z_xd_wrapper) == FAILURE) {
1141                 return;
1142         }
1143         ZEND_FETCH_RESOURCE(ss_wrapper, php_ss_wrapper *, &z_ss_wrapper, -1, "FastXSL XML Stylesheet",
1144                         le_fastxsl_stylesheet);
1145         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1146                         le_fastxsl_document);
1147
1148         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1149
1150         if (result) {
1151                 RETVAL_STRINGL((char *) result, length, 1);
1152                 xmlFree(result);
1153         } else {
1154                 RETURN_FALSE;
1155         }
1156 }
1157 /* }}} */
1158
1159 /* {{{ proto string fastxsl_shmcache_tostring(string filename, resource xmldoc)
1160    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1161 #ifdef FASTXSL_MM
1162 PHP_FUNCTION(fastxsl_shmcache_tostring)
1163 {
1164         zval           *z_xd_wrapper;
1165         php_ss_wrapper *ss_wrapper;
1166         php_xd_wrapper *xd_wrapper;
1167         xmlChar        *result = NULL;
1168         char           *ss_filename;
1169         size_t          ss_filename_len;
1170         int             length;
1171
1172         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1173                                 &z_xd_wrapper) == FAILURE) {
1174                 return;
1175         }
1176         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1177                         le_fastxsl_document);
1178         Xml_UseAllocationFunctions();
1179         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RD);
1180         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->table, ss_filename, ss_filename_len);
1181         mm_unlock(FASTXSL_G(cache)->mm);
1182         if (!ss_wrapper) {
1183                 RETURN_FALSE;
1184         }
1185         ss_wrapper->hits++;
1186         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1187         if (result) {
1188                 RETVAL_STRINGL((char *) result, length, 1);
1189                 xmlFree(result);
1190         } else {
1191                 RETVAL_FALSE;
1192         }
1193         Xml_UseAllocationFunctions();
1194 }
1195 #endif
1196 /* }}} */
1197
1198 /* {{{ proto string fastxsl_prmcache_tostring(string filename, resource xmldoc)
1199    Return the string representation of xmldoc which is the result of an XSLT transformation on filename */
1200 PHP_FUNCTION(fastxsl_prmcache_tostring)
1201 {
1202         zval           *z_xd_wrapper;
1203         php_ss_wrapper *ss_wrapper;
1204         php_xd_wrapper *xd_wrapper;
1205         xmlChar        *result = NULL;
1206         char           *ss_filename;
1207         size_t          ss_filename_len;
1208         int             length;
1209
1210         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &ss_filename, &ss_filename_len,
1211                                 &z_xd_wrapper) == FAILURE) {
1212                 return;
1213         }
1214         ZEND_FETCH_RESOURCE(xd_wrapper, php_xd_wrapper *, &z_xd_wrapper, -1, "FastXSL XML Document",
1215                         le_fastxsl_document);
1216
1217         ss_wrapper = fl_hash_find(FASTXSL_G(cache)->prmtable, ss_filename, ss_filename_len);
1218         if (!ss_wrapper) {
1219                 RETURN_FALSE;
1220         }
1221         ss_wrapper->hits++;
1222         xsltSaveResultToString(&result, &length, xd_wrapper->xd, ss_wrapper->data.ss);
1223        
1224         if (result) {
1225                 RETVAL_STRINGL((char *) result, length, 1);
1226                 xmlFree(result);
1227         } else {
1228                 RETURN_FALSE;
1229         }
1230 }
1231 /* }}} */
1232
1233 function_entry fastxsl_functions[] = {
1234         PHP_FE(fastxsl_stylesheet_parsefile,         NULL)
1235         PHP_FE(fastxsl_xml_parsefile,                NULL)
1236         PHP_FE(fastxsl_xml_parsestring,              NULL)
1237 #ifdef FASTXSL_MM
1238         PHP_FE(fastxsl_shmcache_transform,           NULL)
1239         PHP_FE(fastxsl_shmcache_tostring,            NULL)
1240         PHP_FE(fastxsl_shmcache_getstatistics,       NULL)
1241 #endif
1242         PHP_FE(fastxsl_version,                      NULL)
1243         PHP_FE(fastxsl_prmcache_transform,           NULL)
1244         PHP_FE(fastxsl_nocache_transform,            NULL)
1245         PHP_FE(fastxsl_nocache_profile,              NULL)
1246         PHP_FE(fastxsl_nocache_tostring,             NULL)
1247         PHP_FE(fastxsl_prmcache_tostring,            NULL)
1248         PHP_FE(fastxsl_prmcache_getstatistics,       NULL)
1249         {NULL, NULL, NULL}
1250 };
1251
1252
1253 zend_module_entry fastxsl_module_entry = {
1254 #if ZEND_MODULE_API_NO >= 20010901
1255         STANDARD_MODULE_HEADER,
1256 #endif
1257         "fastxsl",
1258         fastxsl_functions,
1259         PHP_MINIT(fastxsl),
1260         PHP_MSHUTDOWN(fastxsl),
1261         PHP_RINIT(fastxsl),
1262         PHP_RSHUTDOWN(fastxsl),
1263         PHP_MINFO(fastxsl),
1264 #if ZEND_MODULE_API_NO >= 20010901
1265         "0.1",
1266 #endif
1267         STANDARD_MODULE_PROPERTIES
1268 };
1269
1270
1271 #ifdef COMPILE_DL_FASTXSL
1272 ZEND_GET_MODULE(fastxsl)
1273 #endif
1274
1275 static void
1276 _SS_Wrapper_Dtor(php_ss_wrapper *wrapper)
1277 {
1278         if(wrapper->data.ss) {
1279                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1280                         //xmlCleanupParserr();
1281                         ShmCache_UseAllocationFunctions();
1282                 } else {
1283                         Xml_UseAllocationFunctions();
1284                 }
1285                 inshm = 1;
1286                 xsltFreeStylesheet(wrapper->data.ss);
1287                 inshm = 0;
1288                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1289                         //xmlCleanupParserr();
1290                         Xml_UseAllocationFunctions();
1291                 }
1292         }
1293         if(wrapper->persistant) {
1294 #ifdef FASTXSL_MM
1295                 mm_free(FASTXSL_G(cache)->mm, wrapper);
1296 #endif
1297         } else {
1298                 free(wrapper);
1299         }
1300 }
1301
1302 static void
1303 SS_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1304 {
1305         php_ss_wrapper *wrapper = (php_ss_wrapper *) rsrc->ptr;
1306         if (wrapper->persistant) {
1307                 return;
1308         }
1309         _SS_Wrapper_Dtor(wrapper);
1310 }
1311
1312 static void _XD_Wrapper_Dtor(php_xd_wrapper *wrapper) {
1313         if (wrapper->xd) {
1314                 if(wrapper->alloc_type == FASTXSL_SHMALLOC) {
1315                         ShmCache_UseAllocationFunctions();
1316                 } else {
1317                         Xml_UseAllocationFunctions();
1318                 }
1319 inshm = 1;
1320                 xmlFreeDoc(wrapper->xd);
1321 inshm = 0;
1322                 Xml_UseAllocationFunctions();
1323         }
1324         free(wrapper);
1325 }
1326
1327 static void
1328 XD_Wrapper_Dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
1329 {
1330         php_xd_wrapper *wrapper = (php_xd_wrapper *) rsrc->ptr;
1331         _XD_Wrapper_Dtor(wrapper);
1332 }
1333
1334 void fastxsl_errorfunc(void *ctx, const char *msg, ...)
1335 {
1336         char *frag;
1337         int fraglen;
1338         int output = 0;
1339         va_list args;
1340         TSRMLS_FETCH();
1341
1342         va_start(args, msg);
1343         fraglen = vspprintf(&frag, 0, msg, args);
1344         while(fraglen && frag[fraglen - 1] == '\n') {
1345                 frag[--fraglen] = '\0';
1346                 output = 1;
1347         }
1348         if(fraglen) {
1349                 if(FASTXSL_G(errbuf)) {
1350                         FASTXSL_G(errbuf) = erealloc(FASTXSL_G(errbuf), fraglen + strlen(FASTXSL_G(errbuf)));
1351                         strcat(FASTXSL_G(errbuf), frag);
1352                 } else {
1353                         FASTXSL_G(errbuf) = frag;
1354                 }
1355         }
1356         va_end(args);
1357         if(output) {
1358                 php_error_docref(NULL TSRMLS_CC, E_WARNING, FASTXSL_G(errbuf));
1359                 efree(FASTXSL_G(errbuf));
1360                 FASTXSL_G(errbuf) = NULL;
1361         }
1362 }
1363
1364 static int
1365 Stream_MatchWrapper(const char *filename)
1366 {
1367         TSRMLS_FETCH();
1368         return php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY TSRMLS_CC) ? 1 : 0;
1369 }
1370
1371 static void *
1372 Stream_XmlWrite_OpenWrapper(const char *filename)
1373 {
1374         TSRMLS_FETCH();
1375         return php_stream_open_wrapper((char *) filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);
1376 }
1377
1378 static int
1379 Stream_XmlWrite_WriteWrapper(void *context, const char *buffer, int length)
1380 {
1381         TSRMLS_FETCH();
1382         return php_stream_write((php_stream *) context, (char *) buffer, length);
1383 }
1384
1385 static int
1386 Stream_CloseWrapper(void *context)
1387 {
1388         TSRMLS_FETCH();
1389         return php_stream_close((php_stream *) context);
1390 }
1391
1392
1393 extern int xmlLoadExtDtdDefaultValue;
1394
1395 /**
1396  * Allocators for the fl_hash storage
1397  */
1398 #ifdef FASTXSL_MM
1399 static FL_Allocator mm_allocators = {ShmCache_Free, ShmCache_Malloc, ShmCache_Calloc};
1400 #endif
1401 static FL_Allocator normal_allocators = {free, malloc, calloc};
1402
1403 static void
1404 php_fastxsl_init_globals(zend_fastxsl_globals *globals)
1405 {
1406         memset(globals, 0, sizeof(zend_fastxsl_globals));
1407        
1408         globals->cache = calloc(1, sizeof(fl_cache));
1409 }
1410
1411
1412 static void
1413 php_fastxsl_destroy_globals(zend_fastxsl_globals *globals)
1414 {
1415         fl_cache *cache;
1416        
1417         cache = globals->cache;
1418         if (cache) {
1419                 if (cache->owner != getpid()) {
1420                         return;
1421                 }
1422                 fl_hash_free(cache->prmtable);
1423         }
1424 }
1425
1426 /* {{{ php function -> xslt exporting
1427  */
1428  
1429 static void fastxsl_ext_function(xmlXPathParserContextPtr ctxt, int nargs)
1430 {
1431         xsltTransformContextPtr tctxt;
1432         zval **params;
1433         zval *param;
1434         zval *function = NULL;
1435         zval *ret = NULL;
1436         xmlChar *fname;
1437         int param_count = nargs - 1;
1438         int i;
1439         TSRMLS_FETCH();
1440        
1441         tctxt = (xsltTransformContextPtr) xsltXPathGetTransformContext(ctxt);
1442         ////xmlCleanupParserr();
1443         if (tctxt == NULL) {
1444                 xsltGenericError(xsltGenericErrorContext,
1445                 "fastxsl extension functions: failed to get the transformation context\n");
1446                 return;
1447         }
1448         /* allocate for args.  first position is function name */
1449         params = emalloc(sizeof(zval *) * param_count);
1450         for(i = param_count - 1; i >=0; i--) {
1451                 xmlXPathObjectPtr obj;
1452                 xmlChar *tmp;
1453                 obj = valuePop(ctxt);
1454                 MAKE_STD_ZVAL(param);
1455                 switch(obj->type) {
1456                         case XPATH_UNDEFINED:
1457                                 ZVAL_NULL(param);
1458                                 break;
1459                         case XPATH_NODESET:
1460                                 tmp = xmlXPathCastToString(obj);
1461                                 ZVAL_STRING(param, (char *) tmp, 1);
1462                                 xmlFree(tmp);
1463                                 break;
1464                         case XPATH_BOOLEAN:
1465                                 ZVAL_BOOL(param, obj->boolval);
1466                                 break;
1467                         case XPATH_NUMBER:
1468                                 ZVAL_DOUBLE(param, obj->floatval);
1469                                 break;
1470                         case XPATH_STRING:
1471                                 ZVAL_STRING(param, (char *)obj->stringval, 1);
1472                                 break;
1473                         default:
1474                                 zend_error(E_WARNING, "inexact type conversion %d", obj->type);
1475                                 tmp = xmlXPathCastToString(obj);
1476                                 ZVAL_STRING(param, (char *)tmp, 1);
1477                                 xmlFree(tmp);
1478                                 break;
1479                 }
1480                 params[i] = param;
1481                 xmlXPathFreeObject(obj);
1482         }
1483         fname = xmlXPathPopString(ctxt);
1484         if(!fname) {
1485                 xsltGenericError(xsltGenericDebugContext,
1486                         "passed function name is not a string");
1487                 xmlXPathReturnEmptyString(ctxt);
1488                 goto cleanup;
1489         }
1490         MAKE_STD_ZVAL(function);
1491         ZVAL_STRING(function, (char *)fname, 1);
1492         xmlFree(fname);
1493         MAKE_STD_ZVAL(ret);
1494         ZVAL_FALSE(ret);
1495         if(call_user_function(EG(function_table), NULL, function, ret,
1496                                  param_count, params TSRMLS_CC) == FAILURE) {
1497                         xsltGenericError(xsltGenericDebugContext,
1498                                 "function evaluation error");
1499                 xmlXPathReturnEmptyString(ctxt);
1500                 goto cleanup;
1501         }
1502         switch(ret->type) {
1503                 case IS_BOOL:
1504                         xmlXPathReturnBoolean(ctxt, Z_BVAL_P(ret));
1505                         break;
1506                 case IS_LONG:
1507                         xmlXPathReturnNumber(ctxt, (float) Z_LVAL_P(ret));
1508                         break;
1509                 case IS_DOUBLE:
1510                         xmlXPathReturnNumber(ctxt, Z_DVAL_P(ret));
1511                         break;
1512                 case IS_STRING:
1513                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1514                         break;
1515                 default:
1516                         convert_to_string_ex(&ret);
1517                         xmlXPathReturnString(ctxt, xmlStrdup((xmlChar *) Z_STRVAL_P(ret)));
1518                         break;
1519         }
1520 cleanup:
1521         if(params) {
1522                 for(i=0; i < param_count; i++) {
1523                         zval_ptr_dtor(&params[i]);
1524                 }
1525                 efree(params); params = NULL;
1526         }
1527         if(function) {
1528                 efree(function); function = NULL;
1529         }
1530         if(ret) {
1531                 efree(ret); ret = NULL;
1532         }
1533         return;
1534 }               
1535 /* }}} */
1536
1537
1538 PHP_INI_BEGIN()
1539         STD_PHP_INI_ENTRY("fastxsl.shmpath", "/tmp/fastxsl_mem", PHP_INI_SYSTEM, OnUpdateString, shmpath, zend_fastxsl_globals, fastxsl_globals)
1540         STD_PHP_INI_BOOLEAN("fastxsl.nostat", "0", PHP_INI_ALL, OnUpdateLong, nostat, zend_fastxsl_globals, fastxsl_globals)
1541         STD_PHP_INI_BOOLEAN("fastxsl.memalloc", "0", PHP_INI_SYSTEM, OnUpdateLong, memalloc, zend_fastxsl_globals, fastxsl_globals)
1542         STD_PHP_INI_BOOLEAN("fastxsl.register_functions", "0", PHP_INI_ALL, OnUpdateLong, register_functions, zend_fastxsl_globals, fastxsl_globals)
1543 PHP_INI_END()
1544
1545 PHP_MINIT_FUNCTION(fastxsl)
1546 {
1547         char   *shmpath;
1548         size_t  shmpath_len;
1549         char    euid[30];
1550
1551         ZEND_INIT_MODULE_GLOBALS(fastxsl, php_fastxsl_init_globals, php_fastxsl_destroy_globals);
1552        
1553         REGISTER_INI_ENTRIES();
1554        
1555         le_fastxsl_stylesheet = zend_register_list_destructors_ex(SS_Wrapper_Dtor, NULL,
1556         le_fastxsl_stylesheet_name, module_number);
1557         le_fastxsl_document   = zend_register_list_destructors_ex(XD_Wrapper_Dtor, NULL,
1558                         le_fastxsl_document_name,   module_number);
1559 #ifdef FASTXSL_MM
1560         if (!sprintf(euid, "%d", geteuid())) {
1561                 return FAILURE;
1562         }
1563
1564         shmpath_len = strlen(FASTXSL_G(shmpath)) + strlen(euid);
1565         shmpath = do_alloca(shmpath_len + 1);
1566
1567         strcpy(shmpath, FASTXSL_G(shmpath));
1568         strcat(shmpath, euid);
1569        
1570         FASTXSL_G(cache)->owner = getpid();
1571         FASTXSL_G(cache)->mm = mm_create(FASTXSL_G(memalloc), shmpath);
1572         free_alloca(shmpath);
1573         if (!FASTXSL_G(cache)->mm) {
1574                 return FAILURE;
1575         }
1576
1577         mm_lock(FASTXSL_G(cache)->mm, MM_LOCK_RW);
1578         FASTXSL_G(cache)->table = fl_hash_new(&mm_allocators, NULL);
1579         mm_unlock(FASTXSL_G(cache)->mm);
1580 #endif
1581         FASTXSL_G(cache)->prmtable = fl_hash_new(&normal_allocators, NULL);
1582         //xmlGcMemGet(&free_ptr, &malloc_ptr, &mallocatomic_ptr, &realloc_ptr, &strdup_ptr);
1583         xmlMemGet(&free_ptr, &malloc_ptr, &realloc_ptr, &strdup_ptr);
1584         //xmlCleanupParserr();
1585         ShmCache_UseAllocationFunctions();
1586 inshm = 1;
1587         xsltRegisterAllExtras();
1588 #if HAVE_DOMEXSLT
1589         exsltRegisterAll();
1590 #endif
1591         xmlSubstituteEntitiesDefault(1);
1592         xmlLoadExtDtdDefaultValue = 1;
1593
1594         xmlRegisterOutputCallbacks(Stream_MatchWrapper, Stream_XmlWrite_OpenWrapper,
1595                                            Stream_XmlWrite_WriteWrapper, Stream_CloseWrapper);
1596         xsltSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1597         xmlSetGenericErrorFunc(NULL, fastxsl_errorfunc);
1598        
1599         if(FASTXSL_G(register_functions)) {
1600                 xsltRegisterExtModuleFunction ((const xmlChar *) "function",
1601                                            (const xmlChar *) "http://php.net/fastxsl",
1602                                            fastxsl_ext_function);
1603         }
1604         xsltRegisterExtModuleFunction ((const xmlChar *) "cached_document",
1605                                    (const xmlChar *) "http://php.net/fastxsl/cached_document",
1606                                    fastxsl_CachedDocumentFunction);
1607         //xmlCleanupParserr();
1608 inshm = 0;
1609         Xml_UseAllocationFunctions();
1610         return SUCCESS;
1611 }
1612
1613 PHP_MSHUTDOWN_FUNCTION(fastxsl)
1614 {
1615   UNREGISTER_INI_ENTRIES();
1616 }
1617 PHP_RINIT_FUNCTION(fastxsl)
1618 {
1619 #ifdef FASTXSL_MM
1620   /* just in case, set back the allocators */
1621   Xml_UseAllocationFunctions();
1622 #endif
1623 }
1624 PHP_RSHUTDOWN_FUNCTION(fastxsl)
1625 {
1626 #ifdef FASTXSL_MM
1627   /* just in case, set back the allocators */
1628   Xml_UseAllocationFunctions();
1629 #endif
1630 }
1631
1632 PHP_MINFO_FUNCTION(fastxsl)
1633 {
1634         php_info_print_table_start();
1635         php_info_print_table_header(2, "fastxsl support", "enabled");
1636         php_info_print_table_row(2, "libxml Version", LIBXML_DOTTED_VERSION);
1637         php_info_print_table_row(2, "libxslt Version", LIBXSLT_DOTTED_VERSION);
1638 #if HAVE_DOMEXSLT
1639         php_info_print_table_row(2, "libexslt Version", LIBEXSLT_DOTTED_VERSION);
1640 #endif
1641         php_info_print_table_end();
1642 }
Note: See TracBrowser for help on using the browser.