root/ext/dom/xpath.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dom_xpath_ext_function_php
  2. dom_xpath_ext_function_string_php
  3. dom_xpath_ext_function_object_php
  4. PHP_METHOD
  5. dom_xpath_document_read
  6. PHP_FUNCTION
  7. dom_xpath_iter
  8. php_xpath_eval
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 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: Christian Stocker <chregu@php.net>                          |
  16    |          Rob Richards <rrichards@php.net>                            |
  17    +----------------------------------------------------------------------+
  18 */
  19 
  20 /* $Id$ */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include "config.h"
  24 #endif
  25 
  26 #include "php.h"
  27 #if HAVE_LIBXML && HAVE_DOM
  28 #include "php_dom.h"
  29 
  30 #define PHP_DOM_XPATH_QUERY 0
  31 #define PHP_DOM_XPATH_EVALUATE 1
  32 
  33 /*
  34 * class DOMXPath
  35 */
  36 
  37 #if defined(LIBXML_XPATH_ENABLED)
  38 
  39 /* {{{ arginfo */
  40 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_xpath_construct, 0, 0, 1)
  41         ZEND_ARG_OBJ_INFO(0, doc, DOMDocument, 0)
  42 ZEND_END_ARG_INFO();
  43 
  44 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_xpath_register_ns, 0, 0, 2)
  45         ZEND_ARG_INFO(0, prefix)
  46         ZEND_ARG_INFO(0, uri)
  47 ZEND_END_ARG_INFO();
  48 
  49 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_xpath_query, 0, 0, 1)
  50         ZEND_ARG_INFO(0, expr)
  51         ZEND_ARG_OBJ_INFO(0, context, DOMNode, 1)
  52         ZEND_ARG_INFO(0, registerNodeNS)
  53 ZEND_END_ARG_INFO();
  54 
  55 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_xpath_evaluate, 0, 0, 1)
  56         ZEND_ARG_INFO(0, expr)
  57         ZEND_ARG_OBJ_INFO(0, context, DOMNode, 1)
  58         ZEND_ARG_INFO(0, registerNodeNS)
  59 ZEND_END_ARG_INFO();
  60 
  61 ZEND_BEGIN_ARG_INFO_EX(arginfo_dom_xpath_register_php_functions, 0, 0, 0)
  62 ZEND_END_ARG_INFO();
  63 /* }}} */
  64 
  65 const zend_function_entry php_dom_xpath_class_functions[] = {
  66         PHP_ME(domxpath, __construct, arginfo_dom_xpath_construct, ZEND_ACC_PUBLIC)
  67         PHP_FALIAS(registerNamespace, dom_xpath_register_ns, arginfo_dom_xpath_register_ns)
  68         PHP_FALIAS(query, dom_xpath_query, arginfo_dom_xpath_query)
  69         PHP_FALIAS(evaluate, dom_xpath_evaluate, arginfo_dom_xpath_evaluate)
  70         PHP_FALIAS(registerPhpFunctions, dom_xpath_register_php_functions, arginfo_dom_xpath_register_php_functions)
  71         PHP_FE_END
  72 };
  73 
  74 
  75 static void dom_xpath_ext_function_php(xmlXPathParserContextPtr ctxt, int nargs, int type) /* {{{ */
  76 {
  77         zval retval;
  78         int result, i;
  79         int error = 0;
  80         zend_fcall_info fci;
  81         xmlXPathObjectPtr obj;
  82         char *str;
  83         zend_string *callable = NULL;
  84         dom_xpath_object *intern;
  85 
  86 
  87         if (! zend_is_executing()) {
  88                 xmlGenericError(xmlGenericErrorContext,
  89                 "xmlExtFunctionTest: Function called from outside of PHP\n");
  90                 error = 1;
  91         } else {
  92                 intern = (dom_xpath_object *) ctxt->context->userData;
  93                 if (intern == NULL) {
  94                         xmlGenericError(xmlGenericErrorContext,
  95                         "xmlExtFunctionTest: failed to get the internal object\n");
  96                         error = 1;
  97                 }
  98                 else if (intern->registerPhpFunctions == 0) {
  99                         xmlGenericError(xmlGenericErrorContext,
 100                         "xmlExtFunctionTest: PHP Object did not register PHP functions\n");
 101                         error = 1;
 102                 }
 103         }
 104 
 105         if (error == 1) {
 106                 for (i = nargs - 1; i >= 0; i--) {
 107                         obj = valuePop(ctxt);
 108                         xmlXPathFreeObject(obj);
 109                 }
 110                 return;
 111         }
 112 
 113         fci.param_count = nargs - 1;
 114         if (fci.param_count > 0) {
 115                 fci.params = safe_emalloc(fci.param_count, sizeof(zval), 0);
 116         }
 117         /* Reverse order to pop values off ctxt stack */
 118         for (i = nargs - 2; i >= 0; i--) {
 119                 obj = valuePop(ctxt);
 120                 switch (obj->type) {
 121                         case XPATH_STRING:
 122                                 ZVAL_STRING(&fci.params[i],  (char *)obj->stringval);
 123                                 break;
 124                         case XPATH_BOOLEAN:
 125                                 ZVAL_BOOL(&fci.params[i],  obj->boolval);
 126                                 break;
 127                         case XPATH_NUMBER:
 128                                 ZVAL_DOUBLE(&fci.params[i], obj->floatval);
 129                                 break;
 130                         case XPATH_NODESET:
 131                                 if (type == 1) {
 132                                         str = (char *)xmlXPathCastToString(obj);
 133                                         ZVAL_STRING(&fci.params[i], str);
 134                                         xmlFree(str);
 135                                 } else if (type == 2) {
 136                                         int j;
 137                                         array_init(&fci.params[i]);
 138                                         if (obj->nodesetval && obj->nodesetval->nodeNr > 0) {
 139                                                 for (j = 0; j < obj->nodesetval->nodeNr; j++) {
 140                                                         xmlNodePtr node = obj->nodesetval->nodeTab[j];
 141                                                         zval child;
 142                                                         /* not sure, if we need this... it's copied from xpath.c */
 143                                                         if (node->type == XML_NAMESPACE_DECL) {
 144                                                                 xmlNsPtr curns;
 145                                                                 xmlNodePtr nsparent;
 146 
 147                                                                 nsparent = node->_private;
 148                                                                 curns = xmlNewNs(NULL, node->name, NULL);
 149                                                                 if (node->children) {
 150                                                                         curns->prefix = xmlStrdup((xmlChar *) node->children);
 151                                                                 }
 152                                                                 if (node->children) {
 153                                                                         node = xmlNewDocNode(node->doc, NULL, (xmlChar *) node->children, node->name);
 154                                                                 } else {
 155                                                                         node = xmlNewDocNode(node->doc, NULL, (xmlChar *) "xmlns", node->name);
 156                                                                 }
 157                                                                 node->type = XML_NAMESPACE_DECL;
 158                                                                 node->parent = nsparent;
 159                                                                 node->ns = curns;
 160                                                         }
 161                                                         php_dom_create_object(node, &child, &intern->dom);
 162                                                         add_next_index_zval(&fci.params[i], &child);
 163                                                 }
 164                                         }
 165                                 }
 166                                 break;
 167                         default:
 168                         ZVAL_STRING(&fci.params[i], (char *)xmlXPathCastToString(obj));
 169                 }
 170                 xmlXPathFreeObject(obj);
 171         }
 172 
 173         fci.size = sizeof(fci);
 174         fci.function_table = EG(function_table);
 175 
 176         obj = valuePop(ctxt);
 177         if (obj->stringval == NULL) {
 178                 php_error_docref(NULL, E_WARNING, "Handler name must be a string");
 179                 xmlXPathFreeObject(obj);
 180                 if (fci.param_count > 0) {
 181                         for (i = 0; i < nargs - 1; i++) {
 182                                 zval_ptr_dtor(&fci.params[i]);
 183                         }
 184                         efree(fci.params);
 185                 }
 186                 return;
 187         }
 188         ZVAL_STRING(&fci.function_name, (char *) obj->stringval);
 189         xmlXPathFreeObject(obj);
 190 
 191         fci.symbol_table = NULL;
 192         fci.object = NULL;
 193         fci.retval = &retval;
 194         fci.no_separation = 0;
 195 
 196         if (!zend_make_callable(&fci.function_name, &callable)) {
 197                 php_error_docref(NULL, E_WARNING, "Unable to call handler %s()", ZSTR_VAL(callable));
 198         } else if (intern->registerPhpFunctions == 2 && zend_hash_exists(intern->registered_phpfunctions, callable) == 0) {
 199                 php_error_docref(NULL, E_WARNING, "Not allowed to call handler '%s()'.", ZSTR_VAL(callable));
 200                 /* Push an empty string, so that we at least have an xslt result... */
 201                 valuePush(ctxt, xmlXPathNewString((xmlChar *)""));
 202         } else {
 203                 result = zend_call_function(&fci, NULL);
 204                 if (result == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
 205                         if (Z_TYPE(retval) == IS_OBJECT && instanceof_function(Z_OBJCE(retval), dom_node_class_entry)) {
 206                                 xmlNode *nodep;
 207                                 dom_object *obj;
 208                                 if (intern->node_list == NULL) {
 209                                         ALLOC_HASHTABLE(intern->node_list);
 210                                         zend_hash_init(intern->node_list, 0, NULL, ZVAL_PTR_DTOR, 0);
 211                                 }
 212                                 Z_ADDREF(retval);
 213                                 zend_hash_next_index_insert(intern->node_list, &retval);
 214                                 obj = Z_DOMOBJ_P(&retval);
 215                                 nodep = dom_object_get_node(obj);
 216                                 valuePush(ctxt, xmlXPathNewNodeSet(nodep));
 217                         } else if (Z_TYPE(retval) == IS_FALSE || Z_TYPE(retval) == IS_TRUE) {
 218                                 valuePush(ctxt, xmlXPathNewBoolean(Z_TYPE(retval) == IS_TRUE));
 219                         } else if (Z_TYPE(retval) == IS_OBJECT) {
 220                                 php_error_docref(NULL, E_WARNING, "A PHP Object cannot be converted to a XPath-string");
 221                                 valuePush(ctxt, xmlXPathNewString((xmlChar *)""));
 222                         } else {
 223                                 zend_string *str = zval_get_string(&retval);
 224                                 valuePush(ctxt, xmlXPathNewString((xmlChar *) ZSTR_VAL(str)));
 225                                 zend_string_release(str);
 226                         }
 227                         zval_ptr_dtor(&retval);
 228                 }
 229         }
 230         zend_string_release(callable);
 231         zval_dtor(&fci.function_name);
 232         if (fci.param_count > 0) {
 233                 for (i = 0; i < nargs - 1; i++) {
 234                         zval_ptr_dtor(&fci.params[i]);
 235                 }
 236                 efree(fci.params);
 237         }
 238 }
 239 /* }}} */
 240 
 241 static void dom_xpath_ext_function_string_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
 242 {
 243         dom_xpath_ext_function_php(ctxt, nargs, 1);
 244 }
 245 /* }}} */
 246 
 247 static void dom_xpath_ext_function_object_php(xmlXPathParserContextPtr ctxt, int nargs) /* {{{ */
 248 {
 249         dom_xpath_ext_function_php(ctxt, nargs, 2);
 250 }
 251 /* }}} */
 252 
 253 /* {{{ proto void DOMXPath::__construct(DOMDocument doc) U */
 254 PHP_METHOD(domxpath, __construct)
 255 {
 256         zval *id = getThis(), *doc;
 257         xmlDocPtr docp = NULL;
 258         dom_object *docobj;
 259         dom_xpath_object *intern;
 260         xmlXPathContextPtr ctx, oldctx;
 261 
 262         if (zend_parse_parameters_throw(ZEND_NUM_ARGS(), "O", &doc, dom_document_class_entry) == FAILURE) {
 263                 return;
 264         }
 265 
 266         DOM_GET_OBJ(docp, doc, xmlDocPtr, docobj);
 267 
 268         ctx = xmlXPathNewContext(docp);
 269         if (ctx == NULL) {
 270                 php_dom_throw_error(INVALID_STATE_ERR, 1);
 271                 RETURN_FALSE;
 272         }
 273 
 274         intern = Z_XPATHOBJ_P(id);
 275         if (intern != NULL) {
 276                 oldctx = (xmlXPathContextPtr)intern->dom.ptr;
 277                 if (oldctx != NULL) {
 278                         php_libxml_decrement_doc_ref((php_libxml_node_object *) &intern->dom);
 279                         xmlXPathFreeContext(oldctx);
 280                 }
 281 
 282                 xmlXPathRegisterFuncNS (ctx, (const xmlChar *) "functionString",
 283                                            (const xmlChar *) "http://php.net/xpath",
 284                                            dom_xpath_ext_function_string_php);
 285                 xmlXPathRegisterFuncNS (ctx, (const xmlChar *) "function",
 286                                            (const xmlChar *) "http://php.net/xpath",
 287                                            dom_xpath_ext_function_object_php);
 288 
 289                 intern->dom.ptr = ctx;
 290                 ctx->userData = (void *)intern;
 291                 intern->dom.document = docobj->document;
 292                 php_libxml_increment_doc_ref((php_libxml_node_object *) &intern->dom, docp);
 293         }
 294 }
 295 /* }}} end DOMXPath::__construct */
 296 
 297 /* {{{ document DOMDocument*/
 298 int dom_xpath_document_read(dom_object *obj, zval *retval)
 299 {
 300         xmlDoc *docp = NULL;
 301         xmlXPathContextPtr ctx = (xmlXPathContextPtr) obj->ptr;
 302 
 303         if (ctx) {
 304                 docp = (xmlDocPtr) ctx->doc;
 305         }
 306 
 307         php_dom_create_object((xmlNodePtr) docp, retval, obj);
 308         return SUCCESS;
 309 }
 310 /* }}} */
 311 
 312 /* {{{ proto boolean dom_xpath_register_ns(string prefix, string uri) */
 313 PHP_FUNCTION(dom_xpath_register_ns)
 314 {
 315         zval *id;
 316         xmlXPathContextPtr ctxp;
 317         size_t prefix_len, ns_uri_len;
 318         dom_xpath_object *intern;
 319         unsigned char *prefix, *ns_uri;
 320 
 321         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Oss", &id, dom_xpath_class_entry, &prefix, &prefix_len, &ns_uri, &ns_uri_len) == FAILURE) {
 322                 return;
 323         }
 324 
 325         intern = Z_XPATHOBJ_P(id);
 326 
 327         ctxp = (xmlXPathContextPtr) intern->dom.ptr;
 328         if (ctxp == NULL) {
 329                 php_error_docref(NULL, E_WARNING, "Invalid XPath Context");
 330                 RETURN_FALSE;
 331         }
 332 
 333         if (xmlXPathRegisterNs(ctxp, prefix, ns_uri) != 0) {
 334                 RETURN_FALSE
 335         }
 336         RETURN_TRUE;
 337 }
 338 /* }}} */
 339 
 340 static void dom_xpath_iter(zval *baseobj, dom_object *intern) /* {{{ */
 341 {
 342         dom_nnodemap_object *mapptr = (dom_nnodemap_object *) intern->ptr;
 343 
 344         ZVAL_COPY_VALUE(&mapptr->baseobj_zv, baseobj);
 345         mapptr->nodetype = DOM_NODESET;
 346 }
 347 /* }}} */
 348 
 349 static void php_xpath_eval(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */
 350 {
 351         zval *id, retval, *context = NULL;
 352         xmlXPathContextPtr ctxp;
 353         xmlNodePtr nodep = NULL;
 354         xmlXPathObjectPtr xpathobjp;
 355         size_t expr_len, nsnbr = 0, xpath_type;
 356         dom_xpath_object *intern;
 357         dom_object *nodeobj;
 358         char *expr;
 359         xmlDoc *docp = NULL;
 360         xmlNsPtr *ns = NULL;
 361         zend_bool register_node_ns = 1;
 362 
 363         if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os|O!b", &id, dom_xpath_class_entry, &expr, &expr_len, &context, dom_node_class_entry, &register_node_ns) == FAILURE) {
 364                 return;
 365         }
 366 
 367         intern = Z_XPATHOBJ_P(id);
 368 
 369         ctxp = (xmlXPathContextPtr) intern->dom.ptr;
 370         if (ctxp == NULL) {
 371                 php_error_docref(NULL, E_WARNING, "Invalid XPath Context");
 372                 RETURN_FALSE;
 373         }
 374 
 375         docp = (xmlDocPtr) ctxp->doc;
 376         if (docp == NULL) {
 377                 php_error_docref(NULL, E_WARNING, "Invalid XPath Document Pointer");
 378                 RETURN_FALSE;
 379         }
 380 
 381         if (context != NULL) {
 382                 DOM_GET_OBJ(nodep, context, xmlNodePtr, nodeobj);
 383         }
 384 
 385         if (!nodep) {
 386                 nodep = xmlDocGetRootElement(docp);
 387         }
 388 
 389         if (nodep && docp != nodep->doc) {
 390                 php_error_docref(NULL, E_WARNING, "Node From Wrong Document");
 391                 RETURN_FALSE;
 392         }
 393 
 394         ctxp->node = nodep;
 395 
 396         if (register_node_ns) {
 397                 /* Register namespaces in the node */
 398                 ns = xmlGetNsList(docp, nodep);
 399 
 400                 if (ns != NULL) {
 401                         while (ns[nsnbr] != NULL)
 402                         nsnbr++;
 403                 }
 404         }
 405 
 406 
 407     ctxp->namespaces = ns;
 408     ctxp->nsNr = nsnbr;
 409 
 410         xpathobjp = xmlXPathEvalExpression((xmlChar *) expr, ctxp);
 411         ctxp->node = NULL;
 412 
 413         if (ns != NULL) {
 414                 xmlFree(ns);
 415                 ctxp->namespaces = NULL;
 416                 ctxp->nsNr = 0;
 417         }
 418 
 419         if (! xpathobjp) {
 420                 RETURN_FALSE;
 421         }
 422 
 423         if (type == PHP_DOM_XPATH_QUERY) {
 424                 xpath_type = XPATH_NODESET;
 425         } else {
 426                 xpath_type = xpathobjp->type;
 427         }
 428 
 429         switch (xpath_type) {
 430 
 431                 case  XPATH_NODESET:
 432                 {
 433                         int i;
 434                         xmlNodeSetPtr nodesetp;
 435 
 436                         array_init(&retval);
 437 
 438                         if (xpathobjp->type == XPATH_NODESET && NULL != (nodesetp = xpathobjp->nodesetval)) {
 439 
 440                                 for (i = 0; i < nodesetp->nodeNr; i++) {
 441                                         xmlNodePtr node = nodesetp->nodeTab[i];
 442                                         zval child;
 443 
 444                                         if (node->type == XML_NAMESPACE_DECL) {
 445                                                 xmlNsPtr curns;
 446                                                 xmlNodePtr nsparent;
 447 
 448                                                 nsparent = node->_private;
 449                                                 curns = xmlNewNs(NULL, node->name, NULL);
 450                                                 if (node->children) {
 451                                                         curns->prefix = xmlStrdup((xmlChar *) node->children);
 452                                                 }
 453                                                 if (node->children) {
 454                                                         node = xmlNewDocNode(docp, NULL, (xmlChar *) node->children, node->name);
 455                                                 } else {
 456                                                         node = xmlNewDocNode(docp, NULL, (xmlChar *) "xmlns", node->name);
 457                                                 }
 458                                                 node->type = XML_NAMESPACE_DECL;
 459                                                 node->parent = nsparent;
 460                                                 node->ns = curns;
 461                                         }
 462                                         php_dom_create_object(node, &child, &intern->dom);
 463                                         add_next_index_zval(&retval, &child);
 464                                 }
 465                         }
 466                         php_dom_create_interator(return_value, DOM_NODELIST);
 467                         nodeobj = Z_DOMOBJ_P(return_value);
 468                         dom_xpath_iter(&retval, nodeobj);
 469                         break;
 470                 }
 471 
 472                 case XPATH_BOOLEAN:
 473                         RETVAL_BOOL(xpathobjp->boolval);
 474                         break;
 475 
 476                 case XPATH_NUMBER:
 477                         RETVAL_DOUBLE(xpathobjp->floatval)
 478                         break;
 479 
 480                 case XPATH_STRING:
 481                         RETVAL_STRING((char *) xpathobjp->stringval);
 482                         break;
 483 
 484                 default:
 485                         RETVAL_NULL();
 486                         break;
 487         }
 488 
 489         xmlXPathFreeObject(xpathobjp);
 490 }
 491 /* }}} */
 492 
 493 /* {{{ proto DOMNodeList dom_xpath_query(string expr [,DOMNode context [, boolean registerNodeNS]]) */
 494 PHP_FUNCTION(dom_xpath_query)
 495 {
 496         php_xpath_eval(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_DOM_XPATH_QUERY);
 497 }
 498 /* }}} end dom_xpath_query */
 499 
 500 /* {{{ proto mixed dom_xpath_evaluate(string expr [,DOMNode context [, boolean registerNodeNS]]) */
 501 PHP_FUNCTION(dom_xpath_evaluate)
 502 {
 503         php_xpath_eval(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_DOM_XPATH_EVALUATE);
 504 }
 505 /* }}} end dom_xpath_evaluate */
 506 
 507 /* {{{ proto void dom_xpath_register_php_functions() */
 508 PHP_FUNCTION(dom_xpath_register_php_functions)
 509 {
 510         zval *id;
 511         dom_xpath_object *intern;
 512         zval *array_value, *entry, new_string;
 513         zend_string *name;
 514 
 515         DOM_GET_THIS(id);
 516 
 517         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "a",  &array_value) == SUCCESS) {
 518                 intern = Z_XPATHOBJ_P(id);
 519                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array_value), entry) {
 520                         zend_string *str = zval_get_string(entry);
 521                         ZVAL_LONG(&new_string,1);
 522                         zend_hash_update(intern->registered_phpfunctions, str, &new_string);
 523                         zend_string_release(str);
 524                 } ZEND_HASH_FOREACH_END();
 525                 intern->registerPhpFunctions = 2;
 526                 RETURN_TRUE;
 527 
 528         } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S",  &name) == SUCCESS) {
 529                 intern = Z_XPATHOBJ_P(id);
 530 
 531                 ZVAL_LONG(&new_string, 1);
 532                 zend_hash_update(intern->registered_phpfunctions, name, &new_string);
 533                 intern->registerPhpFunctions = 2;
 534         } else {
 535                 intern = Z_XPATHOBJ_P(id);
 536                 intern->registerPhpFunctions = 1;
 537         }
 538 
 539 }
 540 /* }}} end dom_xpath_register_php_functions */
 541 
 542 #endif /* LIBXML_XPATH_ENABLED */
 543 
 544 #endif
 545 
 546 /*
 547  * Local variables:
 548  * tab-width: 4
 549  * c-basic-offset: 4
 550  * End:
 551  * vim600: noet sw=4 ts=4 fdm=marker
 552  * vim<600: noet sw=4 ts=4
 553  */

/* [<][>][^][v][top][bottom][index][help] */