Annotation of embedaddon/php/ext/json/json.c, revision 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: | Author: Omar Kilani <omar@php.net> |
! 16: +----------------------------------------------------------------------+
! 17: */
! 18:
! 19: /* $Id: json.c 321634 2012-01-01 13:15:04Z felipe $ */
! 20:
! 21: #ifdef HAVE_CONFIG_H
! 22: #include "config.h"
! 23: #endif
! 24:
! 25: #include "php.h"
! 26: #include "php_ini.h"
! 27: #include "ext/standard/info.h"
! 28: #include "ext/standard/php_smart_str.h"
! 29: #include "utf8_to_utf16.h"
! 30: #include "JSON_parser.h"
! 31: #include "php_json.h"
! 32:
! 33: static PHP_MINFO_FUNCTION(json);
! 34: static PHP_FUNCTION(json_encode);
! 35: static PHP_FUNCTION(json_decode);
! 36: static PHP_FUNCTION(json_last_error);
! 37:
! 38: static const char digits[] = "0123456789abcdef";
! 39:
! 40: ZEND_DECLARE_MODULE_GLOBALS(json)
! 41:
! 42: /* {{{ arginfo */
! 43: ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
! 44: ZEND_ARG_INFO(0, value)
! 45: ZEND_ARG_INFO(0, options)
! 46: ZEND_END_ARG_INFO()
! 47:
! 48: ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
! 49: ZEND_ARG_INFO(0, json)
! 50: ZEND_ARG_INFO(0, assoc)
! 51: ZEND_ARG_INFO(0, depth)
! 52: ZEND_END_ARG_INFO()
! 53:
! 54: ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
! 55: ZEND_END_ARG_INFO()
! 56: /* }}} */
! 57:
! 58: /* {{{ json_functions[] */
! 59: static const function_entry json_functions[] = {
! 60: PHP_FE(json_encode, arginfo_json_encode)
! 61: PHP_FE(json_decode, arginfo_json_decode)
! 62: PHP_FE(json_last_error, arginfo_json_last_error)
! 63: PHP_FE_END
! 64: };
! 65: /* }}} */
! 66:
! 67: /* {{{ MINIT */
! 68: static PHP_MINIT_FUNCTION(json)
! 69: {
! 70: REGISTER_LONG_CONSTANT("JSON_HEX_TAG", PHP_JSON_HEX_TAG, CONST_CS | CONST_PERSISTENT);
! 71: REGISTER_LONG_CONSTANT("JSON_HEX_AMP", PHP_JSON_HEX_AMP, CONST_CS | CONST_PERSISTENT);
! 72: REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
! 73: REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
! 74: REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
! 75: REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
! 76:
! 77: REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
! 78: REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
! 79: REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
! 80: REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
! 81: REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
! 82: REGISTER_LONG_CONSTANT("JSON_ERROR_UTF8", PHP_JSON_ERROR_UTF8, CONST_CS | CONST_PERSISTENT);
! 83:
! 84: return SUCCESS;
! 85: }
! 86: /* }}} */
! 87:
! 88: /* {{{ PHP_GINIT_FUNCTION
! 89: */
! 90: static PHP_GINIT_FUNCTION(json)
! 91: {
! 92: json_globals->error_code = 0;
! 93: }
! 94: /* }}} */
! 95:
! 96:
! 97: /* {{{ json_module_entry
! 98: */
! 99: zend_module_entry json_module_entry = {
! 100: STANDARD_MODULE_HEADER,
! 101: "json",
! 102: json_functions,
! 103: PHP_MINIT(json),
! 104: NULL,
! 105: NULL,
! 106: NULL,
! 107: PHP_MINFO(json),
! 108: PHP_JSON_VERSION,
! 109: PHP_MODULE_GLOBALS(json),
! 110: PHP_GINIT(json),
! 111: NULL,
! 112: NULL,
! 113: STANDARD_MODULE_PROPERTIES_EX
! 114: };
! 115: /* }}} */
! 116:
! 117: #ifdef COMPILE_DL_JSON
! 118: ZEND_GET_MODULE(json)
! 119: #endif
! 120:
! 121: /* {{{ PHP_MINFO_FUNCTION
! 122: */
! 123: static PHP_MINFO_FUNCTION(json)
! 124: {
! 125: php_info_print_table_start();
! 126: php_info_print_table_row(2, "json support", "enabled");
! 127: php_info_print_table_row(2, "json version", PHP_JSON_VERSION);
! 128: php_info_print_table_end();
! 129: }
! 130: /* }}} */
! 131:
! 132: static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC);
! 133:
! 134: static int json_determine_array_type(zval **val TSRMLS_DC) /* {{{ */
! 135: {
! 136: int i;
! 137: HashTable *myht = HASH_OF(*val);
! 138:
! 139: i = myht ? zend_hash_num_elements(myht) : 0;
! 140: if (i > 0) {
! 141: char *key;
! 142: ulong index, idx;
! 143: uint key_len;
! 144: HashPosition pos;
! 145:
! 146: zend_hash_internal_pointer_reset_ex(myht, &pos);
! 147: idx = 0;
! 148: for (;; zend_hash_move_forward_ex(myht, &pos)) {
! 149: i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
! 150: if (i == HASH_KEY_NON_EXISTANT)
! 151: break;
! 152:
! 153: if (i == HASH_KEY_IS_STRING) {
! 154: return 1;
! 155: } else {
! 156: if (index != idx) {
! 157: return 1;
! 158: }
! 159: }
! 160: idx++;
! 161: }
! 162: }
! 163:
! 164: return PHP_JSON_OUTPUT_ARRAY;
! 165: }
! 166: /* }}} */
! 167:
! 168: static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */
! 169: {
! 170: int i, r;
! 171: HashTable *myht;
! 172:
! 173: if (Z_TYPE_PP(val) == IS_ARRAY) {
! 174: myht = HASH_OF(*val);
! 175: r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
! 176: } else {
! 177: myht = Z_OBJPROP_PP(val);
! 178: r = PHP_JSON_OUTPUT_OBJECT;
! 179: }
! 180:
! 181: if (myht && myht->nApplyCount > 1) {
! 182: php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
! 183: smart_str_appendl(buf, "null", 4);
! 184: return;
! 185: }
! 186:
! 187: if (r == PHP_JSON_OUTPUT_ARRAY) {
! 188: smart_str_appendc(buf, '[');
! 189: } else {
! 190: smart_str_appendc(buf, '{');
! 191: }
! 192:
! 193: i = myht ? zend_hash_num_elements(myht) : 0;
! 194:
! 195: if (i > 0)
! 196: {
! 197: char *key;
! 198: zval **data;
! 199: ulong index;
! 200: uint key_len;
! 201: HashPosition pos;
! 202: HashTable *tmp_ht;
! 203: int need_comma = 0;
! 204:
! 205: zend_hash_internal_pointer_reset_ex(myht, &pos);
! 206: for (;; zend_hash_move_forward_ex(myht, &pos)) {
! 207: i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos);
! 208: if (i == HASH_KEY_NON_EXISTANT)
! 209: break;
! 210:
! 211: if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) {
! 212: tmp_ht = HASH_OF(*data);
! 213: if (tmp_ht) {
! 214: tmp_ht->nApplyCount++;
! 215: }
! 216:
! 217: if (r == PHP_JSON_OUTPUT_ARRAY) {
! 218: if (need_comma) {
! 219: smart_str_appendc(buf, ',');
! 220: } else {
! 221: need_comma = 1;
! 222: }
! 223:
! 224: php_json_encode(buf, *data, options TSRMLS_CC);
! 225: } else if (r == PHP_JSON_OUTPUT_OBJECT) {
! 226: if (i == HASH_KEY_IS_STRING) {
! 227: if (key[0] == '\0' && Z_TYPE_PP(val) == IS_OBJECT) {
! 228: /* Skip protected and private members. */
! 229: if (tmp_ht) {
! 230: tmp_ht->nApplyCount--;
! 231: }
! 232: continue;
! 233: }
! 234:
! 235: if (need_comma) {
! 236: smart_str_appendc(buf, ',');
! 237: } else {
! 238: need_comma = 1;
! 239: }
! 240:
! 241: json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC);
! 242: smart_str_appendc(buf, ':');
! 243:
! 244: php_json_encode(buf, *data, options TSRMLS_CC);
! 245: } else {
! 246: if (need_comma) {
! 247: smart_str_appendc(buf, ',');
! 248: } else {
! 249: need_comma = 1;
! 250: }
! 251:
! 252: smart_str_appendc(buf, '"');
! 253: smart_str_append_long(buf, (long) index);
! 254: smart_str_appendc(buf, '"');
! 255: smart_str_appendc(buf, ':');
! 256:
! 257: php_json_encode(buf, *data, options TSRMLS_CC);
! 258: }
! 259: }
! 260:
! 261: if (tmp_ht) {
! 262: tmp_ht->nApplyCount--;
! 263: }
! 264: }
! 265: }
! 266: }
! 267:
! 268: if (r == PHP_JSON_OUTPUT_ARRAY) {
! 269: smart_str_appendc(buf, ']');
! 270: } else {
! 271: smart_str_appendc(buf, '}');
! 272: }
! 273: }
! 274: /* }}} */
! 275:
! 276: #define REVERSE16(us) (((us & 0xf) << 12) | (((us >> 4) & 0xf) << 8) | (((us >> 8) & 0xf) << 4) | ((us >> 12) & 0xf))
! 277:
! 278: static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */
! 279: {
! 280: int pos = 0;
! 281: unsigned short us;
! 282: unsigned short *utf16;
! 283:
! 284: if (len == 0) {
! 285: smart_str_appendl(buf, "\"\"", 2);
! 286: return;
! 287: }
! 288:
! 289: if (options & PHP_JSON_NUMERIC_CHECK) {
! 290: double d;
! 291: int type;
! 292: long p;
! 293:
! 294: if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
! 295: if (type == IS_LONG) {
! 296: smart_str_append_long(buf, p);
! 297: } else if (type == IS_DOUBLE) {
! 298: if (!zend_isinf(d) && !zend_isnan(d)) {
! 299: char *tmp;
! 300: int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d);
! 301: smart_str_appendl(buf, tmp, l);
! 302: efree(tmp);
! 303: } else {
! 304: php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", d);
! 305: smart_str_appendc(buf, '0');
! 306: }
! 307: }
! 308: return;
! 309: }
! 310:
! 311: }
! 312:
! 313: utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
! 314:
! 315: len = utf8_to_utf16(utf16, s, len);
! 316: if (len <= 0) {
! 317: if (utf16) {
! 318: efree(utf16);
! 319: }
! 320: if (len < 0) {
! 321: JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
! 322: if (!PG(display_errors)) {
! 323: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid UTF-8 sequence in argument");
! 324: }
! 325: smart_str_appendl(buf, "null", 4);
! 326: } else {
! 327: smart_str_appendl(buf, "\"\"", 2);
! 328: }
! 329: return;
! 330: }
! 331:
! 332: smart_str_appendc(buf, '"');
! 333:
! 334: while (pos < len)
! 335: {
! 336: us = utf16[pos++];
! 337:
! 338: switch (us)
! 339: {
! 340: case '"':
! 341: if (options & PHP_JSON_HEX_QUOT) {
! 342: smart_str_appendl(buf, "\\u0022", 6);
! 343: } else {
! 344: smart_str_appendl(buf, "\\\"", 2);
! 345: }
! 346: break;
! 347:
! 348: case '\\':
! 349: smart_str_appendl(buf, "\\\\", 2);
! 350: break;
! 351:
! 352: case '/':
! 353: smart_str_appendl(buf, "\\/", 2);
! 354: break;
! 355:
! 356: case '\b':
! 357: smart_str_appendl(buf, "\\b", 2);
! 358: break;
! 359:
! 360: case '\f':
! 361: smart_str_appendl(buf, "\\f", 2);
! 362: break;
! 363:
! 364: case '\n':
! 365: smart_str_appendl(buf, "\\n", 2);
! 366: break;
! 367:
! 368: case '\r':
! 369: smart_str_appendl(buf, "\\r", 2);
! 370: break;
! 371:
! 372: case '\t':
! 373: smart_str_appendl(buf, "\\t", 2);
! 374: break;
! 375:
! 376: case '<':
! 377: if (options & PHP_JSON_HEX_TAG) {
! 378: smart_str_appendl(buf, "\\u003C", 6);
! 379: } else {
! 380: smart_str_appendc(buf, '<');
! 381: }
! 382: break;
! 383:
! 384: case '>':
! 385: if (options & PHP_JSON_HEX_TAG) {
! 386: smart_str_appendl(buf, "\\u003E", 6);
! 387: } else {
! 388: smart_str_appendc(buf, '>');
! 389: }
! 390: break;
! 391:
! 392: case '&':
! 393: if (options & PHP_JSON_HEX_AMP) {
! 394: smart_str_appendl(buf, "\\u0026", 6);
! 395: } else {
! 396: smart_str_appendc(buf, '&');
! 397: }
! 398: break;
! 399:
! 400: case '\'':
! 401: if (options & PHP_JSON_HEX_APOS) {
! 402: smart_str_appendl(buf, "\\u0027", 6);
! 403: } else {
! 404: smart_str_appendc(buf, '\'');
! 405: }
! 406: break;
! 407:
! 408: default:
! 409: if (us >= ' ' && (us & 127) == us) {
! 410: smart_str_appendc(buf, (unsigned char) us);
! 411: } else {
! 412: smart_str_appendl(buf, "\\u", 2);
! 413: us = REVERSE16(us);
! 414:
! 415: smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
! 416: us >>= 4;
! 417: smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
! 418: us >>= 4;
! 419: smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
! 420: us >>= 4;
! 421: smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]);
! 422: }
! 423: break;
! 424: }
! 425: }
! 426:
! 427: smart_str_appendc(buf, '"');
! 428: efree(utf16);
! 429: }
! 430: /* }}} */
! 431:
! 432: PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */
! 433: {
! 434: switch (Z_TYPE_P(val))
! 435: {
! 436: case IS_NULL:
! 437: smart_str_appendl(buf, "null", 4);
! 438: break;
! 439:
! 440: case IS_BOOL:
! 441: if (Z_BVAL_P(val)) {
! 442: smart_str_appendl(buf, "true", 4);
! 443: } else {
! 444: smart_str_appendl(buf, "false", 5);
! 445: }
! 446: break;
! 447:
! 448: case IS_LONG:
! 449: smart_str_append_long(buf, Z_LVAL_P(val));
! 450: break;
! 451:
! 452: case IS_DOUBLE:
! 453: {
! 454: char *d = NULL;
! 455: int len;
! 456: double dbl = Z_DVAL_P(val);
! 457:
! 458: if (!zend_isinf(dbl) && !zend_isnan(dbl)) {
! 459: len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl);
! 460: smart_str_appendl(buf, d, len);
! 461: efree(d);
! 462: } else {
! 463: php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", dbl);
! 464: smart_str_appendc(buf, '0');
! 465: }
! 466: }
! 467: break;
! 468:
! 469: case IS_STRING:
! 470: json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC);
! 471: break;
! 472:
! 473: case IS_ARRAY:
! 474: case IS_OBJECT:
! 475: json_encode_array(buf, &val, options TSRMLS_CC);
! 476: break;
! 477:
! 478: default:
! 479: php_error_docref(NULL TSRMLS_CC, E_WARNING, "type is unsupported, encoded as null");
! 480: smart_str_appendl(buf, "null", 4);
! 481: break;
! 482: }
! 483:
! 484: return;
! 485: }
! 486: /* }}} */
! 487:
! 488: PHP_JSON_API void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC) /* {{{ */
! 489: {
! 490: int utf16_len;
! 491: zval *z;
! 492: unsigned short *utf16;
! 493: JSON_parser jp;
! 494:
! 495: utf16 = (unsigned short *) safe_emalloc((str_len+1), sizeof(unsigned short), 1);
! 496:
! 497: utf16_len = utf8_to_utf16(utf16, str, str_len);
! 498: if (utf16_len <= 0) {
! 499: if (utf16) {
! 500: efree(utf16);
! 501: }
! 502: JSON_G(error_code) = PHP_JSON_ERROR_UTF8;
! 503: RETURN_NULL();
! 504: }
! 505:
! 506: if (depth <= 0) {
! 507: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Depth must be greater than zero");
! 508: efree(utf16);
! 509: RETURN_NULL();
! 510: }
! 511:
! 512: ALLOC_INIT_ZVAL(z);
! 513: jp = new_JSON_parser(depth);
! 514: if (parse_JSON(jp, z, utf16, utf16_len, assoc TSRMLS_CC)) {
! 515: *return_value = *z;
! 516: }
! 517: else
! 518: {
! 519: double d;
! 520: int type;
! 521: long p;
! 522:
! 523: RETVAL_NULL();
! 524: if (str_len == 4) {
! 525: if (!strcasecmp(str, "null")) {
! 526: /* We need to explicitly clear the error because its an actual NULL and not an error */
! 527: jp->error_code = PHP_JSON_ERROR_NONE;
! 528: RETVAL_NULL();
! 529: } else if (!strcasecmp(str, "true")) {
! 530: RETVAL_BOOL(1);
! 531: }
! 532: } else if (str_len == 5 && !strcasecmp(str, "false")) {
! 533: RETVAL_BOOL(0);
! 534: }
! 535:
! 536: if ((type = is_numeric_string(str, str_len, &p, &d, 0)) != 0) {
! 537: if (type == IS_LONG) {
! 538: RETVAL_LONG(p);
! 539: } else if (type == IS_DOUBLE) {
! 540: RETVAL_DOUBLE(d);
! 541: }
! 542: }
! 543:
! 544: if (Z_TYPE_P(return_value) != IS_NULL) {
! 545: jp->error_code = PHP_JSON_ERROR_NONE;
! 546: }
! 547:
! 548: zval_dtor(z);
! 549: }
! 550: FREE_ZVAL(z);
! 551: efree(utf16);
! 552: JSON_G(error_code) = jp->error_code;
! 553: free_JSON_parser(jp);
! 554: }
! 555: /* }}} */
! 556:
! 557: /* {{{ proto string json_encode(mixed data [, int options])
! 558: Returns the JSON representation of a value */
! 559: static PHP_FUNCTION(json_encode)
! 560: {
! 561: zval *parameter;
! 562: smart_str buf = {0};
! 563: long options = 0;
! 564:
! 565: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", ¶meter, &options) == FAILURE) {
! 566: return;
! 567: }
! 568:
! 569: JSON_G(error_code) = PHP_JSON_ERROR_NONE;
! 570:
! 571: php_json_encode(&buf, parameter, options TSRMLS_CC);
! 572:
! 573: ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
! 574:
! 575: smart_str_free(&buf);
! 576: }
! 577: /* }}} */
! 578:
! 579: /* {{{ proto mixed json_decode(string json [, bool assoc [, long depth]])
! 580: Decodes the JSON representation into a PHP value */
! 581: static PHP_FUNCTION(json_decode)
! 582: {
! 583: char *str;
! 584: int str_len;
! 585: zend_bool assoc = 0; /* return JS objects as PHP objects by default */
! 586: long depth = JSON_PARSER_DEFAULT_DEPTH;
! 587:
! 588: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bl", &str, &str_len, &assoc, &depth) == FAILURE) {
! 589: return;
! 590: }
! 591:
! 592: JSON_G(error_code) = 0;
! 593:
! 594: if (!str_len) {
! 595: RETURN_NULL();
! 596: }
! 597:
! 598: php_json_decode(return_value, str, str_len, assoc, depth TSRMLS_CC);
! 599: }
! 600: /* }}} */
! 601:
! 602: /* {{{ proto int json_last_error()
! 603: Returns the error code of the last json_decode(). */
! 604: static PHP_FUNCTION(json_last_error)
! 605: {
! 606: if (zend_parse_parameters_none() == FAILURE) {
! 607: return;
! 608: }
! 609:
! 610: RETURN_LONG(JSON_G(error_code));
! 611: }
! 612: /* }}} */
! 613:
! 614: /*
! 615: * Local variables:
! 616: * tab-width: 4
! 617: * c-basic-offset: 4
! 618: * End:
! 619: * vim600: noet sw=4 ts=4 fdm=marker
! 620: * vim<600: noet sw=4 ts=4
! 621: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>