Annotation of embedaddon/php/ext/libxml/libxml.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
                      5:    | Copyright (c) 1997-2012 The PHP Group                                |
                      6:    +----------------------------------------------------------------------+
                      7:    | This source file is subject to version 3.01 of the PHP license,      |
                      8:    | that is bundled with this package in the file LICENSE, and is        |
                      9:    | available through the world-wide-web at the following url:           |
                     10:    | http://www.php.net/license/3_01.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:    | Authors: Shane Caraveo <shane@php.net>                               |
                     16:    |          Wez Furlong <wez@thebrainroom.com>                          |
                     17:    +----------------------------------------------------------------------+
                     18:  */
                     19: 
                     20: /* $Id: libxml.c 321634 2012-01-01 13:15:04Z felipe $ */
                     21: 
                     22: #define IS_EXT_MODULE
                     23: 
                     24: #ifdef HAVE_CONFIG_H
                     25: #include "config.h"
                     26: #endif
                     27: 
                     28: #include "php.h"
                     29: 
                     30: #define PHP_XML_INTERNAL
                     31: #include "zend_variables.h"
                     32: #include "ext/standard/php_string.h"
                     33: #include "ext/standard/info.h"
                     34: #include "ext/standard/file.h"
                     35: 
                     36: #if HAVE_LIBXML
                     37: 
                     38: #include <libxml/parser.h>
                     39: #include <libxml/parserInternals.h>
                     40: #include <libxml/tree.h>
                     41: #include <libxml/uri.h>
                     42: #include <libxml/xmlerror.h>
                     43: #include <libxml/xmlsave.h>
                     44: #ifdef LIBXML_SCHEMAS_ENABLED
                     45: #include <libxml/relaxng.h>
                     46: #endif
                     47: 
                     48: #include "php_libxml.h"
                     49: 
                     50: #define PHP_LIBXML_ERROR 0
                     51: #define PHP_LIBXML_CTX_ERROR 1
                     52: #define PHP_LIBXML_CTX_WARNING 2
                     53: 
                     54: /* a true global for initialization */
                     55: static int _php_libxml_initialized = 0;
                     56: 
                     57: typedef struct _php_libxml_func_handler {
                     58:        php_libxml_export_node export_func;
                     59: } php_libxml_func_handler;
                     60: 
                     61: static HashTable php_libxml_exports;
                     62: 
                     63: static ZEND_DECLARE_MODULE_GLOBALS(libxml)
                     64: static PHP_GINIT_FUNCTION(libxml);
                     65: 
                     66: static PHP_FUNCTION(libxml_set_streams_context);
                     67: static PHP_FUNCTION(libxml_use_internal_errors);
                     68: static PHP_FUNCTION(libxml_get_last_error);
                     69: static PHP_FUNCTION(libxml_clear_errors);
                     70: static PHP_FUNCTION(libxml_get_errors);
                     71: static PHP_FUNCTION(libxml_disable_entity_loader);
                     72: 
                     73: static zend_class_entry *libxmlerror_class_entry;
                     74: 
                     75: /* {{{ dynamically loadable module stuff */
                     76: #ifdef COMPILE_DL_LIBXML
                     77: ZEND_GET_MODULE(libxml)
                     78: #endif /* COMPILE_DL_LIBXML */
                     79: /* }}} */
                     80: 
                     81: /* {{{ function prototypes */
                     82: static PHP_MINIT_FUNCTION(libxml);
                     83: static PHP_RINIT_FUNCTION(libxml);
                     84: static PHP_MSHUTDOWN_FUNCTION(libxml);
                     85: static PHP_RSHUTDOWN_FUNCTION(libxml);
                     86: static PHP_MINFO_FUNCTION(libxml);
                     87: 
                     88: /* }}} */
                     89: 
                     90: /* {{{ arginfo */
                     91: ZEND_BEGIN_ARG_INFO(arginfo_libxml_set_streams_context, 0)
                     92:        ZEND_ARG_INFO(0, context)
                     93: ZEND_END_ARG_INFO()
                     94: 
                     95: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_use_internal_errors, 0, 0, 0)
                     96:        ZEND_ARG_INFO(0, use_errors)
                     97: ZEND_END_ARG_INFO()
                     98: 
                     99: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_last_error, 0)
                    100: ZEND_END_ARG_INFO()
                    101: 
                    102: ZEND_BEGIN_ARG_INFO(arginfo_libxml_get_errors, 0)
                    103: ZEND_END_ARG_INFO()
                    104: 
                    105: ZEND_BEGIN_ARG_INFO(arginfo_libxml_clear_errors, 0)
                    106: ZEND_END_ARG_INFO()
                    107: 
                    108: ZEND_BEGIN_ARG_INFO_EX(arginfo_libxml_disable_entity_loader, 0, 0, 0)
                    109:        ZEND_ARG_INFO(0, disable)
                    110: ZEND_END_ARG_INFO()
                    111: 
                    112: /* }}} */
                    113: 
                    114: /* {{{ extension definition structures */
                    115: static const zend_function_entry libxml_functions[] = {
                    116:        PHP_FE(libxml_set_streams_context, arginfo_libxml_set_streams_context)
                    117:        PHP_FE(libxml_use_internal_errors, arginfo_libxml_use_internal_errors)
                    118:        PHP_FE(libxml_get_last_error, arginfo_libxml_get_last_error)
                    119:        PHP_FE(libxml_clear_errors, arginfo_libxml_clear_errors)
                    120:        PHP_FE(libxml_get_errors, arginfo_libxml_get_errors)
                    121:        PHP_FE(libxml_disable_entity_loader, arginfo_libxml_disable_entity_loader)
                    122:        PHP_FE_END
                    123: };
                    124: 
                    125: zend_module_entry libxml_module_entry = {
                    126:        STANDARD_MODULE_HEADER,
                    127:        "libxml",                /* extension name */
                    128:        libxml_functions,        /* extension function list */
                    129:        PHP_MINIT(libxml),       /* extension-wide startup function */
                    130:        PHP_MSHUTDOWN(libxml),   /* extension-wide shutdown function */
                    131:        PHP_RINIT(libxml),       /* per-request startup function */
                    132:        PHP_RSHUTDOWN(libxml),   /* per-request shutdown function */
                    133:        PHP_MINFO(libxml),       /* information function */
                    134:        NO_VERSION_YET,
                    135:        PHP_MODULE_GLOBALS(libxml), /* globals descriptor */
                    136:        PHP_GINIT(libxml),          /* globals ctor */
                    137:        NULL,                       /* globals dtor */
                    138:        NULL,                       /* post deactivate */
                    139:        STANDARD_MODULE_PROPERTIES_EX
                    140: };
                    141: 
                    142: /* }}} */
                    143: 
                    144: /* {{{ internal functions for interoperability */
                    145: static int php_libxml_clear_object(php_libxml_node_object *object TSRMLS_DC)
                    146: {
                    147:        if (object->properties) {
                    148:                object->properties = NULL;
                    149:        }
                    150:        php_libxml_decrement_node_ptr(object TSRMLS_CC);
                    151:        return php_libxml_decrement_doc_ref(object TSRMLS_CC);
                    152: }
                    153: 
                    154: static int php_libxml_unregister_node(xmlNodePtr nodep TSRMLS_DC)
                    155: {
                    156:        php_libxml_node_object *wrapper;
                    157: 
                    158:        php_libxml_node_ptr *nodeptr = nodep->_private;
                    159: 
                    160:        if (nodeptr != NULL) {
                    161:                wrapper = nodeptr->_private;
                    162:                if (wrapper) {
                    163:                        php_libxml_clear_object(wrapper TSRMLS_CC);
                    164:                } else {
                    165:                        if (nodeptr->node != NULL && nodeptr->node->type != XML_DOCUMENT_NODE) {
                    166:                                nodeptr->node->_private = NULL;
                    167:                        }
                    168:                        nodeptr->node = NULL;
                    169:                }
                    170:        }
                    171: 
                    172:        return -1;
                    173: }
                    174: 
                    175: static void php_libxml_node_free(xmlNodePtr node)
                    176: {
                    177:        if(node) {
                    178:                if (node->_private != NULL) {
                    179:                        ((php_libxml_node_ptr *) node->_private)->node = NULL;
                    180:                }
                    181:                switch (node->type) {
                    182:                        case XML_ATTRIBUTE_NODE:
                    183:                                xmlFreeProp((xmlAttrPtr) node);
                    184:                                break;
                    185:                        case XML_ENTITY_DECL:
                    186:                        case XML_ELEMENT_DECL:
                    187:                        case XML_ATTRIBUTE_DECL:
                    188:                                break;
                    189:                        case XML_NOTATION_NODE:
                    190:                                /* These require special handling */
                    191:                                if (node->name != NULL) {
                    192:                                        xmlFree((char *) node->name);
                    193:                                }
                    194:                                if (((xmlEntityPtr) node)->ExternalID != NULL) {
                    195:                                        xmlFree((char *) ((xmlEntityPtr) node)->ExternalID);
                    196:                                }
                    197:                                if (((xmlEntityPtr) node)->SystemID != NULL) {
                    198:                                        xmlFree((char *) ((xmlEntityPtr) node)->SystemID);
                    199:                                }
                    200:                                xmlFree(node);
                    201:                                break;
                    202:                        case XML_NAMESPACE_DECL:
                    203:                                if (node->ns) {
                    204:                                        xmlFreeNs(node->ns);
                    205:                                        node->ns = NULL;
                    206:                                }
                    207:                                node->type = XML_ELEMENT_NODE;
                    208:                        default:
                    209:                                xmlFreeNode(node);
                    210:                }
                    211:        }
                    212: }
                    213: 
                    214: static void php_libxml_node_free_list(xmlNodePtr node TSRMLS_DC)
                    215: {
                    216:        xmlNodePtr curnode;
                    217: 
                    218:        if (node != NULL) {
                    219:                curnode = node;
                    220:                while (curnode != NULL) {
                    221:                        node = curnode;
                    222:                        switch (node->type) {
                    223:                                /* Skip property freeing for the following types */
                    224:                                case XML_NOTATION_NODE:
                    225:                                case XML_ENTITY_DECL:
                    226:                                        break;
                    227:                                case XML_ENTITY_REF_NODE:
                    228:                                        php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
                    229:                                        break;
                    230:                                case XML_ATTRIBUTE_NODE:
                    231:                                                if ((node->doc != NULL) && (((xmlAttrPtr) node)->atype == XML_ATTRIBUTE_ID)) {
                    232:                                                        xmlRemoveID(node->doc, (xmlAttrPtr) node);
                    233:                                                }
                    234:                                case XML_ATTRIBUTE_DECL:
                    235:                                case XML_DTD_NODE:
                    236:                                case XML_DOCUMENT_TYPE_NODE:
                    237:                                case XML_NAMESPACE_DECL:
                    238:                                case XML_TEXT_NODE:
                    239:                                        php_libxml_node_free_list(node->children TSRMLS_CC);
                    240:                                        break;
                    241:                                default:
                    242:                                        php_libxml_node_free_list(node->children TSRMLS_CC);
                    243:                                        php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
                    244:                        }
                    245: 
                    246:                        curnode = node->next;
                    247:                        xmlUnlinkNode(node);
                    248:                        if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
                    249:                                node->doc = NULL;
                    250:                        }
                    251:                        php_libxml_node_free(node);
                    252:                }
                    253:        }
                    254: }
                    255: 
                    256: /* }}} */
                    257: 
                    258: /* {{{ startup, shutdown and info functions */
                    259: static PHP_GINIT_FUNCTION(libxml)
                    260: {
                    261:        libxml_globals->stream_context = NULL;
                    262:        libxml_globals->error_buffer.c = NULL;
                    263:        libxml_globals->error_list = NULL;
                    264: }
                    265: 
                    266: /* Channel libxml file io layer through the PHP streams subsystem.
                    267:  * This allows use of ftps:// and https:// urls */
                    268: 
                    269: static void *php_libxml_streams_IO_open_wrapper(const char *filename, const char *mode, const int read_only)
                    270: {
                    271:        php_stream_statbuf ssbuf;
                    272:        php_stream_context *context = NULL;
                    273:        php_stream_wrapper *wrapper = NULL;
                    274:        char *resolved_path, *path_to_open = NULL;
                    275:        void *ret_val = NULL;
                    276:        int isescaped=0;
                    277:        xmlURI *uri;
                    278: 
                    279:        TSRMLS_FETCH();
                    280: 
                    281:        uri = xmlParseURI((xmlChar *)filename);
                    282:        if (uri && (uri->scheme == NULL || (xmlStrncmp(uri->scheme, "file", 4) == 0))) {
                    283:                resolved_path = xmlURIUnescapeString(filename, 0, NULL);
                    284:                isescaped = 1;
                    285:        } else {
                    286:                resolved_path = (char *)filename;
                    287:        }
                    288: 
                    289:        if (uri) {
                    290:                xmlFreeURI(uri);
                    291:        }
                    292: 
                    293:        if (resolved_path == NULL) {
                    294:                return NULL;
                    295:        }
                    296: 
                    297:        /* logic copied from _php_stream_stat, but we only want to fail
                    298:           if the wrapper supports stat, otherwise, figure it out from
                    299:           the open.  This logic is only to support hiding warnings
                    300:           that the streams layer puts out at times, but for libxml we
                    301:           may try to open files that don't exist, but it is not a failure
                    302:           in xml processing (eg. DTD files)  */
                    303:        wrapper = php_stream_locate_url_wrapper(resolved_path, &path_to_open, ENFORCE_SAFE_MODE TSRMLS_CC);
                    304:        if (wrapper && read_only && wrapper->wops->url_stat) {
                    305:                if (wrapper->wops->url_stat(wrapper, path_to_open, PHP_STREAM_URL_STAT_QUIET, &ssbuf, NULL TSRMLS_CC) == -1) {
                    306:                        if (isescaped) {
                    307:                                xmlFree(resolved_path);
                    308:                        }
                    309:                        return NULL;
                    310:                }
                    311:        }
                    312: 
                    313:        context = php_stream_context_from_zval(LIBXML(stream_context), 0);
                    314: 
                    315:        ret_val = php_stream_open_wrapper_ex(path_to_open, (char *)mode, ENFORCE_SAFE_MODE|REPORT_ERRORS, NULL, context);
                    316:        if (isescaped) {
                    317:                xmlFree(resolved_path);
                    318:        }
                    319:        return ret_val;
                    320: }
                    321: 
                    322: static void *php_libxml_streams_IO_open_read_wrapper(const char *filename)
                    323: {
                    324:        return php_libxml_streams_IO_open_wrapper(filename, "rb", 1);
                    325: }
                    326: 
                    327: static void *php_libxml_streams_IO_open_write_wrapper(const char *filename)
                    328: {
                    329:        return php_libxml_streams_IO_open_wrapper(filename, "wb", 0);
                    330: }
                    331: 
                    332: static int php_libxml_streams_IO_read(void *context, char *buffer, int len)
                    333: {
                    334:        TSRMLS_FETCH();
                    335:        return php_stream_read((php_stream*)context, buffer, len);
                    336: }
                    337: 
                    338: static int php_libxml_streams_IO_write(void *context, const char *buffer, int len)
                    339: {
                    340:        TSRMLS_FETCH();
                    341:        return php_stream_write((php_stream*)context, buffer, len);
                    342: }
                    343: 
                    344: static int php_libxml_streams_IO_close(void *context)
                    345: {
                    346:        TSRMLS_FETCH();
                    347:        return php_stream_close((php_stream*)context);
                    348: }
                    349: 
                    350: static xmlParserInputBufferPtr
                    351: php_libxml_input_buffer_noload(const char *URI, xmlCharEncoding enc)
                    352: {
                    353:        return NULL;
                    354: }
                    355: 
                    356: static xmlParserInputBufferPtr
                    357: php_libxml_input_buffer_create_filename(const char *URI, xmlCharEncoding enc)
                    358: {
                    359:        xmlParserInputBufferPtr ret;
                    360:        void *context = NULL;
                    361: 
                    362:        if (URI == NULL)
                    363:                return(NULL);
                    364: 
                    365:        context = php_libxml_streams_IO_open_read_wrapper(URI);
                    366: 
                    367:        if (context == NULL) {
                    368:                return(NULL);
                    369:        }
                    370: 
                    371:        /* Allocate the Input buffer front-end. */
                    372:        ret = xmlAllocParserInputBuffer(enc);
                    373:        if (ret != NULL) {
                    374:                ret->context = context;
                    375:                ret->readcallback = php_libxml_streams_IO_read;
                    376:                ret->closecallback = php_libxml_streams_IO_close;
                    377:        } else
                    378:                php_libxml_streams_IO_close(context);
                    379: 
                    380:        return(ret);
                    381: }
                    382: 
                    383: static xmlOutputBufferPtr
                    384: php_libxml_output_buffer_create_filename(const char *URI,
                    385:                               xmlCharEncodingHandlerPtr encoder,
                    386:                               int compression ATTRIBUTE_UNUSED)
                    387: {
                    388:        xmlOutputBufferPtr ret;
                    389:        xmlURIPtr puri;
                    390:        void *context = NULL;
                    391:        char *unescaped = NULL;
                    392: 
                    393:        if (URI == NULL)
                    394:                return(NULL);
                    395: 
                    396:        puri = xmlParseURI(URI);
                    397:        if (puri != NULL) {
                    398:                if (puri->scheme != NULL)
                    399:                        unescaped = xmlURIUnescapeString(URI, 0, NULL);
                    400:                xmlFreeURI(puri);
                    401:        }
                    402: 
                    403:        if (unescaped != NULL) {
                    404:                context = php_libxml_streams_IO_open_write_wrapper(unescaped);
                    405:                xmlFree(unescaped);
                    406:        }
                    407: 
                    408:        /* try with a non-escaped URI this may be a strange filename */
                    409:        if (context == NULL) {
                    410:                context = php_libxml_streams_IO_open_write_wrapper(URI);
                    411:        }
                    412: 
                    413:        if (context == NULL) {
                    414:                return(NULL);
                    415:        }
                    416: 
                    417:        /* Allocate the Output buffer front-end. */
                    418:        ret = xmlAllocOutputBuffer(encoder);
                    419:        if (ret != NULL) {
                    420:                ret->context = context;
                    421:                ret->writecallback = php_libxml_streams_IO_write;
                    422:                ret->closecallback = php_libxml_streams_IO_close;
                    423:        }
                    424: 
                    425:        return(ret);
                    426: }
                    427: 
                    428: static int _php_libxml_free_error(xmlErrorPtr error)
                    429: {
                    430:        /* This will free the libxml alloc'd memory */
                    431:        xmlResetError(error);
                    432:        return 1;
                    433: }
                    434: 
                    435: static void _php_list_set_error_structure(xmlErrorPtr error, const char *msg)
                    436: {
                    437:        xmlError error_copy;
                    438:        int ret;
                    439: 
                    440:        TSRMLS_FETCH();
                    441: 
                    442:        memset(&error_copy, 0, sizeof(xmlError));
                    443: 
                    444:        if (error) {
                    445:                ret = xmlCopyError(error, &error_copy);
                    446:        } else {
                    447:                error_copy.domain = 0;
                    448:                error_copy.code = XML_ERR_INTERNAL_ERROR;
                    449:                error_copy.level = XML_ERR_ERROR;
                    450:                error_copy.line = 0;
                    451:                error_copy.node = NULL;
                    452:                error_copy.int1 = 0;
                    453:                error_copy.int2 = 0;
                    454:                error_copy.ctxt = NULL;
                    455:                error_copy.message = xmlStrdup(msg);
                    456:                error_copy.file = NULL;
                    457:                error_copy.str1 = NULL;
                    458:                error_copy.str2 = NULL;
                    459:                error_copy.str3 = NULL;
                    460:                ret = 0;
                    461:        }
                    462: 
                    463:        if (ret == 0) {
                    464:                zend_llist_add_element(LIBXML(error_list), &error_copy);
                    465:        }
                    466: }
                    467: 
                    468: static void php_libxml_ctx_error_level(int level, void *ctx, const char *msg TSRMLS_DC)
                    469: {
                    470:        xmlParserCtxtPtr parser;
                    471: 
                    472:        parser = (xmlParserCtxtPtr) ctx;
                    473: 
                    474:        if (parser != NULL && parser->input != NULL) {
                    475:                if (parser->input->filename) {
                    476:                        php_error_docref(NULL TSRMLS_CC, level, "%s in %s, line: %d", msg, parser->input->filename, parser->input->line);
                    477:                } else {
                    478:                        php_error_docref(NULL TSRMLS_CC, level, "%s in Entity, line: %d", msg, parser->input->line);
                    479:                }
                    480:        }
                    481: }
                    482: 
                    483: void php_libxml_issue_error(int level, const char *msg TSRMLS_DC)
                    484: {
                    485:        if (LIBXML(error_list)) {
                    486:                _php_list_set_error_structure(NULL, msg);
                    487:        } else {
                    488:                php_error_docref(NULL TSRMLS_CC, level, "%s", msg);
                    489:        }
                    490: }
                    491: 
                    492: static void php_libxml_internal_error_handler(int error_type, void *ctx, const char **msg, va_list ap)
                    493: {
                    494:        char *buf;
                    495:        int len, len_iter, output = 0;
                    496: 
                    497:        TSRMLS_FETCH();
                    498: 
                    499:        len = vspprintf(&buf, 0, *msg, ap);
                    500:        len_iter = len;
                    501: 
                    502:        /* remove any trailing \n */
                    503:        while (len_iter && buf[--len_iter] == '\n') {
                    504:                buf[len_iter] = '\0';
                    505:                output = 1;
                    506:        }
                    507: 
                    508:        smart_str_appendl(&LIBXML(error_buffer), buf, len);
                    509: 
                    510:        efree(buf);
                    511: 
                    512:        if (output == 1) {
                    513:                if (LIBXML(error_list)) {
                    514:                        _php_list_set_error_structure(NULL, LIBXML(error_buffer).c);
                    515:                } else {
                    516:                        switch (error_type) {
                    517:                                case PHP_LIBXML_CTX_ERROR:
                    518:                                        php_libxml_ctx_error_level(E_WARNING, ctx, LIBXML(error_buffer).c TSRMLS_CC);
                    519:                                        break;
                    520:                                case PHP_LIBXML_CTX_WARNING:
                    521:                                        php_libxml_ctx_error_level(E_NOTICE, ctx, LIBXML(error_buffer).c TSRMLS_CC);
                    522:                                        break;
                    523:                                default:
                    524:                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", LIBXML(error_buffer).c);
                    525:                        }
                    526:                }
                    527:                smart_str_free(&LIBXML(error_buffer));
                    528:        }
                    529: }
                    530: 
                    531: PHP_LIBXML_API void php_libxml_ctx_error(void *ctx, const char *msg, ...)
                    532: {
                    533:        va_list args;
                    534:        va_start(args, msg);
                    535:        php_libxml_internal_error_handler(PHP_LIBXML_CTX_ERROR, ctx, &msg, args);
                    536:        va_end(args);
                    537: }
                    538: 
                    539: PHP_LIBXML_API void php_libxml_ctx_warning(void *ctx, const char *msg, ...)
                    540: {
                    541:        va_list args;
                    542:        va_start(args, msg);
                    543:        php_libxml_internal_error_handler(PHP_LIBXML_CTX_WARNING, ctx, &msg, args);
                    544:        va_end(args);
                    545: }
                    546: 
                    547: PHP_LIBXML_API void php_libxml_structured_error_handler(void *userData, xmlErrorPtr error)
                    548: {
                    549:        _php_list_set_error_structure(error, NULL);
                    550: 
                    551:        return;
                    552: }
                    553: 
                    554: PHP_LIBXML_API void php_libxml_error_handler(void *ctx, const char *msg, ...)
                    555: {
                    556:        va_list args;
                    557:        va_start(args, msg);
                    558:        php_libxml_internal_error_handler(PHP_LIBXML_ERROR, ctx, &msg, args);
                    559:        va_end(args);
                    560: }
                    561: 
                    562: 
                    563: PHP_LIBXML_API void php_libxml_initialize(void)
                    564: {
                    565:        if (!_php_libxml_initialized) {
                    566:                /* we should be the only one's to ever init!! */
                    567:                xmlInitParser();
                    568: 
                    569:                zend_hash_init(&php_libxml_exports, 0, NULL, NULL, 1);
                    570: 
                    571:                _php_libxml_initialized = 1;
                    572:        }
                    573: }
                    574: 
                    575: PHP_LIBXML_API void php_libxml_shutdown(void)
                    576: {
                    577:        if (_php_libxml_initialized) {
                    578: #if defined(LIBXML_SCHEMAS_ENABLED)
                    579:                xmlRelaxNGCleanupTypes();
                    580: #endif
                    581:                xmlCleanupParser();
                    582:                zend_hash_destroy(&php_libxml_exports);
                    583:                _php_libxml_initialized = 0;
                    584:        }
                    585: }
                    586: 
                    587: PHP_LIBXML_API zval *php_libxml_switch_context(zval *context TSRMLS_DC)
                    588: {
                    589:        zval *oldcontext;
                    590: 
                    591:        oldcontext = LIBXML(stream_context);
                    592:        LIBXML(stream_context) = context;
                    593:        return oldcontext;
                    594: 
                    595: }
                    596: 
                    597: static PHP_MINIT_FUNCTION(libxml)
                    598: {
                    599:        zend_class_entry ce;
                    600: 
                    601:        php_libxml_initialize();
                    602: 
                    603:        REGISTER_LONG_CONSTANT("LIBXML_VERSION",                        LIBXML_VERSION,                 CONST_CS | CONST_PERSISTENT);
                    604:        REGISTER_STRING_CONSTANT("LIBXML_DOTTED_VERSION",       LIBXML_DOTTED_VERSION,  CONST_CS | CONST_PERSISTENT);
                    605:        REGISTER_STRING_CONSTANT("LIBXML_LOADED_VERSION",       (char *)xmlParserVersion,               CONST_CS | CONST_PERSISTENT);
                    606: 
                    607:        /* For use with loading xml */
                    608:        REGISTER_LONG_CONSTANT("LIBXML_NOENT",          XML_PARSE_NOENT,                CONST_CS | CONST_PERSISTENT);
                    609:        REGISTER_LONG_CONSTANT("LIBXML_DTDLOAD",        XML_PARSE_DTDLOAD,              CONST_CS | CONST_PERSISTENT);
                    610:        REGISTER_LONG_CONSTANT("LIBXML_DTDATTR",        XML_PARSE_DTDATTR,              CONST_CS | CONST_PERSISTENT);
                    611:        REGISTER_LONG_CONSTANT("LIBXML_DTDVALID",       XML_PARSE_DTDVALID,             CONST_CS | CONST_PERSISTENT);
                    612:        REGISTER_LONG_CONSTANT("LIBXML_NOERROR",        XML_PARSE_NOERROR,              CONST_CS | CONST_PERSISTENT);
                    613:        REGISTER_LONG_CONSTANT("LIBXML_NOWARNING",      XML_PARSE_NOWARNING,    CONST_CS | CONST_PERSISTENT);
                    614:        REGISTER_LONG_CONSTANT("LIBXML_NOBLANKS",       XML_PARSE_NOBLANKS,             CONST_CS | CONST_PERSISTENT);
                    615:        REGISTER_LONG_CONSTANT("LIBXML_XINCLUDE",       XML_PARSE_XINCLUDE,             CONST_CS | CONST_PERSISTENT);
                    616:        REGISTER_LONG_CONSTANT("LIBXML_NSCLEAN",        XML_PARSE_NSCLEAN,              CONST_CS | CONST_PERSISTENT);
                    617:        REGISTER_LONG_CONSTANT("LIBXML_NOCDATA",        XML_PARSE_NOCDATA,              CONST_CS | CONST_PERSISTENT);
                    618:        REGISTER_LONG_CONSTANT("LIBXML_NONET",          XML_PARSE_NONET,                CONST_CS | CONST_PERSISTENT);
                    619: #if LIBXML_VERSION >= 20621
                    620:        REGISTER_LONG_CONSTANT("LIBXML_COMPACT",        XML_PARSE_COMPACT,              CONST_CS | CONST_PERSISTENT);
                    621:        REGISTER_LONG_CONSTANT("LIBXML_NOXMLDECL",      XML_SAVE_NO_DECL,               CONST_CS | CONST_PERSISTENT);
                    622: #endif
                    623: #if LIBXML_VERSION >= 20703
                    624:        REGISTER_LONG_CONSTANT("LIBXML_PARSEHUGE",      XML_PARSE_HUGE,                 CONST_CS | CONST_PERSISTENT);
                    625: #endif
                    626:        REGISTER_LONG_CONSTANT("LIBXML_NOEMPTYTAG",     LIBXML_SAVE_NOEMPTYTAG, CONST_CS | CONST_PERSISTENT);
                    627: 
                    628:        /* Error levels */
                    629:        REGISTER_LONG_CONSTANT("LIBXML_ERR_NONE",               XML_ERR_NONE,           CONST_CS | CONST_PERSISTENT);
                    630:        REGISTER_LONG_CONSTANT("LIBXML_ERR_WARNING",    XML_ERR_WARNING,        CONST_CS | CONST_PERSISTENT);
                    631:        REGISTER_LONG_CONSTANT("LIBXML_ERR_ERROR",              XML_ERR_ERROR,          CONST_CS | CONST_PERSISTENT);
                    632:        REGISTER_LONG_CONSTANT("LIBXML_ERR_FATAL",              XML_ERR_FATAL,          CONST_CS | CONST_PERSISTENT);
                    633: 
                    634:        INIT_CLASS_ENTRY(ce, "LibXMLError", NULL);
                    635:        libxmlerror_class_entry = zend_register_internal_class(&ce TSRMLS_CC);
                    636: 
                    637:        return SUCCESS;
                    638: }
                    639: 
                    640: 
                    641: static PHP_RINIT_FUNCTION(libxml)
                    642: {
                    643:        /* report errors via handler rather than stderr */
                    644:        xmlSetGenericErrorFunc(NULL, php_libxml_error_handler);
                    645:        xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
                    646:        xmlOutputBufferCreateFilenameDefault(php_libxml_output_buffer_create_filename);
                    647:        return SUCCESS;
                    648: }
                    649: 
                    650: 
                    651: static PHP_MSHUTDOWN_FUNCTION(libxml)
                    652: {
                    653:        php_libxml_shutdown();
                    654: 
                    655:        return SUCCESS;
                    656: }
                    657: 
                    658: 
                    659: static PHP_RSHUTDOWN_FUNCTION(libxml)
                    660: {
                    661:        /* reset libxml generic error handling */
                    662:        xmlSetGenericErrorFunc(NULL, NULL);
                    663:        xmlSetStructuredErrorFunc(NULL, NULL);
                    664: 
                    665:        xmlParserInputBufferCreateFilenameDefault(NULL);
                    666:        xmlOutputBufferCreateFilenameDefault(NULL);
                    667: 
                    668:        if (LIBXML(stream_context)) {
                    669:                zval_ptr_dtor(&LIBXML(stream_context));
                    670:                LIBXML(stream_context) = NULL;
                    671:        }
                    672:        smart_str_free(&LIBXML(error_buffer));
                    673:        if (LIBXML(error_list)) {
                    674:                zend_llist_destroy(LIBXML(error_list));
                    675:                efree(LIBXML(error_list));
                    676:                LIBXML(error_list) = NULL;
                    677:        }
                    678:        xmlResetLastError();
                    679: 
                    680:        return SUCCESS;
                    681: }
                    682: 
                    683: 
                    684: static PHP_MINFO_FUNCTION(libxml)
                    685: {
                    686:        php_info_print_table_start();
                    687:        php_info_print_table_row(2, "libXML support", "active");
                    688:        php_info_print_table_row(2, "libXML Compiled Version", LIBXML_DOTTED_VERSION);
                    689:        php_info_print_table_row(2, "libXML Loaded Version", (char *)xmlParserVersion);
                    690:        php_info_print_table_row(2, "libXML streams", "enabled");
                    691:        php_info_print_table_end();
                    692: }
                    693: /* }}} */
                    694: 
                    695: /* {{{ proto void libxml_set_streams_context(resource streams_context) 
                    696:    Set the streams context for the next libxml document load or write */
                    697: static PHP_FUNCTION(libxml_set_streams_context)
                    698: {
                    699:        zval *arg;
                    700: 
                    701:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
                    702:                return;
                    703:        }
                    704:        if (LIBXML(stream_context)) {
                    705:                zval_ptr_dtor(&LIBXML(stream_context));
                    706:                LIBXML(stream_context) = NULL;
                    707:        }
                    708:        Z_ADDREF_P(arg);
                    709:        LIBXML(stream_context) = arg;
                    710: }
                    711: /* }}} */
                    712: 
                    713: /* {{{ proto bool libxml_use_internal_errors([boolean use_errors]) 
                    714:    Disable libxml errors and allow user to fetch error information as needed */
                    715: static PHP_FUNCTION(libxml_use_internal_errors)
                    716: {
                    717:        xmlStructuredErrorFunc current_handler;
                    718:        zend_bool use_errors=0, retval;
                    719: 
                    720:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &use_errors) == FAILURE) {
                    721:                return;
                    722:        }
                    723: 
                    724:        current_handler = xmlStructuredError;
                    725:        if (current_handler && current_handler == php_libxml_structured_error_handler) {
                    726:                retval = 1;
                    727:        } else {
                    728:                retval = 0;
                    729:        }
                    730: 
                    731:        if (ZEND_NUM_ARGS() == 0) {
                    732:                RETURN_BOOL(retval);
                    733:        }
                    734: 
                    735:        if (use_errors == 0) {
                    736:                xmlSetStructuredErrorFunc(NULL, NULL);
                    737:                if (LIBXML(error_list)) {
                    738:                        zend_llist_destroy(LIBXML(error_list));
                    739:                        efree(LIBXML(error_list));
                    740:                        LIBXML(error_list) = NULL;
                    741:                }
                    742:        } else {
                    743:                xmlSetStructuredErrorFunc(NULL, php_libxml_structured_error_handler);
                    744:                if (LIBXML(error_list) == NULL) {
                    745:                        LIBXML(error_list) = (zend_llist *) emalloc(sizeof(zend_llist));
                    746:                        zend_llist_init(LIBXML(error_list), sizeof(xmlError), (llist_dtor_func_t) _php_libxml_free_error, 0);
                    747:                }
                    748:        }
                    749:        RETURN_BOOL(retval);
                    750: }
                    751: /* }}} */
                    752: 
                    753: /* {{{ proto object libxml_get_last_error() 
                    754:    Retrieve last error from libxml */
                    755: static PHP_FUNCTION(libxml_get_last_error)
                    756: {
                    757:        xmlErrorPtr error;
                    758: 
                    759:        error = xmlGetLastError();
                    760:        
                    761:        if (error) {
                    762:                object_init_ex(return_value, libxmlerror_class_entry);
                    763:                add_property_long(return_value, "level", error->level);
                    764:                add_property_long(return_value, "code", error->code);
                    765:                add_property_long(return_value, "column", error->int2);
                    766:                if (error->message) {
                    767:                        add_property_string(return_value, "message", error->message, 1);
                    768:                } else {
                    769:                        add_property_stringl(return_value, "message", "", 0, 1);
                    770:                }
                    771:                if (error->file) {
                    772:                        add_property_string(return_value, "file", error->file, 1);
                    773:                } else {
                    774:                        add_property_stringl(return_value, "file", "", 0, 1);
                    775:                }
                    776:                add_property_long(return_value, "line", error->line);
                    777:        } else {
                    778:                RETURN_FALSE;
                    779:        }
                    780: }
                    781: /* }}} */
                    782: 
                    783: /* {{{ proto object libxml_get_errors()
                    784:    Retrieve array of errors */
                    785: static PHP_FUNCTION(libxml_get_errors)
                    786: {
                    787:        
                    788:        xmlErrorPtr error;
                    789: 
                    790:        if (array_init(return_value) == FAILURE) {
                    791:                RETURN_FALSE;
                    792:        }
                    793: 
                    794:        if (LIBXML(error_list)) {
                    795: 
                    796:                error = zend_llist_get_first(LIBXML(error_list));
                    797: 
                    798:                while (error != NULL) {
                    799:                        zval *z_error;
                    800:                        MAKE_STD_ZVAL(z_error);
                    801: 
                    802:                        object_init_ex(z_error, libxmlerror_class_entry);
                    803:                        add_property_long(z_error, "level", error->level);
                    804:                        add_property_long(z_error, "code", error->code);
                    805:                        add_property_long(z_error, "column", error->int2);
                    806:                        if (error->message) {
                    807:                                add_property_string(z_error, "message", error->message, 1);
                    808:                        } else {
                    809:                                add_property_stringl(z_error, "message", "", 0, 1);
                    810:                        }
                    811:                        if (error->file) {
                    812:                                add_property_string(z_error, "file", error->file, 1);
                    813:                        } else {
                    814:                                add_property_stringl(z_error, "file", "", 0, 1);
                    815:                        }
                    816:                        add_property_long(z_error, "line", error->line);
                    817:                        add_next_index_zval(return_value, z_error);
                    818: 
                    819:                        error = zend_llist_get_next(LIBXML(error_list));
                    820:                }
                    821:        }
                    822: }
                    823: /* }}} */
                    824: 
                    825: /* {{{ proto void libxml_clear_errors() 
                    826:    Clear last error from libxml */
                    827: static PHP_FUNCTION(libxml_clear_errors)
                    828: {
                    829:        xmlResetLastError();
                    830:        if (LIBXML(error_list)) {
                    831:                zend_llist_clean(LIBXML(error_list));
                    832:        }
                    833: }
                    834: /* }}} */
                    835: 
                    836: /* {{{ proto bool libxml_disable_entity_loader([boolean disable]) 
                    837:    Disable/Enable ability to load external entities */
                    838: static PHP_FUNCTION(libxml_disable_entity_loader)
                    839: {
                    840:        zend_bool disable = 1;
                    841:        xmlParserInputBufferCreateFilenameFunc old;
                    842: 
                    843:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &disable) == FAILURE) {
                    844:                return;
                    845:        }
                    846: 
                    847:        if (disable == 0) {
                    848:                old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_create_filename);
                    849:        } else {
                    850:                old = xmlParserInputBufferCreateFilenameDefault(php_libxml_input_buffer_noload);
                    851:        }
                    852: 
                    853:        if (old == php_libxml_input_buffer_noload) {
                    854:                RETURN_TRUE;
                    855:        }
                    856: 
                    857:        RETURN_FALSE;
                    858: }
                    859: /* }}} */
                    860: 
                    861: /* {{{ Common functions shared by extensions */
                    862: int php_libxml_xmlCheckUTF8(const unsigned char *s)
                    863: {
                    864:        int i;
                    865:        unsigned char c;
                    866: 
                    867:        for (i = 0; (c = s[i++]);) {
                    868:                if ((c & 0x80) == 0) {
                    869:                } else if ((c & 0xe0) == 0xc0) {
                    870:                        if ((s[i++] & 0xc0) != 0x80) {
                    871:                                return 0;
                    872:                        }
                    873:                } else if ((c & 0xf0) == 0xe0) {
                    874:                        if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
                    875:                                return 0;
                    876:                        }
                    877:                } else if ((c & 0xf8) == 0xf0) {
                    878:                        if ((s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80 || (s[i++] & 0xc0) != 0x80) {
                    879:                                return 0;
                    880:                        }
                    881:                } else {
                    882:                        return 0;
                    883:                }
                    884:        }
                    885:        return 1;
                    886: }
                    887: 
                    888: int php_libxml_register_export(zend_class_entry *ce, php_libxml_export_node export_function)
                    889: {
                    890:        php_libxml_func_handler export_hnd;
                    891:        
                    892:        /* Initialize in case this module hasnt been loaded yet */
                    893:        php_libxml_initialize();
                    894:        export_hnd.export_func = export_function;
                    895: 
                    896:        return zend_hash_add(&php_libxml_exports, ce->name, ce->name_length + 1, &export_hnd, sizeof(export_hnd), NULL);
                    897: }
                    898: 
                    899: PHP_LIBXML_API xmlNodePtr php_libxml_import_node(zval *object TSRMLS_DC)
                    900: {
                    901:        zend_class_entry *ce = NULL;
                    902:        xmlNodePtr node = NULL;
                    903:        php_libxml_func_handler *export_hnd;
                    904: 
                    905:        if (object->type == IS_OBJECT) {
                    906:                ce = Z_OBJCE_P(object);
                    907:                while (ce->parent != NULL) {
                    908:                        ce = ce->parent;
                    909:                }
                    910:                if (zend_hash_find(&php_libxml_exports, ce->name, ce->name_length + 1, (void **) &export_hnd)  == SUCCESS) {
                    911:                        node = export_hnd->export_func(object TSRMLS_CC);
                    912:                }
                    913:        }
                    914:        return node;
                    915: }
                    916: 
                    917: PHP_LIBXML_API int php_libxml_increment_node_ptr(php_libxml_node_object *object, xmlNodePtr node, void *private_data TSRMLS_DC)
                    918: {
                    919:        int ret_refcount = -1;
                    920: 
                    921:        if (object != NULL && node != NULL) {
                    922:                if (object->node != NULL) {
                    923:                        if (object->node->node == node) {
                    924:                                return object->node->refcount;
                    925:                        } else {
                    926:                                php_libxml_decrement_node_ptr(object TSRMLS_CC);
                    927:                        }
                    928:                }
                    929:                if (node->_private != NULL) {
                    930:                        object->node = node->_private;
                    931:                        ret_refcount = ++object->node->refcount;
                    932:                        /* Only dom uses _private */
                    933:                        if (object->node->_private == NULL) {
                    934:                                object->node->_private = private_data;
                    935:                        }
                    936:                } else {
                    937:                        ret_refcount = 1;
                    938:                        object->node = emalloc(sizeof(php_libxml_node_ptr));
                    939:                        object->node->node = node;
                    940:                        object->node->refcount = 1;
                    941:                        object->node->_private = private_data;
                    942:                        node->_private = object->node;
                    943:                }
                    944:        }
                    945: 
                    946:        return ret_refcount;
                    947: }
                    948: 
                    949: PHP_LIBXML_API int php_libxml_decrement_node_ptr(php_libxml_node_object *object TSRMLS_DC)
                    950: {
                    951:        int ret_refcount = -1;
                    952:        php_libxml_node_ptr *obj_node;
                    953: 
                    954:        if (object != NULL && object->node != NULL) {
                    955:                obj_node = (php_libxml_node_ptr *) object->node;
                    956:                ret_refcount = --obj_node->refcount;
                    957:                if (ret_refcount == 0) {
                    958:                        if (obj_node->node != NULL) {
                    959:                                obj_node->node->_private = NULL;
                    960:                        }
                    961:                        efree(obj_node);
                    962:                } 
                    963:                object->node = NULL;
                    964:        }
                    965: 
                    966:        return ret_refcount;
                    967: }
                    968: 
                    969: PHP_LIBXML_API int php_libxml_increment_doc_ref(php_libxml_node_object *object, xmlDocPtr docp TSRMLS_DC)
                    970: {
                    971:        int ret_refcount = -1;
                    972: 
                    973:        if (object->document != NULL) {
                    974:                object->document->refcount++;
                    975:                ret_refcount = object->document->refcount;
                    976:        } else if (docp != NULL) {
                    977:                ret_refcount = 1;
                    978:                object->document = emalloc(sizeof(php_libxml_ref_obj));
                    979:                object->document->ptr = docp;
                    980:                object->document->refcount = ret_refcount;
                    981:                object->document->doc_props = NULL;
                    982:        }
                    983: 
                    984:        return ret_refcount;
                    985: }
                    986: 
                    987: PHP_LIBXML_API int php_libxml_decrement_doc_ref(php_libxml_node_object *object TSRMLS_DC)
                    988: {
                    989:        int ret_refcount = -1;
                    990: 
                    991:        if (object != NULL && object->document != NULL) {
                    992:                ret_refcount = --object->document->refcount;
                    993:                if (ret_refcount == 0) {
                    994:                        if (object->document->ptr != NULL) {
                    995:                                xmlFreeDoc((xmlDoc *) object->document->ptr);
                    996:                        }
                    997:                        if (object->document->doc_props != NULL) {
                    998:                                if (object->document->doc_props->classmap) {
                    999:                                        zend_hash_destroy(object->document->doc_props->classmap);
                   1000:                                        FREE_HASHTABLE(object->document->doc_props->classmap);
                   1001:                                }
                   1002:                                efree(object->document->doc_props);
                   1003:                        }
                   1004:                        efree(object->document);
                   1005:                        object->document = NULL;
                   1006:                }
                   1007:        }
                   1008: 
                   1009:        return ret_refcount;
                   1010: }
                   1011: 
                   1012: PHP_LIBXML_API void php_libxml_node_free_resource(xmlNodePtr node TSRMLS_DC)
                   1013: {
                   1014:        if (!node) {
                   1015:                return;
                   1016:        }
                   1017: 
                   1018:        switch (node->type) {
                   1019:                case XML_DOCUMENT_NODE:
                   1020:                case XML_HTML_DOCUMENT_NODE:
                   1021:                        break;
                   1022:                default:
                   1023:                        if (node->parent == NULL || node->type == XML_NAMESPACE_DECL) {
                   1024:                                php_libxml_node_free_list((xmlNodePtr) node->children TSRMLS_CC);
                   1025:                                switch (node->type) {
                   1026:                                        /* Skip property freeing for the following types */
                   1027:                                        case XML_ATTRIBUTE_DECL:
                   1028:                                        case XML_DTD_NODE:
                   1029:                                        case XML_DOCUMENT_TYPE_NODE:
                   1030:                                        case XML_ENTITY_DECL:
                   1031:                                        case XML_ATTRIBUTE_NODE:
                   1032:                                        case XML_NAMESPACE_DECL:
                   1033:                                        case XML_TEXT_NODE:
                   1034:                                                break;
                   1035:                                        default:
                   1036:                                                php_libxml_node_free_list((xmlNodePtr) node->properties TSRMLS_CC);
                   1037:                                }
                   1038:                                if (php_libxml_unregister_node(node TSRMLS_CC) == 0) {
                   1039:                                        node->doc = NULL;
                   1040:                                }
                   1041:                                php_libxml_node_free(node);
                   1042:                        } else {
                   1043:                                php_libxml_unregister_node(node TSRMLS_CC);
                   1044:                        }
                   1045:        }
                   1046: }
                   1047: 
                   1048: PHP_LIBXML_API void php_libxml_node_decrement_resource(php_libxml_node_object *object TSRMLS_DC)
                   1049: {
                   1050:        int ret_refcount = -1;
                   1051:        xmlNodePtr nodep;
                   1052:        php_libxml_node_ptr *obj_node;
                   1053: 
                   1054:        if (object != NULL && object->node != NULL) {
                   1055:                obj_node = (php_libxml_node_ptr *) object->node;
                   1056:                nodep = object->node->node;
                   1057:                ret_refcount = php_libxml_decrement_node_ptr(object TSRMLS_CC);
                   1058:                if (ret_refcount == 0) {
                   1059:                        php_libxml_node_free_resource(nodep TSRMLS_CC);
                   1060:                } else {
                   1061:                        if (obj_node && object == obj_node->_private) {
                   1062:                                obj_node->_private = NULL;
                   1063:                        }
                   1064:                }
                   1065:        }
                   1066:        if (object != NULL && object->document != NULL) {
                   1067:                /* Safe to call as if the resource were freed then doc pointer is NULL */
                   1068:                php_libxml_decrement_doc_ref(object TSRMLS_CC);
                   1069:        }
                   1070: }
                   1071: /* }}} */
                   1072: 
                   1073: #ifdef PHP_WIN32
                   1074: PHP_LIBXML_API BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
                   1075: {
                   1076:        return xmlDllMain(hinstDLL, fdwReason, lpvReserved);
                   1077: }
                   1078: #endif
                   1079: 
                   1080: #endif
                   1081: 
                   1082: /*
                   1083:  * Local variables:
                   1084:  * tab-width: 4
                   1085:  * c-basic-offset: 4
                   1086:  * End:
                   1087:  * vim600: sw=4 ts=4 fdm=marker
                   1088:  * vim<600: sw=4 ts=4
                   1089:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>